有什么微信可以支付的支付宝购买app store

微信支付 一步一个坑的APP支付! - 推酷
微信支付 一步一个坑的APP支付!
秋高气爽,天气转凉,正是学习工作做的好时候。(~ ̄▽ ̄)~~(~ ̄▽ ̄)~
我是个phper最近在写微信支付(APP支付),微信给的官方文档并不是很详细也没有dome之类的代码啥的(对于新手来说比较麻烦),本人是新手以前也没写过支付,踩了好多坑,所以想写篇文章给没写过支付的新手几个建议。
这首先呢你得注册个
的账号吧,注册完成后呢你会收到一封微信里邮件里面有你的商户号等信息,注册这俩账号完你会拥有商户号,appid,appkey等需要的东西。
准备完成后我们来看一下支付的大体流程
商户APP应用与微信支付主要的交互说明:
用户在商户APP应用(移动端)中选择商品提交订单,支付方式选择微信支付。
商户APP应用(后台)收到用户支付订单,调用微信支付中的
商户APP应用(后台)统一下单接口调用成功后,返回的数据中有我们需要的prepay_id,按照
重新生成一个签名,然后把这个重新生成的签名及app需要的数据返回给商户APP应用(移动端)。
商户APP应用(移动端)收到商户APP应用(后台)的数据调起微信支付,用户进行支付
商户APP应用(后台)的回调接口会收到微信发来的
商户APP应用(后台)查询
附:1,4是移动端所要做的事情,2,3,5是我们PHP服务端后台要做的6也是,但我没做,这个根据情况而定如果需要的话就做。
步骤1由移动端完成
先要做的是流程中的第二步,调用同一下单接口。官方文档里说了请求的地址与参数,其中有一些是必填参数,有
应用ID 固定值,你申请账号时就给你了
商户号 固定值,你申请账号时就给你了
随机字符串
这个是自己写的要求不能长于32位,参见官方给的[标准][8]
我们把这个签名叫做第一次签名,注意这个是个坑,得自己写了,官方只给了如何写的[标准][9]没有代码,这个就比较蛋疼了。好多人掉进这个坑里,写的签名函数不对,老是出错。但不用担心我在文章的最后会贴出代码里面有签名函数直接调用就可以了。(注意看我写的函数使用规则)
商品描述交易字段格式根据不同的应用场景按照以下格式:APP——需传入应用市场上的APP名字-实际商品名称,天天爱消除-游戏充值。
out_trade_no
商户订单号
我们自己定义的订单号,32个字符内、可包含字母。
这个就是你要支付的钱数了,由前端返回。注意一下这里的货币单位是分!
spbill_create_ip
这个用户的IP地址,写个取IP地址的函数一调用就行
notify_url
这又是一个坑,好多人不理解是干嘛的,这是接收微信支付异步通知回调地址用的,通知url必须为直接可访问的url,不能携带参数! 也可以这样理解,这个是给微信支付的接口,微信来调用的接口,微信调这接口干嘛用呢?就是告诉你用户付款成功啦或者用户付款失败了,然后你就可以在这个接口里通过微信给你返回的信息来做逻辑处理了。
trade_type
写 “APP” 因为咱写的是APP支付嘛,所以就填APP。
好了就是这些必选参数了,剩下就可以自己选择是否要用的参数了根据自己情况而定。
参数选完了就要发送参数了呗,如何发呢?
我们来调用wechatAppPay类中的unifiedOrder()函数。
啊哈啥!!!!!!??????
(⊙o⊙)?(⊙o⊙)?(⊙o⊙)?(⊙o⊙)?(⊙o⊙)?
wechatAppPay类???unifiedOrder()函数???
对就这这俩东西,不要惊讶,不要着急看最后有代码,有这个类,有代码的O(∩_∩)O哈哈~,
你只需在你的项目中加载这个类就可以调用这个方法了!不要崇拜我( ╯▽╰)(因为这个类不是我写的我也忘了从哪找的了,我从百度搜的然后整理的做了些改动╮(╯▽╰)╭ -_-|||-_-|||-_-!好吧好吧好吧没做改动,只是加了点注释而已,感谢写这个类的大神谢谢O(∩_∩)O谢谢O(∩_∩)O谢谢)
好了抽完疯了,开是干正事!
我们先来new下wechatAppPay类
= 'wx0';//应用ID 字符串
= '';//商户号 字符串
$notify_url
= '/xxxx.php/xxxx/xxxx';//接收微信支付异步通知回调地址 字符串
= '';//这个是在商户中心设置的那个值用来生成签名时保证安全的 字符串
$this-&wechatAppPay = new wechatAppPay($wxappid, $mch_id, $notify_url, $wxkey);
调用wechatAppPay类中的unifiedOrder()函数。unifiedOrder()需要的参数是个数组我们定义为$params
= array();
$params['body']
= 'APP-在线支付';
//必填项 商品描述
$params['out_trade_no']
time().&$member&;
//必填项 自定义的订单号
$params['total_fee']
= ($money*100);
//必填项 订单金额 只能为整数 单位为分所以要*100
$params['trade_type']
//必填项 交易类型固定写
$params['根据自己情况定的值'] = &根据自己情况定的值& //非必填项 根据自己情况定的值 这个可有好多个可以参看开发文档中的参数
$result = $this-&wechatAppPay-&unifiedOrder( $params );
注:如果你加了$params['根据自己情况定的值'] wechatAppPay类里要做相应的改动,文章的最后有代码,你一看代码就明白了
现在$result就是我们调用统一下单接口返回的数据了,这个$resutl通过unifiedOrder()函数的处理已经把xml格式变成数组了。$result 里有return_code,return_msg,appid,mch_id,nonce_str,sign,result_code,prepay_id,trade_type。这里面就用一个prepay_id(预支付交易会话ID),其他都不重要了
步骤3 把数据返回给商户APP应用(移动端)
现在我们要把调用统一下单接口返回的数据$resutl里的几个值返回给移动端
那几个值呢?这几个:
应用ID 这个是固定的 可以自己写也可以从$resutl里拿 可以让移动端写死 就不用每次返回了
商户号 这个也是固定的 可以自己写也可以从$resutl里拿 可以让移动端写死 就不用每次返回了
预支付交易会话ID 这个很重要必须返回给移动端 是必须从$resutl里拿的
扩展字段 可以自己写也可以从$resutl里拿 暂填写固定值&Sign=WXPay& 可以让移动端写死 就不用每次返回了
随机字符串
这个可以自己写也可以从$resutl里拿
时间戳 自己生成 标准北京时间,时区为东八区注意:部分系统取到的值为毫秒级,需要转换成秒(10位数字),这里有个坑,ISO端接收的时候好像得强行转化一下,因为返回的是字符串不是数字,还有什么几位的数字之类的,我也不太懂,反正就是写的时候提醒下iOS工程师就行。安卓不清楚。
签名 又来一个坑,我们把这个签名叫做二次签名,但是这个签名不是从$resutl里拿的,而是自己写的,如何写呢,又有坑!因为参与签名的参数值是那几个不清楚,参数名写不对!不怕我有代码!贴给你看!需要参与签名的值有六个!
$sign_array
= array();
$sign_array['appid']
= $wx_result['appid'];
//注意 $sign_array['appid'] 里的参数名必须是appid
$sign_array['partnerid'] = $wx_result['mch_id'];
//注意 $sign_array['partnerid'] 里的参数名必须是partnerid
$sign_array['prepayid']
= $wx_result['prepay_id'];//注意 $sign_array['prepayid'] 里的参数名必须是prepayid
$sign_array['package']
= 'Sign=WXPay';
//注意 $sign_array['package'] 里的参数名必须是package
$sign_array['noncestr']
= $wx_result['nonce_str'];//注意 $sign_array['noncestr'] 里的参数名必须是noncestr
$sign_array['timestamp'] = time();
//注意 $sign_array['timestamp'] 里的参数名必须是timestamp
$sign_two = $this-&wechatAppPay-&MakeSign($sign_array);//调用wechatAppPay类里的MakeSign()函数生成sign
现在就可以把重新生成的sign($sign_two)以及其他参数返回给移动端了,一共返回七个值,有三个之可以让前端写死(appid,partnerid,package),其余四个必须由服务器返回给移动端。
步骤4由移动端完成
步骤5 回调接口
还记得步骤2中我们设置的$notify_url吗,对现在就要对这个微信返回到这个接口的数据进行一系列的逻辑处理了
官方是这样写的:
支付完成后,微信会把相关支付结果和用户信息发送给商户,商户需要接收处理,并返回应答。
对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。 (通知频率为15/15/30/180/00/,单位:秒)
注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。
推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
特别提醒:商户系统对于支付结果通知的内容一定要做签名验证,防止数据泄漏导致出现“假通知”,造成资金损失。
首先来接收数据
$data = $this-&wechatAppPay-&getNotifyData();//获取数据 用wechatAppPay类里的getNotifyData()方法,这里数据也被getNotifyData()由xml转化成了数组。
然后官方说要采用数据锁进行并发控制,这个我不懂所以没写(如果你懂你会的话请给我留言私信告诉我,在这谢谢了),对数据进行状态检查这个写了,如何写的呢?很简单微信返回的值有好多其中就可以判断result_code(业务结果)和return_code(返回状态码)是否为SUCCESS就可以了代码就不写了。
然后验签,这个很重要因为这是保证数据没有被第三方人为篡改的标准!
如何验签呢?
把返回的数据$data里除去sign剩下的值都参与重新签名我们把这次签名叫做验签签名,验签签名生成后再与$data里的sign对比,如果相同验签通过,否则不通过。这次签名的参数名与二次签名时的参数名不同,$data数组里叫什么参数名就验签时叫什么参数名。听乱了吧?(~ ̄▽ ̄)~(~ ̄▽ ̄)~没关系请看代码
//假如$data里有如下参数
$w_sign = array();
//参加验签签名的参数数组
$w_sign['appid']
= $data['appid'];
$w_sign['bank_type']
= $data['bank_type'];
$w_sign['cash_fee']
= $data['cash_fee'];
$w_sign['fee_type']
= $data['fee_type'];
$w_sign['is_subscribe']
= $data['is_subscribe'];
$w_sign['mch_id']
= $data['mch_id'];
$w_sign['nonce_str']
= $data['nonce_str'];
$w_sign['openid']
= $data['openid'];
$w_sign['out_trade_no']
= $data['out_trade_no'];
$w_sign['result_code']
= $data['result_code'];
$w_sign['return_code']
= $data['return_code'];
$w_sign['time_end']
= $data['time_end'];
$w_sign['total_fee']
= $data['total_fee'];
$w_sign['trade_type']
= $data['trade_type'];
$w_sign['transaction_id']
= $data['transaction_id'];
$verify_sign = $this-&wechatAppPay-&MakeSign($w_sign);//生成验签签名
好了现在假设你的验签已经通过了接下里就是你自己的逻辑处理了
///////////////////////////////////////////////////////
商户APP应用(后台)处理逻辑代码
//////////////////////////////////////////////////////
自己的逻辑处理已经处理完之后,还得告诉微信一下,别再一直发结果通用通知啦,我已经收到通知并处理完啦!
$this-&wechatAppPay-&replyNotify();//商户处理后同步返回给微信参数
步骤6根据自己情况而定
至此微信支付处理完成~(≧▽≦)/~啦啦啦~(≧▽≦)/~啦啦啦~(≧▽≦)/~啦啦啦~(≧▽≦)/~啦啦啦
写的有不对的方还请大家多多指导指教!!!给我留言!!b( ̄▽ ̄)db( ̄▽ ̄)db( ̄▽ ̄)d
还有感谢在我写微信支付地时候 那些被我问烦了的大神们! !谢谢啦~(≧▽≦)/~啦啦啦~(≧▽≦)/~啦啦啦~(≧▽≦)/~啦啦啦O(∩_∩)O哈哈~O(∩_∩)O哈哈~O(∩_∩)O哈哈~&( ̄︶ ̄)&&( ̄︶ ̄)&&( ̄︶ ̄)&
wechatAppPay类
class wechatAppPay
//接口API URL前缀
const API_URL_PREFIX = 'https://api.mch.';
//下单地址URL
const UNIFIEDORDER_URL = &/pay/unifiedorder&;
//查询订单URL
const ORDERQUERY_URL = &/pay/orderquery&;
//关闭订单URL
const CLOSEORDER_URL = &/pay/closeorder&;
//公众账号ID
private $mch_
//随机字符串
private $nonce_
//商品描述
//商户订单号
private $out_trade_
//支付总金额
private $total_
private $spbill_create_
//支付结果回调通知地址
private $notify_
//交易类型
private $trade_
//支付密钥
//证书路径
private $SSLCERT_PATH;
private $SSLKEY_PATH;
//所有参数
private $params = array();
public function __construct($wxappid, $mch_id, $notify_url, $key)
$this-&appid = $
$this-&mch_id = $mch_
$this-&notify_url = $notify_
$this-&key = $
* 下单方法
$params 下单参数
public function unifiedOrder( $params ){
$this-&body = $params['body'];
$this-&out_trade_no = $params['out_trade_no'];
$this-&total_fee = $params['total_fee'];
$this-&trade_type = $params['trade_type'];
$this-&nonce_str = $this-&genRandomString();
$this-&spbill_create_ip = $_SERVER['REMOTE_ADDR'];
$this-&params['appid'] = $this-&
$this-&params['mch_id'] = $this-&mch_
$this-&params['nonce_str'] = $this-&nonce_
$this-&params['body'] = $this-&
$this-&params['out_trade_no'] = $this-&out_trade_
$this-&params['total_fee'] = $this-&total_
$this-&params['spbill_create_ip'] = $this-&spbill_create_
$this-&params['notify_url'] = $this-&notify_
$this-&params['trade_type'] = $this-&trade_
//获取签名数据
$this-&sign = $this-&MakeSign( $this-&params );
$this-&params['sign'] = $this-&
$xml = $this-&data_to_xml($this-&params);
$response = $this-&postXmlCurl($xml, self::API_URL_PREFIX.self::UNIFIEDORDER_URL);
if( !$response ){
$result = $this-&xml_to_data( $response );
if( !empty($result['result_code']) && !empty($result['err_code']) ){
$result['err_msg'] = $this-&error_code( $result['err_code'] );
* 查询订单信息
* @param $out_trade_no
* @return array
public function orderQuery( $out_trade_no ){
$this-&params['appid'] = $this-&
$this-&params['mch_id'] = $this-&mch_
$this-&params['nonce_str'] = $this-&genRandomString();
$this-&params['out_trade_no'] = $out_trade_
//获取签名数据
$this-&sign = $this-&MakeSign( $this-&params );
$this-&params['sign'] = $this-&
$xml = $this-&data_to_xml($this-&params);
$response = $this-&postXmlCurl($xml, self::API_URL_PREFIX.self::ORDERQUERY_URL);
if( !$response ){
$result = $this-&xml_to_data( $response );
if( !empty($result['result_code']) && !empty($result['err_code']) ){
$result['err_msg'] = $this-&error_code( $result['err_code'] );
* 关闭订单
* @param $out_trade_no
* @return array
public function closeOrder( $out_trade_no ){
$this-&params['appid'] = $this-&
$this-&params['mch_id'] = $this-&mch_
$this-&params['nonce_str'] = $this-&genRandomString();
$this-&params['out_trade_no'] = $out_trade_
//获取签名数据
$this-&sign = $this-&MakeSign( $this-&params );
$this-&params['sign'] = $this-&
$xml = $this-&data_to_xml($this-&params);
$response = $this-&postXmlCurl($xml, self::API_URL_PREFIX.self::CLOSEORDER_URL);
if( !$response ){
$result = $this-&xml_to_data( $response );
* 获取支付结果通知数据
* return array
public function getNotifyData(){
//获取通知的数据
$xml = $GLOBALS['HTTP_RAW_POST_DATA'];
$data = array();
if( empty($xml) ){
$data = $this-&xml_to_data( $xml );
if( !empty($data['return_code']) ){
if( $data['return_code'] == 'FAIL' ){
* 接收通知成功后应答输出XML数据
* @param string $xml
public function replyNotify(){
$data['return_code'] = 'SUCCESS';
$data['return_msg'] = 'OK';
$xml = $this-&data_to_xml( $data );
* 生成APP端支付参数
public function getAppPayParams( $prepayid ){
$data['appid'] = $this-&
$data['partnerid'] = $this-&mch_
$data['prepayid'] = $
$data['package'] = 'Sign=WXPay';
$data['noncestr'] = $this-&genRandomString();
$data['timestamp'] = time();
$data['sign'] = $this-&MakeSign( $data );
* 生成签名
@return 签名
public function MakeSign( $params ){
//签名步骤一:按字典序排序数组参数
ksort($params);
$string = $this-&ToUrlParams($params);
//签名步骤二:在string后加入KEY
$string = $string . &&key=&.$this-&
//签名步骤三:MD5加密
$string = md5($string);
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
* 将参数拼接为url: key=value&key=value
public function ToUrlParams( $params ){
$string = '';
if( !empty($params) ){
$array = array();
foreach( $params as $key =& $value ){
$array[] = $key.'='.$
$string = implode(&&&,$array);
* 输出xml字符
返回组装的xml
public function data_to_xml( $params ){
if(!is_array($params)|| count($params) &= 0)
$xml = &&xml&&;
foreach ($params as $key=&$val)
if (is_numeric($val)){
$xml.=&&&.$key.&&&.$val.&&/&.$key.&&&;
$xml.=&&&.$key.&&&![CDATA[&.$val.&]]&&/&.$key.&&&;
$xml.=&&/xml&&;
* 将xml转为array
* @param string $xml
* return array
public function xml_to_data($xml){
if(!$xml){
//将XML转为array
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
* 获取毫秒级别的时间戳
private static function getMillisecond(){
//获取毫秒的时间戳
$time = explode ( & &, microtime () );
$time = $time[1] . ($time[0] * 1000);
$time2 = explode( &.&, $time );
$time = $time2[0];
* 产生一个指定长度的随机字符串,并返回给用户
* @param type $len 产生字符串的长度
* @return string 随机字符串
private function genRandomString($len = 32) {
$chars = array(
&a&, &b&, &c&, &d&, &e&, &f&, &g&, &h&, &i&, &j&, &k&,
&l&, &m&, &n&, &o&, &p&, &q&, &r&, &s&, &t&, &u&, &v&,
&w&, &x&, &y&, &z&, &A&, &B&, &C&, &D&, &E&, &F&, &G&,
&H&, &I&, &J&, &K&, &L&, &M&, &N&, &O&, &P&, &Q&, &R&,
&S&, &T&, &U&, &V&, &W&, &X&, &Y&, &Z&, &0&, &1&, &2&,
&3&, &4&, &5&, &6&, &7&, &8&, &9&
$charsLen = count($chars) - 1;
// 将数组打乱
shuffle($chars);
$output = &&;
for ($i = 0; $i & $ $i++) {
$output .= $chars[mt_rand(0, $charsLen)];
* 以post方式提交xml到对应的接口url
* @param string $xml
需要post的xml数据
* @param string $url
* @param bool $useCert 是否需要证书,默认不需要
* @param int $second
url执行超时时间,默认30s
* @throws WxPayException
private function postXmlCurl($xml, $url, $useCert = false, $second = 30){
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
if($useCert == true){
//设置证书
//使用证书:cert 与 key 分别属于两个.pem文件
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
//curl_setopt($ch,CURLOPT_SSLCERT, WxPayConfig::SSLCERT_PATH);
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
//curl_setopt($ch,CURLOPT_SSLKEY, WxPayConfig::SSLKEY_PATH);
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//运行curl
$data = curl_exec($ch);
//返回结果
if($data){
curl_close($ch);
$error = curl_errno($ch);
curl_close($ch);
* 错误代码
服务器输出的错误代码
* return string
public function error_code( $code ){
$errList = array(
'商户未开通此接口权限',
'NOTENOUGH'
'用户帐号余额不足',
'ORDERNOTEXIST'
'订单号不存在',
'ORDERPAID'
'商户订单已支付,无需重复操作',
'ORDERCLOSED'
'当前订单已关闭,无法支付',
'SYSTEMERROR'
'系统错误!系统超时',
'APPID_NOT_EXIST'
'参数中缺少APPID',
'MCHID_NOT_EXIST'
'参数中缺少MCHID',
'APPID_MCHID_NOT_MATCH' =&
'appid和mch_id不匹配',
'LACK_PARAMS'
'缺少必要的请求参数',
'OUT_TRADE_NO_USED'
'同一笔交易不能多次提交',
'SIGNERROR'
'参数签名结果不正确',
'XML_FORMAT_ERROR'
'XML格式错误',
'REQUIRE_POST_METHOD'
'未使用post传递参数 ',
'POST_DATA_EMPTY'
'post数据不能为空',
'NOT_UTF8'
'未使用指定编码格式',
if( array_key_exists( $code , $errList ) ){
return $errList[$code];
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致下载拍拍APP
品质生活购物社区
下载拍拍二手APP
二手闲置物品处理平台
关注拍拍服务号
关注拍拍 惊喜多多
>>什么是微信支付?如何进行微信支付?
什么是微信支付?如何进行微信支付?
微信支付是拍拍平台可以通过手机进行的支付方式之一。
您可以通过以下两种方式进行付款购买,如下图所示:
您确认您所需要购买的商品,大部分店铺在商品页面”立即购买”的右方有商品的二维码,您用手机微信扫一扫功能扫描商品二维码.
在您扫过二维码后,在您手机的页面将显示商品详情
在商品页面点击”立即购买”进入订单确认页,确认商品信息,收件人等信息(温馨提示:如若您首次选择此类方式进行购买务必核实您的收货地址,一般情况下第一次生成的收货地址由系统自动生成)。
在您确认订单信息无误后,在付款方式中选择“微信支付”点击“立即支付”跳至付款页面。
方式2:您通过PC端选择好商品后点击“立即购买”跳转至订单信息确认页面,您确认您所需商品信息后,在”确认订单信息”页面”选择支付方式”中选择微信支付,点击”提交订单”.
您点击提交订单后将会生成付款二维码,您用您手机微信的扫一扫功能,扫描二维码跳转至付款页面。.
跳转至付款页面后,如若您微信账号中有足够的余额您可以点击”使用零钱支付”即可支付成功。
如若您微信账户没有足够的余额,您可以点击”使用银行卡支付”。
点击”使用银行卡支付”后跳转至信息填写页面,您按照页面提示进行填写,填写完毕后点击”获取验证码”填写,点击下一步即可支付成功。
以上内容是否解决了您的问题呢?
         
您也可以关注拍拍官方商户服务号获得在线咨询服务,微信号:paipaimjfw获得更多帮助。
买手网罗全球好货
QQ一键联系卖家
拍出好货不瞎淘
7天无理由退换货
24小时闪电发货
诚信保证计划
Copyright &
广东省通管局 增值电信业务经营许可证B2-iOS客户端支持微信支付
对于一个iOS的APP,如果有一些虚拟的商品或者服务需要通过在线支付来收费的话,一般有几种主流的选择。
如果是通过APP调用支付平台APP的思路的话,一个是调起支付宝客户端,一个则是调起微信支付。
实际上,从代码的角度,调起支付APP就是把一些关键的参数通过一定方式打包成为一个订单,然后发送到支付平台的服务器。所以,只要搞清楚了参数设置,搞清楚了每个支付平台的SDK里面一些关键API的使用,基本上就可以很简单的支持支付。
今天记录一下客户端里面,如何支持微信支付。首先。我们要仔细一下微信SDK的开发文档,了解一下整个支付的大概流程。
然后根据提示,把相应的SDK下载下来,所谓的SDK,也就是一个链接库和两个头文件,很简单。
下载完毕,需要把SDK导入到工程里面,并且配置一下工程。因为开发者文档已经有详细描述,这里就不再复述。
http://pay./wiki/doc/api/app.php?chapter=8_5
从文档看到,调起微信支付其实最核心的是一下这么一段
PayReq *request = [[[PayReq alloc] init] autorelease];
request.partnerId = @&&;
request.prepayId= @&fc314aa427&;
request.package = @&Sign=WXPay&;
request.nonceStr= @&a462b76eed6e13c64b4fd1c&;
request.timeStamp= @&&;
request.sign= @&DD2B03AD8CB16E7A256&;
[WXApi sendReq:request];
这里的范例是一段hardcode,真正使用的时候,参数都需要自行传入。
为了搞清楚如何使用API,我们可以下载Sample代码。不过,这个sample代码应该是微信的实习生写的,而且应该是一个对于C++比较熟悉,对于ObjectC比较陌生的实习生。。。代码风格可以看出很多东西哈。。所以这个sample读起来总觉得有点奇怪。当然,写出这个demo也是需要不错的水平,因为这个sample不仅仅是一些API的调用,还包括了一些算法的实现,MD5之类的。
看懂了sample之后,一般可以自己重构一下,成为自己APP里面的一个Manager类。
我是在下载的微信Sampel代码,里面包括有:
payRequestHandler.h
payRequestHandler.m
如果比较看重命名规范的OC程序猿,就会觉得这个payRequestHandler类非常别扭,不符合camel命名规则,而且handler这个词更偏向于c++风格。我就以这个类为原型,重构了一下,并改装成一个传参的方法,供自己的APP调用。APP里面卖商品,一般就是商品名字,价格两个关键参数。所以这个重构的方法也只是提供这两个参数的接口。
ApiXml.h && ApiXml.m && WXUtil.h && WXUtil.m不变
WechatPayManager.h
Created by HuangCharlie on 5/24/15.
#import &WXUtil.h&
#import &ApiXml.h&
#import &WXApi.h&
// 账号帐户资料
// 更改商户把相关参数后可测试
#define APP_ID
@&wx427a2f57bc4456d1&
#define APP_SECRET
//appsecret,看起来好像没用
//商户号,填写商户对应参数
#define MCH_ID
//商户API密钥,填写相应参数
#define PARTNER_ID
//支付结果回调页面
#define NOTIFY_URL
@&http://wxpay./pub_v2/pay/notify.v2.php&
//获取服务器端支付数据地址(商户自定义)(在小吉这里,签名算法直接放在APP端,故不需要自定义)
#define SP_URL
@&http://wxpay./pub_v2/app/app_pay.php&
@interface WechatPayManager : NSObject
//预支付网关url地址
@property (nonatomic,strong) NSString* payU
//debug信息
@property (nonatomic,strong) NSMutableString *debugI
@property (nonatomic,assign) NSInteger lastErrC//返回的错误码
//商户关键信息
@property (nonatomic,strong) NSString *appId,*mchId,*spK
//初始化函数
-(id)initWithAppID:(NSString*)appID
mchID:(NSString*)mchID
spKey:(NSString*)
//获取当前的debug信息
-(NSString *) getDebugI
//获取预支付订单信息(核心是一个prepayID)
- (NSMutableDictionary*)getPrepayWithOrderName:(NSString*)name
price:(NSString*)price
device:(NSString*)
WechatPayManager.m
Created by HuangCharlie on 5/24/15.
#import &WechatPayManager.h&
@implementation WechatPayManager
//初始化函数
-(id)initWithAppID:(NSString*)appID mchID:(NSString*)mchID spKey:(NSString*)key
self = [super init];
//初始化私有参数,主要是一些和商户有关的参数
self.payUrl
= @&https://api.mch./pay/unifiedorder&;
if (self.debugInfo == nil){
self.debugInfo
= [NSMutableString string];
[self.debugInfo setString:@&&];
self.appId = appID;//微信分配给商户的appID
self.mchId = mchID;//
self.spKey =//商户的密钥
//获取debug信息
-(NSString*) getDebugInfo
NSString *res = [NSString stringWithString:self.debugInfo];
[self.debugInfo setString:@&&];
//创建package签名
-(NSString*) createMd5Sign:(NSMutableDictionary*)dict
NSMutableString *contentString
=[NSMutableString string];
NSArray *keys = [dict allKeys];
//按字母顺序排序
NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2 options:NSNumericSearch];
//拼接字符串
for (NSString *categoryId in sortedArray) {
![[dict objectForKey:categoryId] isEqualToString:@&&]
&& ![categoryId isEqualToString:@&sign&]
&& ![categoryId isEqualToString:@&key&]
[contentString appendFormat:@&%@=%@&&, categoryId, [dict objectForKey:categoryId]];
//添加key字段
[contentString appendFormat:@&key=%@&, self.spKey];
//得到MD5 sign签名
NSString *md5Sign =[WXUtil md5:contentString];
//输出Debug Info
[self.debugInfo appendFormat:@&MD5签名字符串:\n%@\n\n&,contentString];
return md5S
//获取package带参数的签名包
-(NSString *)genPackage:(NSMutableDictionary*)packageParams
NSString *
NSMutableString *reqPars=[NSMutableString string];
//生成签名
= [self createMd5Sign:packageParams];
//生成xml的package
NSArray *keys = [packageParams allKeys];
[reqPars appendString:@&\n&];
for (NSString *categoryId in keys) {
[reqPars appendFormat:@&&%@&%@\n&, categoryId, [packageParams objectForKey:categoryId],categoryId];
[reqPars appendFormat:@&%@\n&, sign];
return [NSString stringWithString:reqPars];
//提交预支付
-(NSString *)sendPrepay:(NSMutableDictionary *)prePayParams
NSString *prepayid =
//获取提交支付
NSString *send
= [self genPackage:prePayParams];
//输出Debug Info
[self.debugInfo appendFormat:@&API链接:%@\n&, self.payUrl];
[self.debugInfo appendFormat:@&发送的xml:%@\n&, send];
//发送请求post xml数据
NSData *res = [WXUtil httpSend:self.payUrl method:@&POST& data:send];
//输出Debug Info
[self.debugInfo appendFormat:@&服务器返回:\n%@\n\n&,[[NSString alloc] initWithData:res encoding:NSUTF8StringEncoding]];
XMLHelper *xml
= [[XMLHelper alloc] autorelease];
//开始解析
[xml startParse:res];
NSMutableDictionary *resParams = [xml getDict];
//判断返回
NSString *return_code
= [resParams objectForKey:@&return_code&];
NSString *result_code
= [resParams objectForKey:@&result_code&];
if ( [return_code isEqualToString:@&SUCCESS&] )
//生成返回数据的签名
NSString *sign
= [self createMd5Sign:resParams ];
NSString *send_sign =[resParams objectForKey:@&sign&] ;
//验证签名正确性
if( [sign isEqualToString:send_sign]){
if( [result_code isEqualToString:@&SUCCESS&]) {
//验证业务处理状态
= [resParams objectForKey:@&prepay_id&];
return_code = 0;
[self.debugInfo appendFormat:@&获取预支付交易标示成功!\n&];
self.lastErrCode = 1;
[self.debugInfo appendFormat:@&gen_sign=%@\n
_sign=%@\n&,sign,send_sign];
[self.debugInfo appendFormat:@&服务器返回签名验证错误!!!\n&];
self.lastErrCode = 2;
[self.debugInfo appendFormat:@&接口返回错误!!!\n&];
- (NSMutableDictionary*)getPrepayWithOrderName:(NSString*)name
price:(NSString*)price
device:(NSString*)device
//订单标题,展示给用户
NSString* orderName =
//订单金额,单位(分)
NSString* orderPrice =//以分为单位的整数
//支付设备号或门店号
NSString* orderDevice =
//支付类型,固定为APP
NSString* orderType = @&APP&;
//发器支付的机器ip,暂时没有发现其作用
NSString* orderIP = @&196.168.1.1&;
//随机数串
srand( (unsigned)time(0) );
NSString *noncestr
= [NSString stringWithFormat:@&%d&, rand()];
NSString *orderNO
= [NSString stringWithFormat:@&%ld&,time(0)];
//================================
//预付单参数订单设置
//================================
NSMutableDictionary *packageParams = [NSMutableDictionary dictionary];
[packageParams setObject: self.appId
forKey:@&appid&];
//开放平台appid
[packageParams setObject: self.mchId
forKey:@&mch_id&];
[packageParams setObject: orderDevice
forKey:@&device_info&]; //支付设备号或门店号
[packageParams setObject: noncestr
forKey:@&nonce_str&];
[packageParams setObject: orderType
forKey:@&trade_type&];
//支付类型,固定为APP
[packageParams setObject: orderName
forKey:@&body&];
//订单描述,展示给用户
[packageParams setObject: NOTIFY_URL
forKey:@&notify_url&];
//支付结果异步通知
[packageParams setObject: orderNO
forKey:@&out_trade_no&];//商户订单号
[packageParams setObject: orderIP
forKey:@&spbill_create_ip&];//发器支付的机器ip
[packageParams setObject: orderPrice
forKey:@&total_fee&];
//订单金额,单位为分
//获取prepayId(预支付交易会话标识)
NSString *preP
prePayid = [self sendPrepay:packageParams];
if(prePayid == nil)
[self.debugInfo appendFormat:@&获取prepayid失败!\n&];
//获取到prepayid后进行第二次签名
*package, *time_stamp, *nonce_
//设置支付参数
time(&now);
time_stamp
= [NSString stringWithFormat:@&%ld&, now];
nonce_str = [WXUtil md5:time_stamp];
//重新按提交格式组包,微信客户端暂只支持package=Sign=WXPay格式,须考虑升级后支持携带package具体参数的情况
= [NSString stringWithFormat:@&Sign=%@&,package];
= @&Sign=WXPay&;
//第二次签名参数列表
NSMutableDictionary *signParams = [NSMutableDictionary dictionary];
[signParams setObject: self.appId
forKey:@&appid&];
[signParams setObject: self.mchId
forKey:@&partnerid&];
[signParams setObject: nonce_str
forKey:@&noncestr&];
[signParams setObject: package
forKey:@&package&];
[signParams setObject: time_stamp
forKey:@&timestamp&];
[signParams setObject: prePayid
forKey:@&prepayid&];
//生成签名
NSString *sign
= [self createMd5Sign:signParams];
//添加签名
[signParams setObject: sign
forKey:@&sign&];
[self.debugInfo appendFormat:@&第二步签名成功,sign=%@\n&,sign];
//返回参数列表
return signP
然后,在需要调用微信支付的Controller里面,新建一个方法。在合适的地方调用。这个方法里面利用WechatPayManager这个类进行了初始化和参数封装,然后把上述的核心代码(PayReq那一段)
- (void)wxPayWithOrderName:(NSString*)name price:(NSString*)price
//创建支付签名对象 && 初始化支付签名对象
WechatPayManager* wxpayManager = [[[WechatPayManager alloc]initWithAppID:APP_ID mchID:MCH_ID spKey:PARTNER_ID] autorelease];
//获取到实际调起微信支付的参数后,在app端调起支付
//生成预支付订单,实际上就是把关键参数进行第一次。
NSString* device = [[UserManager defaultManager]userId];
NSMutableDictionary *dict = [wxpayManager getPrepayWithOrderName:name
price:price
device:device];
if(dict == nil){
//错误提示
NSString *debug = [wxpayManager getDebugInfo];
NSMutableString *stamp
= [dict objectForKey:@&timestamp&];
//调起微信支付
PayReq* req
= [[[PayReq alloc] init]autorelease];
req.openID
= [dict objectForKey:@&appid&];
req.partnerId
= [dict objectForKey:@&partnerid&];
req.prepayId
= [dict objectForKey:@&prepayid&];
req.nonceStr
= [dict objectForKey:@&noncestr&];
req.timeStamp
= stamp.intV
req.package
= [dict objectForKey:@&package&];
= [dict objectForKey:@&sign&];
BOOL flag = [WXApi sendReq:req];
BOOL flag = [WXApi safeSendReq:req];
再者,支付完成了需要调用一个delegate,这个delegate方便个性化显示支付结果。一般直接把这两个delegate放在AppDelegate就好了。因为有一些其他内容也是需要在AppDelegate里面实现,省的分开找不到。
-(void) onResp:(BaseResp*)resp
//启动微信支付的response
NSString *strMsg = [NSString stringWithFormat:@&errcode:%d&, resp.errCode];
if([resp isKindOfClass:[PayResp class]]){
//支付返回结果,实际支付结果需要去微信服务器端查询
switch (resp.errCode) {
strMsg = @&支付结果:成功!&;
strMsg = @&支付结果:失败!&;
strMsg = @&用户已经退出支付!&;
strMsg = [NSString stringWithFormat:@&支付结果:失败!retcode = %d, retstr = %@&, resp.errCode,resp.errStr];
注意事项:
1)如果APP里面已经使用了ShareSDK,就有一些地方要注意。不要再重复导入微信的SDK,因为shareSDK里面的extend已经包括了微信的SDK。
2)微信本身是鼓励客户APP把签名算法放到服务器上面,这样信息就不容易被。但是如果客户APP本身没有服务器端,或者认为不需要放到服务器端,也可以直接把签名(加密)的部分直接放在APP端。Sample代码的注释有点乱,多次提到服务器云云,但是其实可以不这么做。
3)微信的price单位是分。注意下即可。
4)暂时想不到,以后想到了再记录。。
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'

我要回帖

更多关于 那些 app可以微信支付 的文章

 

随机推荐