iOS微信支付接入以及工具类封装

2018 年 8 月 21 日 CocoaChina

本公众号内容均为本号转发,已尽可能注明出处。因未能核实来源或转发内容图片有权利瑕疵的,请及时联系本号,本号会第一时间进行修改或删除。 QQ : 3442093904 


在刚刚结束的一个项目中用到了微信支付,从接入微信支付到工具类的封装,在本文中做个积累,方便日后使用。


1.开始接入微信支付的准备工作



首先你需要去微信开放平台注册账号,在这里要吐槽一下,不知道这个微信平台的账号密码验证机制,忘了以前的密码,重新登录,各种找回密码都不行,实在没辙,去注册个Gmail😑,登录成功后,可以看到如下界面。



点击右上角的创建移动应用,一步一步填写必要填入的信息,在这里就不做多余的赘述了。


需要注意的是这里填入的Bundle ID需要和项目的一一对应



接下来就等一个星期左右,等待微信审核通过你就可以将微信支付SDK集成到项目中,详情可以看官方给出的文档.


pod 集成方法

pod 'WechatOpenSDK'


在Xcode中,选择你的工程设置项,选中“TARGETS”一栏,在“info”标签栏的“URL type“添加“URL scheme”为你所注册的应用程序id(如下图所示)。



完成之后可以获取到appid(微信开放平台为应用生成的唯一识别码)、商户id、商户secretKey。对于app端来说只用到appid,商户id最好通过接口从server获取,商户secretKey是用来签名的,一般只有server能用到。


2.支付流程



刚开始看这个流程图可能会觉得很复杂,所以总结了我们比较关系的流程是:


  1. app客户端向服务器发送支付请求

  2. 服务器在收到客户端请求之后向微信后台调用统一下单API,获得预付单信息

  3. 服务端生成带签名的客户端支付信息给app

  4. app客户端用户确认支付,app唤醒微信客户端进行支付

  5. app获得支付结果后向服务端查询最终的结果并显示


app端的工作:


  • 接入微信支付SDK

  • 向服务器发送支付请求

  • 支付信息唤醒微信app,然后进行支付

  • 收到微信支付回调后向服务器确认支付结果

  • 根据查询结果展示结果页面告知用户支付结果


服务器端的工作:


  • 收到app客户端支付请求后向微信后台请求预支付订单

  • 服务器端签名并返回信息给app客户端

  • 接收微信后台返回的支付结果,用来app端查询


服务器端返回的字段说明:


appId:返回的appid

partnerId: 父级id

prepayId: 支付id

packages: 包名(微信默认的为“Sign=WXPay”)

nonceStr: 生成的随机字符串

timesTamp: 时间戳

sign: 签名



3.iOS端使用


在AppDelegate.m,导入微信SDK头文件WXApi.h

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[WXApi registerApp:@"注册获得的appid"];//注册appid
    return YES;
}

 //支持所有iOS系统回调
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
//    [self handleOpenURL:url];
    BOOL result = [[UMSocialManager defaultManager] handleOpenURL:url sourceApplication:sourceApplication annotation:annotation];
    if (!result) {
        // 其他如支付等SDK的回调
        [self handleOpenURL:url];
    }
    return YES;
}
- (void)handleOpenURL:(NSURL*)url {
    if ([url.host isEqualToString:@"pay"]) { // -- 微信支付
        [WXApi handleOpenURL:url delegate:[WXPayService sharedInstance]];
    }
}


此处的WXPayService就是自己单独抽出来写的一个类,遵循WXApiManagerDelegate协议


WXPayService.h

#import <Foundation/Foundation.h>
#import "WXApi.h"
@interface WXPayService : NSObject <WXApiDelegate>
///单例来接收微信请求的回调
+ (instancetype)sharedInstance;
// -- 根据接口返回的预支付信息,构造支付请求
+ (PayReq *)getPayRequest:(NSDictionary *)prepayData;

///处理非支付请求的回调
- (void)onRespCallBack:(void(^)(BaseResp * resp))callback;
///从服务器端获取到微信返回的支付请求用到的参数来发起支付请求
- (void)startPayWithReq:(PayReq *)req callback:(void(^)(BaseResp * resp))callback; 
@end


WXPayService.m

#import "WXPayService.h"
@interface WXPayService ()
@property (nonatomic,copyvoid(^RespCallBack)(BaseResp *);
@end
static WXPayService *sharedInstance;

@implementation WXPayService
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [super allocWithZone:zone];
    });
    return sharedInstance;
}
///单例来接收微信请求的回调
+ (instancetype)sharedInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

// -- 根据接口返回的预支付信息,构造支付请求
+ (PayReq *)getPayRequest:(NSDictionary *)prepayData {
    if (prepayData) {
//  此处Tools是自己的另一个工具类,用来判断字典的
        PayReq *req = [[PayReq alloc] init];
        if ([Tools dicContain:prepayData withKey:@"partnerid"]) {
            req.partnerId = prepayData[@"partnerid"];
        }
        if ([Tools dicContain:prepayData withKey:@"prepayid"]) {
            req.prepayId = prepayData[@"prepayid"];
        }
        if ([Tools dicContain:prepayData withKey:@"noncestr"]) {
            req.nonceStr = prepayData[@"noncestr"];
        }
        if ([Tools dicContain:prepayData withKey:@"timestamp"]) {
            req.timeStamp = [prepayData[@"timestamp"] intValue];
        }

        req.package =@"Sign=WXPay";
        req.sign =  @"null";
        //日志输出
        NSLog(@"appid=%@/npartid=%@/nprepayid=%@/nnoncestr=%@/ntimestamp=%ld/npackage=%@/nsign=%@",[prepayData objectForKey:@"appid"],req.partnerId,req.prepayId,req.nonceStr,(long)req.timeStamp,req.package,req.sign);
        return req;
    }
    return nil;
}

///处理非支付请求的回调
- (void)onRespCallBack:(void(^)(BaseResp * resp))callback {
    self.RespCallBack = callback;
}
///从服务器端获取到微信返回的支付请求用到的参数来发起支付请求
- (void)startPayWithReq:(PayReq *)req callback:(void(^)(BaseResp * resp))callback {
    NSAssert(req !=nil , @"未成功创建微信支付请求");
    self.RespCallBack = callback;
    if ([WXApi isWXAppInstalled]) { // -- 判断是否安装微信应用
        //发起微信支付,设置参数
        [WXApi sendReq:req];
    }else {
        self.RespCallBack(nil);
    }
}

#pragma mark WXApiDelegate
- (void)onResp:(BaseResp *)resp {
    if ([resp isKindOfClass:[PayResp class]]) { // -- 判断是否为支付的回调
        self.RespCallBack(resp);
    }
}
@end


在需要支付的ViewController中导入工具类WXPayService


4.注意点及问题


注意点:


  • 设置好scheme,否则应用无法跳转到微信客户端

  • 支付签名时的key值全部是小写的

  • 如果支付显示验证签名失败的时候,可以将packages设为默认值(Sign=WXPay)试试


问题:


系统版本大于等于iOS9的,调起微信客户端之后,可以直接点击状态栏左侧按钮返回,这时是不走回调方法的。


解决方案:

在AppDelegate.m的applicationWillEnterForeground方法中,调用查询支付结果接口然后刷新当然页面。需要设置bool变量作为标志,否则每次应用进入前台都去查询,就不符合业务要求了。


进入微信支付页面之后,不做操作,切换到自己应用中,退出当前支付页面,然后再进入微信客户端点击支付或者取消,此时自己的应用会崩溃闪退


原因:退出页面后页面已经出栈被销毁,但wx回调时还是去调用其中的代理方法,就会出现野指针。


解决方案:在页面的viewWillDisappear方法中加入

[WXPayService sharedManager].delegate = nil;


5.结束语


微信支付签名建议和服务端协商做二次签名,以保证支付的安全性。


作者:JackerooChu

链接:https://www.jianshu.com/p/9afae0cf6c60


相关推荐:


登录查看更多
0

相关内容

【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
122+阅读 · 2020年5月10日
【干货书】流畅Python,766页pdf,中英文版
专知会员服务
226+阅读 · 2020年3月22日
【经典书】Python计算机视觉编程,中文版,363页pdf
专知会员服务
142+阅读 · 2020年2月16日
【书籍推荐】简洁的Python编程(Clean Python),附274页pdf
专知会员服务
182+阅读 · 2020年1月1日
【电子书】Flutter实战305页PDF免费下载
专知会员服务
23+阅读 · 2019年11月7日
Keras作者François Chollet推荐的开源图像搜索引擎项目Sis
专知会员服务
30+阅读 · 2019年10月17日
AWVS12 V12.0.190530102 windows正式版完美破解版
黑白之道
29+阅读 · 2019年8月24日
今日头条技术架构分析
互联网架构师
11+阅读 · 2019年8月19日
PHP使用Redis实现订阅发布与批量发送短信
安全优佳
7+阅读 · 2019年5月5日
7 款实用到哭的App,只说一遍
高效率工具搜罗
84+阅读 · 2019年4月30日
Pupy – 全平台远程控制工具
黑白之道
43+阅读 · 2019年4月26日
支持多标签页的Windows终端:Fluent 终端
Python程序员
7+阅读 · 2019年4月15日
超级!超级!超级好用的视频标注工具
极市平台
8+阅读 · 2018年12月27日
【智能商务】海量商品查找利器—苏宁搜索系统
产业智能官
5+阅读 · 2017年12月1日
Attend More Times for Image Captioning
Arxiv
6+阅读 · 2018年12月8日
Video-to-Video Synthesis
Arxiv
9+阅读 · 2018年8月20日
VIP会员
相关资讯
AWVS12 V12.0.190530102 windows正式版完美破解版
黑白之道
29+阅读 · 2019年8月24日
今日头条技术架构分析
互联网架构师
11+阅读 · 2019年8月19日
PHP使用Redis实现订阅发布与批量发送短信
安全优佳
7+阅读 · 2019年5月5日
7 款实用到哭的App,只说一遍
高效率工具搜罗
84+阅读 · 2019年4月30日
Pupy – 全平台远程控制工具
黑白之道
43+阅读 · 2019年4月26日
支持多标签页的Windows终端:Fluent 终端
Python程序员
7+阅读 · 2019年4月15日
超级!超级!超级好用的视频标注工具
极市平台
8+阅读 · 2018年12月27日
【智能商务】海量商品查找利器—苏宁搜索系统
产业智能官
5+阅读 · 2017年12月1日
Top
微信扫码咨询专知VIP会员