iOS-关于微信支付
突然发现的一篇文章,这位博主介绍的还是挺详细的,给大家分享一下
不懂的也可以咨询我qq:564702640
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"@interfaceAppDelegate : 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 server
XQDataHelper *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]];
}
// 根据参数生成签名
- (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)
题外话:
若项目中用到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-关于微信支付的更多相关文章
- 关于IOS调用微信支付jsapi不起作用的解决方法
微信支付时,安卓机调用 jsapi可以支付,IOS就不行,点击立即支付,直接返回原立即支付页面,跟刷新页面差不多,解决方案很简单:两句话而已. 不得不说,微信支付坑太多了,我擦..... <sc ...
- iOS之微信支付
前言:下面介绍微信支付的开发流程的细节,图文并茂,你可以按照我的随笔流程过一遍代码.包你也学会了微信支付.而且支付也是面试常问的内容. 正文: 1.首先在开始使用微信支付之前,有一些东西是开发者必须要 ...
- iOS - WXPay 微信支付
1.微信支付申请 微信支付官方集成指引 微信支付官方集成指导视频 微信 APP 支付开发者文档 微信公众平台 微信开放平台 微信商户平台 1.1 微信 APP 支付申请步骤 APP 支付:APP 支付 ...
- IOS开发--微信支付
前言:下面介绍微信支付的开发流程的细节,图文并茂,你可以按照我的随笔流程过一遍代码.包你也学会了微信支付.而且支付也是面试常问的内容. 正文: 1.首先在开始使用微信支付之前,有一些东西是开发者必须要 ...
- iOS开发微信支付
现在基本所有的App都会接入支付宝支付以及微信支付,也有很多第三方提供给你 SDK帮你接入,但是这种涉及到支付的东西还是自己服务器搞来的好一些,其实搞懂了 逻辑非常的简单,下面直接给大家说说下基本流程 ...
- iOS 集成微信支付【转载】
目前项目里有微信支付的需求,调研过一段时间后,发现其实并没有想象中的那么困难.如果你只是想实现该功能,一个方法足以,但是若你想深入了解实现原理.就需要花费更多的功夫了.目前我只清楚微信支付需要做签名, ...
- iOS: 实现微信支付
一.介绍: 现在的消费越来越方便,直接带个手机用各种三方的支付平台进行支付就行,例如微信.支付宝.现在正好我所做的项目中用到了微信支付,今天就来整理一下. 二.准备: 1.去微信官方开发者平台注册开发 ...
- iOS集成微信支付
微信支付的开发 前言:之前听说过微信支付有很多坑,其实没有想象的那么坑,整体感觉很容易上手,按照它的流程来不会有错!PS:官方的流程看的TMD烦,好啦,废话有点多,进入开发.(ps:每个微信的版本一直 ...
- iOS开发微信支付的介绍与实现
1.前期准备 1) 到微信开放平台注册账号 需要登录邮箱验证 填写您的商户信息 2) 进入管理中心 --- 移动应用 --- 创建移动应用 --- 根据页面完善应用资料 3) 审核过后,通过应用详情页 ...
- iOS集成微信支付各种坑收录
统一下单的参数要拼接成XML格式,使用AFN请求时要对参数转义,直接传入字典给AFN无法识别(这个接口微信demo中并没有提供示例) AFHTTPRequestOperationManager *ma ...
随机推荐
- 13. 求链表倒数第k个节点
题目:输入1个链表,输出该链表倒数第k个节点,有头指针和尾指针.链表倒数第0个节点是链表的尾指针节点. 代码: /* 尾指针是倒数第0个,则倒数第k个是正数第len-k个,计算len */ #incl ...
- MysqlHelper类
连接方式:server=localhost;port=3306;userid=root;password=123456789;database=mysql;persist security info= ...
- Hibernate逍遥游记-第2章-使用hibernate.properties
1. package mypack; import org.hibernate.*; import org.hibernate.cfg.Configuration; import java.util. ...
- Android:实现退出确认对话框
在Android平台上捕获Back键的事件,super.onBackPressed()是执行系统的默认动作,就是退出当前activity,我们要做的就是重写onBackPressed()函数, pub ...
- MySQL 5.6 安装配置
mysql 5.6.17下载安装图解_百度经验 http://jingyan.baidu.com/article/4b07be3c67853c48b380f311.html windows 8 系统将 ...
- 常用JVM配置参数
常用JVM配置参数 Trace跟踪参数 堆的分配参数 栈的分配参数 Trace跟踪参数 1.打开GC的日志,如果在程序的运行过程中,系统发生了GC,就会打印相关的信息. -verbose:gc -XX ...
- SDIBT2666——逆波兰表达式求值
逆波兰表达式求值(栈和队列) Description 从键盘上输入一个逆波兰表达式,用伪码写出其求值程序.规定:逆波兰表达式的长度不超过一行,以@符作为输入结束,操作数之间用空格分隔,操作符只可能有+ ...
- The document has been modified outside of Code Composer. Would you like to reload the file
2013-06-20 10:03:32 烧写过程是合众达给出的文档 problem: I'm new to using Code Composer Studio 3.3 and am having a ...
- FastScroll(1)ListView打开FastScroll及自定义它的样式
打开 FastScroll 方式 android:fastScrollEnabled="true" 它是AbsListView的属性. <?xml version=" ...
- chrome禁用某个网站js脚本的执行
1 首先打开谷歌浏览器.如下 2 点击右上角,打开菜单进入[设置] 3 打开后,第一个界面是没有这个的,要滚动到最后点击[显示高级设置...] 4 展开第二页后,点击[隐私设置]->[内容设 ...