最近项目要添加微信支付的功能,也是因为首次做微信支付,故笔记于下,避免下次又掉坑!

1、申请接入

详见 微信支付申请接入 。
创建应用+审核通过,你将得到:APP_ID、APP_SECRET、APP_KEY、PARTNER_ID 。那就可以开始实现支付功能的接入。

2、业务流程

不管是客户端还是后台开发者,微信支付开发者文档里面这张交互时序图,都有必要看看。其实很多开发者,当然也包括我,在接入第三方sdk时,一般都是从其官方demo入手,快速了解其api。结果在这里就掉坑里了(后续细讲)。因为微信支付sdk,不像其他第三方的sdk,只需客户端导入实现即可,还需要本地服务器配合。这里就涉及了:

  • 本地服务器与微信支付系统的交互
  • 客户端与本地服务器的交互

从交互时序图可以发现,不存在客户端与微信支付系统的交互!第二步对支付的流程有一个大概的了解。

3、客户端具体开发步骤

1、项目配置

打开项目–TARGETS – Info – URL types (或者 info.plist 的 URL types)设置你的APP_ID 。

2、注册APPID

在项目中引入微信支付的SDK、lib库、头文件后,在AppDelegate文件中:

  • AppDelegate.h
#import <UIKit/UIKit.h>
#import "payRequsestHandler.h"
#import "WXApi.h"
@interface AppDelegate : UIResponder < UIApplicationDelegate,WXApiDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
  • AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {...//向微信注册BOOL isok = [WXApi registerApp:WEIXIN_APP_ID];if (isok) {DLog(@"注册微信成功");}else{DLog(@"注册微信失败");}...}...- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{return  [WXApi handleOpenURL:url delegate:self];
}- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{return  [WXApi handleOpenURL:url delegate:self];
}
...
/* WXApiDelegate代理方法
** onReq是微信终端向第三方程序发起请求,要求第三方程序响应。第三方程序响应完后必须调用sendRsp返回。在调用sendRsp返回时,会切回到微信终端程序界面。
*/
-(void) onResp:(BaseResp*)resp
{if([resp isKindOfClass:[PayResp class]]){//支付返回结果,实际支付结果需要去微信服务器端查询[[NSNotificationCenter defaultCenter]postNotificationName:NOTIFICATION_WEIXIN_PAY_BACK object:[NSNumber numberWithInt:resp.errCode]];}
}
@end

3、创建支付

当在app端点击去支付,app server 会先生成订单,再调用微信支付提高的 统一下单API 生成预支付单,即prepay_id,然后进行二次签名,返回给客户端一个参数列表(其包含appId,partnerId,prepayId,nonceStr,timeStamp,package。注意:package的值格式为Sign=WXPay)。app收到返回的参数列表后,就可以创建支付:

#pragma mark weixin pay
//创建微信支付
- (void)weixinPay
{
//_orderId为订单号,作为参数传递给app serverXQDataHelper *helper = [[XQDataHelper alloc]init];[helper createPayWithOrderId:_orderId sucessed:^(id resultObj) {NSDictionary *dict = resultObj;//获取到实际调起微信支付的参数后,在app端调起支付if(dict){NSMutableString *stamp = dict[@"timestamp"];//调起微信支付PayReq* req   = [[PayReq alloc] init];req.openID    = dict [@"appid"];req.partnerId = dict [@"partnerid"];req.prepayId  = dict [@"prepayid"];req.nonceStr  = dict [@"noncestr"];req.timeStamp = stamp.intValue;req.package   = dict [@"package"];req.sign      = dict [@"sign"];BOOL bs = [WXApi isWXAppSupportApi];if (bs) {BOOL isok = [WXApi sendReq:req];if (isok) {DLog(@"调用微信支付成功");}else{DLog(@"调用微信支付失败");}}else{DLog(@"微信版本过低,不支持支付");}}} failed:^(NSString *strError) {}];
}#pragma mark weixinpay 回掉
//当收到微信支付回掉通知时
-(void) weixinPayBack:(NSNotification*)notif{int code = [notif.object intValue];switch (code) {case WXSuccess:{DLog(@"支付成功");}break;case WXErrCodeUserCancel:{DLog(@"支付取消");}break;default:{DLog(@"支付失败");}break;}
}

4、客户端实现2次签名

以上就是成功创建支付的实现方法,那么在创建支付时,客户端能否实现2次签名,来生成参数,创建支付呢?答案是肯定的。
(好吧,如果app server没有理解支付的交互逻辑,而在创建支付时,只返回给你一个预支付号,让你来实现生成其他需要的参数时,你就可以这么干!)
但是,要清楚,支付签名放在客户端是很不安全的,所以,不建议放在客户端来实现。
创建支付,首先得创建一个PayReq的对象,其属性有:

@property (nonatomic, retain) NSString* openID;
/** 商家向财付通申请的商家id */
@property (nonatomic, retain) NSString *partnerId;
/** 预支付订单 */
@property (nonatomic, retain) NSString *prepayId;
/** 随机串,防重发 */
@property (nonatomic, retain) NSString *nonceStr;
/** 时间戳,防重发 */
@property (nonatomic, assign) UInt32 timeStamp;
/** 商家根据财付通文档填写的数据和签名 */
@property (nonatomic, retain) NSString *package;
/** 商家根据微信开放平台文档对数据做的签名 */
@property (nonatomic, retain) NSString *sign;

从微信支付开放文档-调起支付接口 也可以对请求参数有所认识,其中openID即appid,故已有的参数:openID、partnerId、prepayId。那么主要是生成nonceStr、timeStamp、package和sign。其中package又为固定值Sign=WXPay,所以就只需实现nonceStr、timeStamp、sign的生成。

而在官方文档及Demo中,生成方法都有提及:

#pragma mark - 生成各种参数
// 获取时间戳
- (NSString *)genTimeStamp
{return [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]];
}/***  获取32位内的随机串noncestr, 防重发**  注意:商户系统内部的订单号,32个字符内、可包含字母,确保在商户系统唯一*/
- (NSString *)genNonceStr
{return [WXUtil md5:[NSString stringWithFormat:@"%d", arc4random() % 10000]];
}

而sign的生成规则稍显复杂,相见官方签名算法文档

// 根据参数生成签名
- (NSString *)genSign:(NSDictionary *)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=%@", APP_KEY];//即创建应用时生成的//得到MD5 sign签名NSString *md5Sign =[WXUtil md5:contentString];return md5Sign;
}

需要的参数都生成了,那么创建支付如下:

 - (void)weixinPay
{//_orderId为订单号,作为参数传递给app server,而app server只给你返回了预支付号时XQDataHelper *helper = [[XQDataHelper alloc]init];[helper createPayWithOrderId:_orderId sucessed:^(id resultObj) {NSString *repayId = resultObj;if(repayId){NSString *timeStamp = [self genTimeStamp];//调起微信支付PayReq* req   = [[PayReq alloc] init];req.openID    = APP_ID;req.partnerId = PARTNER_ID;req.prepayId  = repayId;//req.nonceStr  = [self genNonceStr];req.timeStamp = [timeStamp intValue];req.package   = @"Sign=WXPay";// 构造参数列表NSMutableDictionary *params = [NSMutableDictionary dictionary];[params setObject:APP_ID forKey:@"appid"];[params setObject:APP_KEY forKey:@"appkey"];[params setObject:req.nonceStr forKey:@"noncestr"];[params setObject:req.package forKey:@"package"];[params setObject:req.partnerId forKey:@"partnerid"];[params setObject:req.prepayId forKey:@"prepayid"];[params setObject:timeStamp forKey:@"timestamp"];req.sign = [self genSign:params];BOOL bs = [WXApi isWXAppSupportApi];if (bs) {BOOL isok = [WXApi sendReq:req];if (isok) {DLog(@"调用微信支付成功");}else{DLog(@"调用微信支付失败");}}else{DLog(@"微信版本过低,不支持支付");}}} failed:^(NSString *strError) {}];
}

5、在过程中遇到的问题

1、点击支付不跳转到微信app

  • 问题:点击支付,发现app没有跳转到微信,更没有执行回掉,结果发现调用微信支付返回失败
BOOL isok = [WXApi sendReq:req];
if (isok) {DLog(@"调用微信支付成功");
}else{DLog(@"调用微信支付失败");
}
  • 原因:因为项目里面还用到umeng分享sdk,其中也集成了libWeChatSDK.a等文件,将其删除,重置Search Paths。(我是将其都彻底删除,然后又重新添加最新的libWeChatSDK.a等文件,这样Search Paths自动设置好了)

2、跳转到微信后又很快跳转回app,并且报错支付失败

  • 问题:跳转到微信后又很快跳转回app,并且回掉时log错误为:
retcode = -1, retstr = (null)
  • 原因:参数签名错误,即sign生成出错,可能是某个参数传递错误或者不匹配。若2次签名为服务器实现,那么就找app server探讨吧,若客户端生成,就一步一步检查本地参数生成代码吧。

题外话:
若项目中用到umeng分享来实现微信的分享的话,请注意,umeng为了实现分享后从其他app跳转回来,肯定在AppDelegate.m中实现了如下:

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{return  [UMSocialSnsService handleOpenURL:url];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{return [UMSocialSnsService handleOpenURL:url];
}

当然,也是实现了-(void) onResp:(BaseResp*)resp 方法,只是封装了,你看不到而已,此时调用支付,你会发现,根本不会执行你实现的-(void) onResp:(BaseResp*)resp 方法。因为被umeng给实现啦!
所以应该区别开来:

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{return  [UMSocialSnsService handleOpenURL:url];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{NSString *urlStr = [NSString stringWithFormat:@"%@",url];if ([sourceApplication isEqualToString:@"com.tencent.xin"] && [urlStr containsString:@"pay"]) {return [WXApi handleOpenURL:url delegate:self];}return [UMSocialSnsService handleOpenURL:url];
}

这样,微信支付则能正常回调。


iOS-关于微信支付相关推荐

  1. 解决ios H5微信支付不能跳回App的问题

    解决ios H5微信支付不能跳回App的问题 app项目是uni-app开发的安卓和iOS版本,安卓测试无问题,以下主要说iOS的解决方案. 问题点:app用webview打开H5页面,在H5页面发起 ...

  2. 关于IOS调用微信支付jsapi不起作用的解决方法

    关于IOS调用微信支付jsapi不起作用的解决方法 参考文章: (1)关于IOS调用微信支付jsapi不起作用的解决方法 (2)https://www.cnblogs.com/randy619/p/5 ...

  3. iOS之“微信支付”开发流程

    实现微信支付的开发,iOS端里面只需要四个步骤: 向服务端请求预支付,获得prepayid以及noncestr: 把参数拼起来签名: 发起支付请求: 处理支付结果. iOS的微信SDK的接入:即为&q ...

  4. iOS开发微信支付的介绍与实现

    1.前期准备 1) 到微信开放平台注册账号 需要登录邮箱验证 填写您的商户信息 2) 进入管理中心 --- 移动应用 --- 创建移动应用 --- 根据页面完善应用资料 3) 审核过后,通过应用详情页 ...

  5. ios调用微信支付提示当前页面的URL未注册

      ios调用JSAPI微信支付提示"当前页面的URL未注册",而页面手动刷新后再次支付则正常,安卓也正常,肯定不是授权目录配置问题.   在微信支付页面,当通过JSAPI微信支付 ...

  6. ios浏览器微信支付回调页面_iOS集成H5微信支付实现跳转与回调的解决方案

    前言 最近有个需求,不能在iOS客户端内集成支付宝和微信的App支付SDK(为了防苹果审核检测SDK),因此使用H5支付,虽然微信和支付宝的H5支付文档都说不要在App内使用H5支付而是使用App支付 ...

  7. iOS 集成微信支付

    前言 最近在进行的项目,需要集成第三方支付.业务需要集成支付宝,微信,银联,Paypal等支付方式.在使用各家sdk时会发现有些第三方sdk调用时不够方便,简单.所以就有了进行再次封装的想法. 资源文 ...

  8. IOS集成微信支付或者支付宝支付功能小结

    2019独角兽企业重金招聘Python工程师标准>>> 第一,你需要有微信开发平台的开发者账号,(网址https://open.weixin.qq.com/,或者自行百度" ...

  9. iOS H5微信支付总结

    功能描述 1.webView加载H5页面 2.点击微信支付,调起微信客户端支付 3.支付完成,返回APP 操作流程 1.调起微信的项目设置 选中'TARGETS'一栏,在'info'中的'LSAppl ...

  10. iOS集成微信支付--Swift

    微信支付在微信红包的推动发展势头越来越猛,甚至有超过支付宝的趋势,那么在App集成微信支付也是比不可少了.我最近在一个项目中集成微信支付遇到了不少问题,Google了不少资料才搞定,不得不吐槽一下微信 ...

最新文章

  1. 《C#3.0 in a Nutshell ,3rd Edition》之序言篇
  2. 修改 keystore密码
  3. Android:按键响应方式第一种onClick属性,第二种方法接口类,第三种方式匿名内部类,第四种方式Activity
  4. F - 数据结构实验之查找六:顺序查找
  5. 离散分布概率:几何分布、二项分布和泊松分布
  6. 演讲预告:一个月的住院经历,我悟到了哪些和程序员职场发展相关的心得
  7. 实分析royden第四版答案_高价实木变板木掺了“假”的实木家具!搞懂这些名词,买家具不上当...
  8. 可以同时开发php Java_php可以和java一起开发吗
  9. redis源码剖析(2):基础数据结构ADLIST
  10. 4.3.2深度定时任务(TimerTask in Depth)
  11. 浪曦视频--工厂方法模式
  12. Pr 视频效果:过时
  13. 电脑重启bootmgr_解决电脑出现bootmgr is missing如何解决
  14. 论文阅读|用于不同问题的MADDPG算法框架系列论文汇总
  15. android 黑白屏问题
  16. 百度地图集成,经纬度返回 4.9e-324
  17. 北京信息科技大学计算机研究生在哪个校区,北京信息科技大学有几个校区,哪个校区最好及各校区介绍...
  18. uni-app如何使用HBuildX云打包发布app
  19. Python 制作、发布与安装模块
  20. 【工具篇】云原生架构,DevOps介绍

热门文章

  1. 强化学习算法:AC系列详解
  2. 数独游戏-安卓版源代码和分析。
  3. Web前端—01HTML超文本标记语言
  4. 图解MySQL系列(2)-SQL实战研究InnoDB架构设计
  5. 713页鸿蒙巨作《鸿蒙HarmonyOS手机应用开发实战》简介
  6. RGB图像转HSI直方图均衡化后再转回RGB
  7. 微信小程序登录 返回 -41003
  8. 08.29web自动化测试
  9. Qtum量子链发布QIP-7:Qtum虚拟机升级,五大更新全面提升开发性能
  10. 新一代云数据库的引领者---AWS