一、前言
最近項目需求需要集成支付寶和微信支付,以前沒有接觸過,這次正好乘着這次機會了解下。
總的來說,客戶端的工作不多,無非就是就是集成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: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