iOS 支付宝、微信支付的集成记录
一、前言
最近项目需求需要集成支付宝和微信支付,以前没有接触过,这次正好乘着这次机会了解下。
总的来说,客户端的工作不多,无非就是就是集成SDK,然后获取后端传来的参数,吊起支付,回调处理等。
先附上官方文档链接:
支付宝:https://docs.open.alipay.com/204
微信支付:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_1
废话不多说,开始吧。
二、支付宝
1、先集成SDK
pod ‘AlipaySDK-iOS‘
2、导入头文件
#import <AlipaySDK/AlipaySDK.h>
3、构造支付宝管理类,方便项目调用
#import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface BYAlipayManager : NSObject //生成支付宝单例类 + (id)sharePayManager; //支付宝支付 //aParam 后端返回支付信息 - (void)handleOrderPayWithParams:(NSString *)aParam; @end NS_ASSUME_NONNULL_END
#import "BYAlipayManager.h" @implementation BYAlipayManager + (id)sharePayManager{ static BYAlipayManager *asAlixPay = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ asAlixPay = [[BYAlipayManager alloc] init]; }); return asAlixPay; } - (void)handleOrderPayWithParams:(NSString *)aParam{ NSLog(@"aParm = %@",aParam); NSString *appScheme = @"alipayBYVideopay";//appScheme是你在项目中添加的URL Type(别写错) NSString *orderString = aParam;//aParam[@"payInfo"]; // NOTE: 调用支付结果开始支付 [[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) { NSLog(@"reslut = %@",resultDic); int statusCode = [resultDic[@"resultStatus"] intValue]; if (statusCode == 9000){ //订单支付 [kKeyWindow makeToast:@"支付成功"]; [[NSNotificationCenter defaultCenter] postNotificationName:KFNNotificationAlipay_paySuccess object:nil]; }else{ //交易失败 [kKeyWindow makeToast:@"支付异常"]; [[NSNotificationCenter defaultCenter] postNotificationName:KFNNotificationAlipay_payFaile object:nil]; } }]; }
说明:
- 实际支付的时候,后端会给前端一个很长的字符串,里面是特殊处理过的数据,客户端拿到这份数据之后就可以直接调用支付宝的SDK,然后处理回调事件就好了。
- appScheme 这个字符串是一段特殊的字符串,自取,标明自身APP的,需要添加到项目的 info ---> URL Types 里面,见截图
4、AppDelegate设置
#pragma mark - openURL Delegate - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { if ([url.host isEqualToString:@"safepay"]) { // 支付跳转支付宝钱包进行支付,处理支付结果 [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) { [self disposeAilyPayResultWith:resultDic]; }]; // 授权跳转支付宝钱包进行支付,处理支付结果 [[AlipaySDK defaultService] processAuth_V2Result:url standbyCallback:^(NSDictionary *resultDic) { [self disposeAilyPayResultWith:resultDic]; // 解析 auth code NSString *result = resultDic[@"result"]; NSString *authCode = nil; if (result.length>0) { NSArray *resultArr = [result componentsSeparatedByString:@"&"]; for (NSString *subResult in resultArr) { if (subResult.length > 10 && [subResult hasPrefix:@"auth_code="]) { authCode = [subResult substringFromIndex:10]; break; } } } NSLog(@"授权结果 authCode = %@", authCode?:@""); }]; } else if ([url.scheme containsString:WeiXinPayKey]) { if ([url.absoluteString containsString:[NSString stringWithFormat:@"%@://pay", WeiXinPayKey]]) { return [BYWeiXinPayManager handleOpenUrl:url]; } else if ([url.absoluteString containsString:[NSString stringWithFormat:@"%@://oauth?", WeiXinPayKey]]) { return [BYWeiXinPayManager handleOpenUrl:url]; } } return YES; } // NOTE: 9.0以后使用新API接口 - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options { if ([url.host isEqualToString:@"safepay"]) { // 支付跳转支付宝钱包进行支付,处理支付结果 [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) { [self disposeAilyPayResultWith:resultDic]; }]; // 授权跳转支付宝钱包进行支付,处理支付结果 [[AlipaySDK defaultService] processAuth_V2Result:url standbyCallback:^(NSDictionary *resultDic) { [self disposeAilyPayResultWith:resultDic]; // 解析 auth code NSString *result = resultDic[@"result"]; NSString *authCode = nil; if (result.length>0) { NSArray *resultArr = [result componentsSeparatedByString:@"&"]; for (NSString *subResult in resultArr) { if (subResult.length > 10 && [subResult hasPrefix:@"auth_code="]) { authCode = [subResult substringFromIndex:10]; break; } } } NSLog(@"授权结果 authCode = %@", authCode?:@""); }]; } else if ([url.scheme containsString:WeiXinPayKey]) { if ([url.absoluteString containsString:[NSString stringWithFormat:@"%@://pay", WeiXinPayKey]]) { return [BYWeiXinPayManager handleOpenUrl:url]; } else if ([url.absoluteString containsString:[NSString stringWithFormat:@"%@://oauth?", WeiXinPayKey]]) { return [BYWeiXinPayManager handleOpenUrl:url]; } } return YES; } - (void)disposeAilyPayResultWith:(NSDictionary *)resultDic { NSLog(@"支付宝支付跳转 result = %@",resultDic); int statusCode = [resultDic[@"resultStatus"] intValue]; if (statusCode == 9000){ //订单支付 [kKeyWindow makeToast:@"支付成功"]; [[NSNotificationCenter defaultCenter] postNotificationName:KFNNotificationAlipay_paySuccess object:nil]; }else{ //交易失败 [[NSNotificationCenter defaultCenter] postNotificationName:KFNNotificationAlipay_payFaile object:nil]; [kKeyWindow makeToast:@"支付异常"]; } }
说明:直接拷贝就行,这块代码是不变的。
5、调用支付
[[BYAlipayManager sharePayManager] handleOrderPayWithParams:responseBody];
说明:responseBody :后端传过来的支付参数
6、处理通知
- (void)addNotionAction { [kNotificationCenter addObserver:self selector:@selector(ailyPaySuccessAction) name:KFNNotificationAlipay_paySuccess object:nil]; [kNotificationCenter addObserver:self selector:@selector(ailyPayFaileAction) name:KFNNotificationAlipay_payFaile object:nil]; } - (void)dealloc { [kNotificationCenter removeObserver:self]; } - (void)ailyPaySuccessAction { //处理支付结果 } - (void)ailyPayFaileAction { //支付异常 }
说明:支付宝的支付系统还是比较简单的,客户端能做的事情不多。一般只需要处理下支付成功的回调。
三、微信支付
1、集成SDK
pod ‘WechatOpenSDK‘
2、导入头文件
#import <WXApi.h>
3、在AppDeletegate 注册
//注册微信 BOOL isSuccess = [WXApi registerApp:WeiXinPayKey universalLink:WeiXinLinks]; if (isSuccess) { NSLog(@"微信API注册成功"); } else { NSLog(@"微信API注册失败"); }
说明:WeiXinPayKey:APP在微信开发者网站上申请的Key。WeiXinLinks:微信开发者Universal Link(这个有点麻烦,后面会详细说明,先把集成过程讲完)。
4、构造支付管理类
#import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface BYWeiXinPayManager : NSObject + (BYWeiXinPayManager *)getInstance; + (BOOL)handleOpenUrl:(NSURL *)url; + (void)hangleWeiXinPayWith:(PayReq *)req; @end NS_ASSUME_NONNULL_END
#import "BYWeiXinPayManager.h" static BYWeiXinPayManager *weiXinPayInstance = nil; @interface BYWeiXinPayManager ()<WXApiDelegate> @end @implementation BYWeiXinPayManager + (BYWeiXinPayManager *)getInstance { if (weiXinPayInstance == nil) { weiXinPayInstance = [[BYWeiXinPayManager alloc] init]; } return weiXinPayInstance; } + (BOOL)handleOpenUrl:(NSURL *)url { return [WXApi handleOpenURL:url delegate:[BYWeiXinPayManager getInstance]]; } + (void)hangleWeiXinPayWith:(PayReq *)req { [WXApi sendReq:req completion:^(BOOL success) { if (success) { [kKeyWindow makeToast:@"微信支付成功"]; } else { [kKeyWindow makeToast:@"微信支付异常"]; } }]; } ///微信支付回调 - (void)onResp:(BaseResp *)resp { if ([resp isKindOfClass:[PayResp class]]){ /* enum WXErrCode { WXSuccess = 0, < 成功 WXErrCodeCommon = -1, < 普通错误类型 WXErrCodeUserCancel = -2, < 用户点击取消并返回 WXErrCodeSentFail = -3, < 发送失败 WXErrCodeAuthDeny = -4, < 授权失败 WXErrCodeUnsupport = -5, < 微信不支持 }; */ PayResp *response = (PayResp*)resp; switch (response.errCode) { case WXSuccess: { [kKeyWindow makeToast:@"微信支付成功"]; [[NSNotificationCenter defaultCenter] postNotificationName:KFNNotificationAlipay_paySuccess object:nil userInfo:nil]; } break; case WXErrCodeCommon: { [kKeyWindow makeToast:@"微信支付异常"]; } break; case WXErrCodeUserCancel: { [kKeyWindow makeToast:@"用户取消支付"]; } break; case WXErrCodeSentFail: { [kKeyWindow makeToast:@"发送支付信息失败"]; } break; case WXErrCodeAuthDeny: { [kKeyWindow makeToast:@"微信授权失败"]; } break; case WXErrCodeUnsupport: { [kKeyWindow makeToast:@"微信版本暂不支持"]; } break; default: break; } } }
说明:可以看到这里的支付成功回调我用的通知是和支付宝支付成功的通知一样,不需要单独再写一个微信支付成功的通知。
5、AppDeletage 处理支付SDK回调
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { if ([url.host isEqualToString:@"safepay"]) { // 支付跳转支付宝钱包进行支付,处理支付结果 [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) { [self disposeAilyPayResultWith:resultDic]; }]; // 授权跳转支付宝钱包进行支付,处理支付结果 [[AlipaySDK defaultService] processAuth_V2Result:url standbyCallback:^(NSDictionary *resultDic) { [self disposeAilyPayResultWith:resultDic]; // 解析 auth code NSString *result = resultDic[@"result"]; NSString *authCode = nil; if (result.length>0) { NSArray *resultArr = [result componentsSeparatedByString:@"&"]; for (NSString *subResult in resultArr) { if (subResult.length > 10 && [subResult hasPrefix:@"auth_code="]) { authCode = [subResult substringFromIndex:10]; break; } } } NSLog(@"授权结果 authCode = %@", authCode?:@""); }]; } else if ([url.scheme containsString:WeiXinPayKey]) { if ([url.absoluteString containsString:[NSString stringWithFormat:@"%@://pay", WeiXinPayKey]]) { return [BYWeiXinPayManager handleOpenUrl:url]; } else if ([url.absoluteString containsString:[NSString stringWithFormat:@"%@://oauth?", WeiXinPayKey]]) { return [BYWeiXinPayManager handleOpenUrl:url]; } } return YES; } // NOTE: 9.0以后使用新API接口 - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options { if ([url.host isEqualToString:@"safepay"]) { // 支付跳转支付宝钱包进行支付,处理支付结果 [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) { [self disposeAilyPayResultWith:resultDic]; }]; // 授权跳转支付宝钱包进行支付,处理支付结果 [[AlipaySDK defaultService] processAuth_V2Result:url standbyCallback:^(NSDictionary *resultDic) { [self disposeAilyPayResultWith:resultDic]; // 解析 auth code NSString *result = resultDic[@"result"]; NSString *authCode = nil; if (result.length>0) { NSArray *resultArr = [result componentsSeparatedByString:@"&"]; for (NSString *subResult in resultArr) { if (subResult.length > 10 && [subResult hasPrefix:@"auth_code="]) { authCode = [subResult substringFromIndex:10]; break; } } } NSLog(@"授权结果 authCode = %@", authCode?:@""); }]; } else if ([url.scheme containsString:WeiXinPayKey]) { if ([url.absoluteString containsString:[NSString stringWithFormat:@"%@://pay", WeiXinPayKey]]) { return [BYWeiXinPayManager handleOpenUrl:url]; } else if ([url.absoluteString containsString:[NSString stringWithFormat:@"%@://oauth?", WeiXinPayKey]]) { return [BYWeiXinPayManager handleOpenUrl:url]; } } return YES; } - (void)disposeAilyPayResultWith:(NSDictionary *)resultDic { NSLog(@"支付宝支付跳转 result = %@",resultDic); int statusCode = [resultDic[@"resultStatus"] intValue]; if (statusCode == 9000){ //订单支付 [kKeyWindow makeToast:@"支付成功"]; [[NSNotificationCenter defaultCenter] postNotificationName:KFNNotificationAlipay_paySuccess object:nil]; }else{ //交易失败 [[NSNotificationCenter defaultCenter] postNotificationName:KFNNotificationAlipay_payFaile object:nil]; [kKeyWindow makeToast:@"支付异常"]; } }
说明:代码和上面支付宝的代码一样的,微信URL判断是看是否包含 微信Key这个字段
6、URL - Types 设置
说明:schemes 这个字段直接填微信平台上的APPID就好。
7、调用支付
NSDictionary *dict = [arg objectOrNilForKey:@"retData"]; PayReq* req = [[PayReq alloc] init]; req.nonceStr = [dict objectForKey:@"noncestr"]; req.timeStamp = [[dict objectForKey:@"timestamp"] intValue]; req.package = [dict objectForKey:@"package"]; req.partnerId = [dict objectForKey:@"partnerid"]; req.prepayId = [dict objectForKey:@"prepayid"]; req.sign = [dict objectForKey:@"sign"]; [BYWeiXinPayManager hangleWeiXinPayWith:req];
说明:
/** 商家向财付通申请的商家id */ @property (nonatomic, copy) NSString *partnerId; /** 预支付订单 */ @property (nonatomic, copy) NSString *prepayId; /** 随机串,防重发 */ @property (nonatomic, copy) NSString *nonceStr; /** 时间戳,防重发 */ @property (nonatomic, assign) UInt32 timeStamp; /** 商家根据财付通文档填写的数据和签名 */ @property (nonatomic, copy) NSString *package; /** 商家根据微信开放平台文档对数据做的签名 */ @property (nonatomic, copy) NSString *sign;
8、最后处理下支付成功的通知即可。
9、微信开发者Universal Link的构造
1、Universal Link是什么?这个暂不多说,简单来说就是一个地址,通过这个地址可以来让你的APP被微信识别(就这么理解吧)。
2、格式:一般是公司APP的官网即可,要以https开头,以 / 结尾。举例:https://wechat.dtslb.com/
3、先在微信开发者官网上填好该地址,然后再Xcode --> Signing & Capabilities 添加 Associated Domains ,格式是以 applinks: 开头,后面接上公司官网,举例:applinks:https://wechat.dtslb.com
4、生成 apple-app-site-association 文件格式,这个文件是没有格式的,你可以新建一个TXT文件,然后把文件名改为这个,文件格式删掉。编辑里面的内容
{ "applinks": { "apps": [], "details": [ { "appID": "TemaID.BoundleID", "paths": [ "*" ] } ] } }
说明:APPID的格式就是 开发者账号的 团队ID.自己APP的boundle Id
5、将该文件发给后端,放到公司官网的根目录下。确实麻烦,这步搞完就大功告成了。
四、总结
1、支付宝支付需要向SDK传入sign字符串,而危险则是传微信参数对象,大致相同。
2、要和后端做好订单支付的确认操作,一般在客户端收到支付成功的回调之后要再去调用一个确认订单状态的接口,来确保支付的正常完成。
3、更多的事情下次再说吧
参考文档链接:
https://www.cnblogs.com/guoshaobin/p/11164000.html