1、介绍:php
如今的消费愈来愈方便,直接带个手机用各类三方的支付平台进行支付就行,例如微信、支付宝。如今正好我所作的项目中用到了微信支付,今天就来整理一下。git
2、准备:github
一、去微信官方开发者平台注册开发者帐号:https://open.weixin.qq.com算法
二、而后登录开发平台:json
三、给项目对应的Bundle ID建立应用程序(默认有登录和分享功能,固然须要花300块钱申请支付功能,通常公司会购买,完成这些操做就是等待审核了,通常一到两个星期就搞定了)api
四、审核经过,能够看到以下显示:会生成AppID(很重要,开发时会用到,用来注册微信支付时使用的)服务器
五、选择APP支付方式,参看文档进行集成微信
六、下载资源包:(通常都是最新的版本,须要在Xocde8.0上编译,我在后面使用的是1.7.1版,在Xcode7.3.1上编译)网络
七、参考APP端开发步骤,配置属性session
(1)我下载的是1.7.1版本,最好手动把SDK拖入到项目中,很简单,主要有四个文件:libWeChatSDK.a静态包、WechatAuthSDK.h、WXApi.h、WXApiObject.h
(2)设置plist网络请求字段(iOS9.0以上须要设置)
(3)添加依赖库后编译,Build success
(4)项目设置APPID.
商户在微信开放平台申请开发APP应用后,微信开放平台会生成APP的惟一标识APPID。在Xcode中打开项目,设置项目属性中的URL Schemes为您的APPID。如图:
(5)进入项目,写代码,注册APPID
商户APP工程中引入微信lib库和头文件,调用API前,须要先向微信注册您的APPID,代码以下:
[WXApi registerApp:@"wxd930xxxxxxxxx" withDescription:@"wxchatpay"]; //注册微信的AppID
(6)商户服务器生成支付订单,先调用【统一下单API】生成预付单,获取到prepay_id后将参数再次签名传输给APP发起支付,给出的参数不少,就不所有截图了。
(7)随机字符串和签名都必须按照微信所给出的算法生成,并且参数都是以xml格式放入到请求正文里
a.随机字符串算法:咱们推荐生成随机数算法以下:调用随机数函数生成,将获得的值转换为字符串。
#pragma mark - 产生随机字符串 //生成随机数算法 ,随机字符串,不长于32位 //微信支付API接口协议中包含字段nonce_str,主要保证签名不可预测。 //咱们推荐生成随机数算法以下:调用随机数函数生成,将获得的值转换为字符串。 + (NSString *)generateTradeNO { static int kNumber = 15; NSString *sourceStr = @"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; NSMutableString *resultStr = [[NSMutableString alloc] init]; // srand函数是初始化随机数的种子,为接下来的rand函数调用作准备。 // time(0)函数返回某一特定时间的小数值。 // 这条语句的意思就是初始化随机数种子,time函数是为了提升随机的质量(也就是减小重复)而使用的。 // srand(time(0)) 就是给这个算法一个启动种子,也就是算法的随机种子数,有这个数之后才能够产生随机数,用1970.1.1至今的秒数,初始化随机数种子。 // Srand是种下随机种子数,你每回种下的种子不同,用Rand获得的随机数就不同。为了每回种下一个不同的种子,因此就选用Time(0),Time(0)是获得当前时时间值(由于每时每刻时间是不同的了)。 srand((unsigned int)time(0)); for (int i = 0; i < kNumber; i++) { unsigned index = rand() % [sourceStr length]; NSString *oneStr = [sourceStr substringWithRange:NSMakeRange(index, 1)]; [resultStr appendString:oneStr]; } return resultStr; }
b.签名生成算法查看连接:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3
也能够模拟签名生成接口,做为一次性测试使用:https://pay.weixin.qq.com/wiki/tools/signverify/,须要填写对应的字段参数,点击生成便可:如图
c、填写参数,使用AFN,进行统一下单,最终的全部的参数统一为xml,不是json,格式以下:
d、返回发送下单请求后的反馈结果:
统一下单代码:
// 交易类型 #define TRADE_TYPE @"APP" // 交易结果通知网站此处用于测试,随意填写,正式使用时填写正确网站 #define NOTIFY_URL @"http://wxpay.weixin.qq.com/pub_v2/pay/notify.v2.php" // 交易价格1表示0.01元,10表示0.1元 #define PRICE @"1" #pragma mark - 客户端操做/ 实际操做由服务端操做 // 随机字符串变量 这里最好使用和安卓端一致的生成逻辑 NSString *tradeNO = [self generateTradeNO]; // 设备IP地址,请在wifi环境下测试,不然获取的ip地址为error,正确格式应该是8.8.8.8 //NSString *addressIP = [self fetchIPAddress]; NSString *addressIP = [[IPToolManager sharedManager] currentIpAddress]; // 随机产生订单号用于测试,正式使用请换成你从本身服务器获取的订单号 NSString *orderno = [NSString stringWithFormat:@"%ld",time(0)]; // 获取SIGN签名 DataMD5 *data = [[DataMD5 alloc] initWithAppid:WX_APPID mch_id:MCH_ID nonce_str:tradeNO partner_id:WX_PartnerKey body:@"充值" out_trade_no:orderno total_fee:PRICE spbill_create_ip:addressIP notify_url:NOTIFY_URL trade_type:TRADE_TYPE]; // 转换成XML字符串,这里知识形似XML,实际并非正确的XML格式,须要使用AF方法进行转义 NSString *string = [[data dic] XMLString]; AFHTTPSessionManager *session = [AFHTTPSessionManager manager]; // 这里传入的XML字符串只是形似XML,但不是正确是XML格式,须要使用AF方法进行转义 session.responseSerializer = [[AFHTTPResponseSerializer alloc] init]; [session.requestSerializer setValue:@"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; [session.requestSerializer setValue:WXUNIFIEDORDERURL forHTTPHeaderField:@"SOAPAction"]; [session.requestSerializer setQueryStringSerializationWithBlock:^NSString *(NSURLRequest *request, NSDictionary *parameters, NSError *__autoreleasing *error) { return string; }]; [session POST:WXUNIFIEDORDERURL parameters:string progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { // 输出XML数据 NSString *responseString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding] ; // 将微信返回的xml数据解析转义成字典 NSDictionary *dic = [NSDictionary dictionaryWithXMLString:responseString]; // 判断返回的许可 if ([[dic objectForKey:@"result_code"] isEqualToString:@"SUCCESS"] &&[[dic objectForKey:@"return_code"] isEqualToString:@"SUCCESS"] ) { //这里面调起支付 (就是下面的第8步) //............pay code....... } } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"%@",error); }];
(8)下单成功后,调起支付
// 发起微信支付,设置参数 PayReq *request = [[PayReq alloc] init]; request.openID = [dic objectForKey:WXAPPID]; request.partnerId = [dic objectForKey:WXMCHID]; request.prepayId= [dic objectForKey:WXPREPAYID]; request.package = @"Sign=WXPay"; request.nonceStr= [dic objectForKey:WXNONCESTR]; // 将当前时间转化成时间戳 NSDate *datenow = [NSDate date]; NSString *timeSp = [NSString stringWithFormat:@"%ld", (long)[datenow timeIntervalSince1970]]; UInt32 timeStamp =[timeSp intValue]; request.timeStamp= timeStamp; // 签名加密 DataMD5 *md5 = [[DataMD5 alloc] init]; request.sign=[md5 createMD5SingForPay:request.openID partnerid:request.partnerId prepayid:request.prepayId package:request.package noncestr:request.nonceStr timestamp:request.timeStamp]; // 调用微信 [WXApi sendReq:request];
支付的接口参数和返回结果截图以下:
(9)设置支付代理,能够设置APPDelegate为代理,也能够本身创下建立单例工具类做为代理,处理支付回调结果。照微信SDK Sample,在类实现onResp函数,支付完成后,微信APP会返回到商户APP并回调onResp函数,开发者须要在该函数中接收通知,判断返回错误码,若是支付成功则去后台查询支付结果再展现用户实际支付结果。注意 必定不能以客户端返回做为用户支付的结果,应以服务器端的接收的支付通知或查询API返回的结果为准。代码示例以下:
-(void)onResp:(BaseResp*)resp{ if ([respisKindOfClass:[PayRespclass]]){ PayResp*response=(PayResp*)resp; switch(response.errCode){ caseWXSuccess: //服务器端查询支付通知或查询API返回的结果再提示成功 NSlog(@"支付成功"); break; default: NSlog(@"支付失败,retcode=%d",resp.errCode); break; } } }
好了,大体差很少就能够了,下面是我用真机测试的结果,测试宏定义设置的一分钱:点击绿色的微信支付按钮
(10)demo
本人demo地址以下(demo中须要在pch文件和info.plist文件设置appID等属性):https://github.com/xiayuanquan/WXChatPay
另外ip地址的获取也很重要,本人demo地址:https://github.com/xiayuanquan/IP_Test
借鉴的支付demo(demo中须要在pch文件和info.plist文件设置appID等属性):https://github.com/lyoniOS/WxPayDemo
参考博客地址: