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 ...
随机推荐
- jquery ajax 访问webServer的xml文件
最近项目中要使用到通过ajax访问webServer的xml文件,通过下面的方式可以直接访问webServer的xml文件,不需要在web.xml中进行任何配置.它的返回参数就是服务器上的xml文件. ...
- Java Socket实战之一 单线程通信
本文地址:http://blog.csdn.net/kongxx/article/details/7259436 现在做Java直接使用Socket的情况是越来越少,因为有很多的选择可选,比如说可以用 ...
- Android TabHost 动态修改图标或者动态改变标题
那时客户需要实现在TabHost标题上动态显示从数据库获取的个数.起初这样思考的,从数据库 获取个数是非常简单,但是要把获取的个数显示在TabHost标题,思前想后,想用Handler来异步实现消息传 ...
- c++编写webui内核 .
http://blog.csdn.net/sx1989827/article/details/8068779 #pragma once #include <mshtmhst.h> #inc ...
- C++ volatile的作用
volatile的作用 2006-10-23 13:44:21 大 中 小 关键在于两个地方: 1. 编译器的优化 (请高手帮我看看下面的理解) 在本次线程内, 当读取一个变量时,为提 ...
- The only legal comparisons are between two numbers, two strings, or two dates.
The only legal comparisons are between two numbers, two strings, or two dates. Left hand operand is ...
- 通用权限管理系统Ver2.0
通用权限管理系统Ver2.0平台采用kendo+mvc4+Nhibernate技术实现,底层采用自定义ORM实现数据库底层代码,支持Oracle.SqlServer.mysql等常用数据库,界面采用k ...
- I.MX6 android shutdown 内核崩溃
/**************************************************************************** * I.MX6 android shutdo ...
- (Android Studio)添加文本框
此文大部分摘自http://hukai.me/android-training-course-in-chinese/basics/firstapp/building-ui.html android : ...
- JSON 格式的转换: 数组、字符串、List集合、DataTable,实体对象
JSON验证工具:http://jsonlint.com/JSON简明教程:http://www.w3school.com.cn/json/Newtonsoft.Json类库下载:http://jso ...