如今基本全部的App都会接入支付宝支付以及微信支付,也有不少第三方提供给你php
SDK帮你接入,可是这种涉及到支付的东西仍是本身服务器搞来的好一些,其实搞懂了c++
逻辑很是的简单,下面直接给你们说说下基本流程和接入须要注意的东西。算法
支付宝详细爬坑接入指南传送门api
前期准备(这个东西通常来说咱们不须要来操心,可是仍是稍微介绍下)安全
1.到微信开放平台注册帐号点击打开连接服务器
2.进入管理中心------移动应用------建立移动应用----根据页面完善应用资料微信
3.审核事后,经过应用详情页面,查看应用详情,查看AppID和AppSecret相关信息app
4.建立这些是没有支付能力的,须要额外申请,仍是根据提示一步步填写,填写完以后会发一封邮件到您的预留的邮箱,而后到商户平台点击打开连接填写资料,最主要的是验证下开户收款帐号,会收到一波几分钱的巨额财产,那么这个时候若是你填写的是你的开户帐号,直接跑路吧,这些钱够你在深圳买房了。。。。。。若是你是个好人,那么找大家财务验证下是否有收到,就表明经过了,愉快的代码时间来了异步
开撸代码以前先看下基本流程ide
商户系统和微信支付系统主要交互说明:
步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。
步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。点击打开连接
步骤3:统一下单接口返回正常的prepay_id,再按签名规范从新生成签名后,将数据传输给APP。参与签名的字段名为appId,partnerId,prepayId,nonceStr,timeStamp,package。注意:package的值格式为Sign=WXPay
步骤4:商户APP调起微信支付。点击打开连接
步骤5:商户后台接收支付通知。点击打开连接
步骤6:商户后台查询支付结果。点击打开连接
看完流程,来看看我们客户端要作什么准备
1.SDK接入
2.依赖库导入(貌似还差个libc++.dylib,也一并加入)
3.iOS 9 配置白名单
4.配置下Scheme(这填写的是申请回来的ID)
终于能够愉快的写代码了
1.向微信注册你的AppID
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. //注册APP,这里的字符串就是Wechat URL Scheme里面对应的ID 也是申请回来的ID,必须一致 [WXApi registerApp:@"这里填写申请回来的ID"]; return YES; }
#pragma mark - 微信支付 - (void)wechatPay { // 把生成的订单信息组装起来传给服务器,如何组装就和服务器约定好 [[TWTShoppingCartLogic sharedData] goToWechatEasyPay:self.orderStr way:@"2" complete:^(NSError *error, id data) { NSMutableString *stamp = [data objectForKey:@"timestamp"]; //调起微信支付 PayReq* req = [[PayReq alloc] init]; req.partnerId = [data objectForKey:@"partnerid"]; req.prepayId = [data objectForKey:@"prepayid"]; req.nonceStr = [data objectForKey:@"noncestr"]; req.timeStamp = stamp.intValue; req.package = [data objectForKey:@"package"]; req.sign = [data objectForKey:@"sign"]; [WXApi sendReq:req]; }]; }
{
"appid" : "wxb4b",微信开放平台审核经过的AppID
"noncestr" : "171127dd056d05e423c8b9e",随机字符串
"package" : "Sign=WXPay", 固定值
"partnerid" : "130", 微信支付分配的商户ID
"prepayid" : "wx201609291601", 预支付交易会话ID
"sign" : "684371081C049B6017641", 签名,除了sign,剩下6个组合的再次签名字符串
"timestamp" : 147513 当前时间
}
注意啦!!!!!!
第一种:老司机后台类型
其实当你把订单传给后台的时候,后台事先会把订单经过微信的生成预支付订单生成
prepayID点击打开连接,那么对于老司机来讲,怎么可能把这种返回的数据返回给你?
他们会把接受的prepayID根据上面的结构组装起来,那么预支付订单生成的时候也会返
回sign字段,老司机不会直接用,后台会把这个字段,也就是剩下6个字段再次md5签
名生成签名算法新的sign字段组装完毕返回给你,这种状况下直接在App上配置模型,
拉起微信支付,很是舒畅,一鼓作气!!!
第二种:没法理解类型后台(让你本身签名)
当你把订单传给他的时候,一样他会生成个预订单prepayID,那么这种司机开车特别
猛,直接把返回的参数根据格式组装后弹回给你,sign字段也是预订单生成后的,没有
通过二次md5签名,他也没有告诉你,那么你也特别猛,没问他,直接用他的字段,组
装完毕,拉起微信,我擦,你会直接懵逼了,那么你将会只会看到这个。
问题不大,就是本身签名了,本身写个本地的md5玩玩(假的千万别用,网上
找来的分享下)
//建立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) { if ( ![[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 =[contentString MD5]; return md5Sign; } - (NSMutableDictionary*)payWithprePayid:(NSString*)prePayid { if(prePayid == nil) { NSLog(@"prePayid 为空"); return nil; } //获取到prepayid后进行第二次签名 NSString *package, *time_stamp, *nonce_str; //设置支付参数 time_t now; time(&now); time_stamp = [NSString stringWithFormat:@"%ld", now]; nonce_str = [time_stamp MD5]; //从新按提交格式组包,微信客户端暂只支持package=Sign=WXPay格式,须考虑升级后支持携带package具体参数的状况 //package = [NSString stringWithFormat:@"Sign=%@",package]; package = @"Sign=WXPay"; //第二次签名参数列表 NSMutableDictionary *signParams = [NSMutableDictionary dictionary]; NSLog(@"%@",signParams); [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"]; //返回参数列表 return signParams; }
若是真的要在App端二次签名的话,那加密的时候还要加入申请的密钥,可是真的很差
这样作,其一:服务器已经作过一次签名了,第二次作了返回给你就行了,不必再给
App。其二:不安全,全放在App上,这种东西必定要放到服务器
小技巧:其实出现上面那种状况有几种可能
1.sign没有二次签名
2.noncerStr是服务器返回的,不要本身生成
3.package是写死的,不要写错了
4.timeStamp是10位数
5.本身签名的sign必定要所有大写
6.为了不上面的状况,交给服务器管理,咱们负责组装拉起微信支付就行了
3.处理回调信息
Appdelegate
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url { // 跳转到URL scheme中配置的地址 //NSLog(@"跳转到URL scheme中配置的地址-->%@",url); return [WXApi handleOpenURL:url delegate:[WXApiManager sharedManager]]; } //支付成功时调用,回到第三方应用中 - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { if ([url.scheme isEqualToString:WECHAT_APPKEY])//微信调用结束 { return [WXApi handleOpenURL:url delegate:[WXApiManager sharedManager]]; } }
注意点:有些人用NSNotificationCenter来通知到发出请求的界面去,而后在发起的界面处理回调的逻辑,可是这里
你要考虑一种非人类的交互,TMD有人在拉起微信支付的时候把本身的App给推出了或者App本身挂了,那么当回调
生效的时候,原先拉起微信支付App的界面已经消失了,你发的通知他收不到了,这种状况我是存到本地的
[[NSUserDefaultsstandardUserDefaults]setValue:self.orderStrforKey:@"WECHAT_PAY_ORDER_TRADEID"];
[[NSUserDefaultsstandardUserDefaults]synchronize];
处理回调的时候直接从本地读取
最终处理逻辑的地方(这里不能直接用他的返回接过,要二次确认)
//微信回调,有支付结果的时候会回调这个方法 - (void)onResp:(BaseResp *)resp { if([resp isKindOfClass:[PayResp class]]){ //支付返回结果,实际支付结果须要去微信服务器端查询 NSString *strMsg,*strTitle = [NSString stringWithFormat:@"支付结果"]; switch (resp.errCode) { case WXSuccess: strMsg = @"支付结果:成功!"; NSLog(@"支付成功-PaySuccess,retcode = %d", resp.errCode); // 这里别用返回的状态来肯定是否正真支付成功了,这样是不对的,咱们必须拿着存到本地的traderID去服务器再次check,这样和服务器收到的异步回调结果匹配以后才能确认是否真的已经支付成功了 [[TWTShoppingCartLogic sharedData] gotoCheckWeChatOrder:tradeID compelete:^(NSError *error, id data) { // 二次确认 }]; break; default: strMsg = [NSString stringWithFormat:@"支付结果:失败!retcode = %d, retstr = %@", resp.errCode,resp.errStr]; NSLog(@"错误,retcode = %d, retstr = %@", resp.errCode,resp.errStr); break; } } }
仍是总结下重要的地方吧
1.App Scheme必定要配置正确
2.千万不能用生成预订单返回的Sign,要从新生成(和后台沟通)
3.要考虑拉起App支付的时候本身程序被退出或者自杀了
4.必定不能用异步返回给App的参数进行判断成功与否,须要和后台进行二次确认,异步返回给后台的数据才是最终的
看官方给的说法
差很少介绍到这里了,本身微信遇到的坑没有接入支付宝的时候多,接过支付宝再接入
微信,真的太简单了,有空再写个支付宝支付,以为有帮到你们的记得给个赞哦~~~
遇到其余问题了再补充
12.6日更新:同一订单支付两次的问题,商户保证支付平台大姨妈的状况下去重
遇到了这么个场景,当你支付完的时候支付宝或者微信没有及时回调,用户已经支付,可是平台还在处理中,也没有异步通知商户后台,例如第一张图的支付宝同步状态码8000 or 6004,第二张图的-1,那么这个时候咱们App作完一系列操做以后非人类用户觉得没支付,可是其实已经支付了,支付宝和微信大姨妈了,土豪买家又点了支付,这个时候是和9000支付成功不一样的,成功的时候支付宝是会去重的,不会让你重复支付的,微信暂时不清楚,这个时候后台还没收到任何回调,又拉起了支付,居然还能支付,神奇的两个订单产生了,虽然最终最会成功一个订单,另外一个订单会支付失败,这个状况遇到了仍是很懵逼的,记录下,有不一样意见的能够留言分享下。
个人作法就是:
对于同步回调的状态码,让后台再开一个接口post给他,他根据这个状态码避免同一个已支付的订单,可是在处理中的时候重复签名,重复去支付,这样就又能愉快的玩耍了,虽然是比较罕见的操做,可是也得稍微留意下
这里就没有Demo了,有个官方的已经很详细了