開(kāi)篇吐槽,文檔看不懂,文檔看不懂,文檔看不懂.重要的事說(shuō)三遍.
對(duì)于沒(méi)集成過(guò)支付寶SDK的人來(lái)說(shuō),官方文檔看完也是一臉懵逼,在網(wǎng)上搜完別人寫(xiě)的什么文檔流程,看完也是一臉懵逼.
官方demo運(yùn)行不了,還有各種什么order類(lèi)生成簽名,返回結(jié)果驗(yàn)簽巴拉巴拉,反正說(shuō)的我心累.
看一下支付寶給的流程圖
圖中的“商戶(hù)客戶(hù)端”其實(shí)就是我們的iOS客戶(hù)端需要做的事情:
1.用后臺(tái)給的簽名后訂單信息調(diào)用支付寶支付接口
2.處理支付寶返回的支付結(jié)果
完了,這就完事了,很簡(jiǎn)單的事情,只需要這兩步,官方文檔給的那么亂七八糟的復(fù)雜東西,什么order類(lèi)啥的,都是把后臺(tái)做的事情,放在了客戶(hù)端來(lái)做,所以才那么復(fù)雜.
那么為什么官方demo中能放在客戶(hù)端做的事情(簽名,驗(yàn)簽)要給后臺(tái)來(lái)做.
看下面官方給的提示:
第一條:私鑰要保存在服務(wù)端,那么決定了調(diào)用支付寶接口需要的簽名后的訂單信息(也就是參數(shù)payOrder)需要后臺(tái)來(lái)生成,傳給我們.
第二條:到底付款成沒(méi)成功,需要依賴(lài)服務(wù)端收到的異步通知結(jié)果來(lái)進(jìn)行判斷,我們客戶(hù)端這邊收到成功的提示也沒(méi)用,必須后臺(tái)告訴我們,他們也成功了,才算成功
第三條:說(shuō)到了難住大多數(shù)人的驗(yàn)簽,官方建議驗(yàn)簽規(guī)則參考異步通知驗(yàn)簽,而異步通知驗(yàn)簽,是在服務(wù)端來(lái)完成的,官方在服務(wù)端的SDK中提供了一個(gè)工具類(lèi)用來(lái)驗(yàn)簽,所以我們也是在服務(wù)端完成的.
了解以上就可以集成支付寶SDK了
這里是官方支付寶SDK集成流程
這里是創(chuàng)建應(yīng)用獲取APPID和配置秘鑰的方法
設(shè)置URL Scheme(要記住這個(gè)標(biāo)識(shí),調(diào)用支付寶方法時(shí)會(huì)用到這個(gè)參數(shù))
修改 info.plist 文件 URL types 項(xiàng)中后面的URL Schemes內(nèi)容,官方建議跟商戶(hù)的app有一定的標(biāo)示度,要做到和其他的商戶(hù)app不重復(fù)泄鹏,否則可能會(huì)導(dǎo)致支付寶返回的結(jié)果無(wú)法正確跳回商戶(hù)app秧耗。(比如你們項(xiàng)目名稱(chēng)+AliPay,我這里設(shè)置了支付寶,qq,微信,微博,只用到支付寶的話(huà),就添加支付寶的就ok)
添加依賴(lài)庫(kù)
把下載的SDK中AlipaySDK.bundle和AlipaySDK.framework拖入工程,然后按官方給的圖添加依賴(lài)庫(kù).官方文檔看到這張圖這里就夠了,其余以下的不用管,都是教你demo怎么運(yùn)行,簽名和驗(yàn)簽也沒(méi)我們客戶(hù)端的事,看他demo干嘛.
設(shè)置頭文件路徑
點(diǎn)擊“Build Settings”選項(xiàng)卡,在搜索框中车猬,以關(guān)鍵字“search”搜索,對(duì)“Header Search Paths”增加頭文件路徑:$(SRCROOT)/項(xiàng)目名稱(chēng)惜浅。如果頭文件信息已增加伏嗜,可不必再增加.
添加URL Schemes白名單
在“Info.plist”中增加一個(gè)LSApplicationQueriesSchemes值,設(shè)置為array, 添加支付寶需要的item:
alipay
也就是圖中的最后一項(xiàng),其他的都是微信微博和QQ的.
設(shè)置https訪(fǎng)問(wèn)
在“Info.plist”中增加一個(gè)App Transport Security Settings值, 其中有一個(gè)Allow Arbitrary Loads對(duì)應(yīng)的值要設(shè)置為YES
然后就就可以愉快的寫(xiě)代碼了
創(chuàng)建了一個(gè)繼承于NSObject的 HHAliPaySDK工具類(lèi),我在其中封裝了一下向后臺(tái)請(qǐng)求簽名后的訂單信息(也就是payOrder)的方法和處理回調(diào)結(jié)果用到的方法.
ps:這個(gè)類(lèi)中有網(wǎng)絡(luò)請(qǐng)求,HHttpManager是我自己對(duì)AFNetworking3.0的二次封裝,感興趣的可以看一看,不感興趣的同學(xué)可以用AFN或者自己的網(wǎng)絡(luò)框架.
.h文件
#import <Foundation/Foundation.h>
@interface HHAliPaySDK : NSObject
/**
根據(jù)訂單信息向后臺(tái)申請(qǐng)prepayId以調(diào)用支付寶支付接口
@param amount 金額
@param orderId 訂單信息(支付前請(qǐng)求后臺(tái)給的沒(méi)有簽名過(guò)的訂單號(hào))
*/
+ (void)sendAliPayRequestWithAmount:(NSString *)amount
orderId:(NSString *)orderId;
/**
openURL
*/
+(BOOL)handleOpenURL:(NSURL *)url;
@end
.m文件
#import "HHAliPaySDK.h"
#import <AlipaySDK/AlipaySDK.h>
@implementation HHAliPaySDK
//post請(qǐng)求后臺(tái),獲取簽名后的訂單信息(也就是payOrder)
+ (void)sendAliPayRequestWithAmount:(NSString *)amount
orderId:(NSString *)orderId{
NSDictionary *paramDict = @{
@"totalAmount":amount,
@"orderId":orderId,
};
//getAliPayOrder:后臺(tái)提供的接口,用來(lái)請(qǐng)求簽名后的訂單信息(也就是payOrder)
[HHttpManager POST:getAliPayOrder parameters:paramDict success:^(id responseObject) {
NSNumber *state = responseObject[@"state"];
if (state.integerValue == 0) {
NSString *orderStr = responseObject[@"data"][0][@"AlipaySign"];
[self sendPayRequstWithPayOrder:orderStr];
}else{
NSLog(@"請(qǐng)求失敗--%@",responseObject[@"msg"]);
}
} failure:^(NSError * error) {
NSLog(@"請(qǐng)求失敗--%@",error);
}];
}
//調(diào)用支付寶支付(無(wú)支付寶客戶(hù)端時(shí)的結(jié)果回調(diào)也在此方法中)
+ (void)sendPayRequstWithPayOrder:(NSString *)payOrder{
NSLog(@"%@", payOrder);
//AliPay_Scheme:設(shè)置URL Scheme時(shí)讓你記住的參數(shù).
[[AlipaySDK defaultService] payOrder:payOrder fromScheme:AliPay_Scheme callback:^(NSDictionary *resultDic) {
NSLog(@"%@", resultDic);
[self handleAliPayCallBackResultWithDictionary:resultDic];
}];
}
/**
openURL(有支付寶客戶(hù)端時(shí)返回的結(jié)果)
*/
+(BOOL)handleOpenURL:(NSURL *)url{
if ([url.host isEqualToString:@"safepay"] ) {
[[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
[self handleAliPayCallBackResultWithDictionary:resultDic];
}];
}
if ([url.host isEqualToString:@"platformapi"]){
[[AlipaySDK defaultService] processAuthResult:url standbyCallback:^(NSDictionary *resultDic) {
[self handleAliPayCallBackResultWithDictionary:resultDic];
}];
}
return YES;
}
+ (void)handleAliPayCallBackResultWithDictionary:(NSDictionary *)resultDic{
if ([resultDic[@"resultStatus"] isEqual:@"9000"])
{
//客戶(hù)端支付成功,然后向后臺(tái)請(qǐng)求,看他是否驗(yàn)簽成功,他也成功了,才證明支付成功,
}
if ([resultDic[@"resultStatus"] isEqual:@"4000"])
{
//支付失敗
}
if ([resultDic[@"resultStatus"] isEqual:@"6001"])
{
//取消支付
}
if ([resultDic[@"resultStatus"] isEqual:@"6002"])
{
//網(wǎng)絡(luò)連接失敗
}
}
@end
設(shè)置(個(gè)人喜歡類(lèi)方法,調(diào)用方便,可自己修改)
在AppDelegate.m文件中
openURL方法中設(shè)置回調(diào),支付寶不用初始化,是不是很開(kāi)森0.0(這里一個(gè)是iOS9以下的系統(tǒng)調(diào)用的系統(tǒng)方法和一個(gè)是iOS9以上的系統(tǒng)調(diào)用的系統(tǒng)方法,都要設(shè)置)
#pragma mark - OpenURL回調(diào)結(jié)果
//iOS9-
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
[self handleOpenURLWithURLHost:url];
return YES;
}
//iOS9和9+
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options{
[self handleOpenURLWithURLHost:url];
return YES;
}
- (void)handleOpenURLWithURLHost:(NSURL *)url{
NSLog(@"url.host:%@", url.host);
//支付寶
if ([url.host isEqualToString:@"safepay"]||[url.host isEqualToString:@"platformapi"]) {
[HHAliPaySDK handleOpenURL:url];
}
}
調(diào)用
類(lèi)方法直接調(diào)用封裝好的接口就行,orderId是需要向后臺(tái)請(qǐng)求的訂單號(hào)(比如:D123457890)
/**
根據(jù)訂單信息向后臺(tái)申請(qǐng)prepayId以調(diào)用支付寶支付接口
@param amount 金額
@param orderId 訂單信息(支付前請(qǐng)求后臺(tái)給的沒(méi)有簽名過(guò)的訂單號(hào))
*/
+ (void)sendAliPayRequestWithAmount:(NSString *)amount
orderId:(NSString *)orderId;
客戶(hù)端題外話(huà),關(guān)于RSA
(上面引入的是阮一峰寫(xiě)的一篇RSA算法原理,都是專(zhuān)業(yè)數(shù)學(xué)知識(shí),看的我一愣一愣的,感謝大大的講解)
簽名和驗(yàn)簽都交給后臺(tái)的來(lái)做,對(duì)我們客戶(hù)端來(lái)說(shuō),既安全有方便(真不是我們客戶(hù)端不做,是官方建議的,上面我有說(shuō)明過(guò),涉及錢(qián)的問(wèn)題,一切為了安全),客戶(hù)端這邊是不需要了解RSA加密解密的(沒(méi)錯(cuò),反正我是不會(huì)),但是需要后臺(tái)了解,最簡(jiǎn)單來(lái)說(shuō),在生產(chǎn)訂單時(shí),需要使用私鑰生成簽名,在處理返回的支付結(jié)果時(shí),需要使用公鑰驗(yàn)證返回結(jié)果是否被篡改.驗(yàn)證通過(guò)才算支付成功.具體后臺(tái)怎么驗(yàn)簽,支付寶提供了方法,他給服務(wù)端的SDK提供了一個(gè)工具類(lèi)用來(lái)驗(yàn)簽,官方舉的例子是Java
Map<String, String> paramsMap = ... //將異步通知中收到的待驗(yàn)證所有參數(shù)都存放到map中
boolean signVerified = AlipaySignature.rsaCheckV1(paramsMap, ALIPAY_PUBLIC_KEY, CHARSET) //調(diào)用SDK驗(yàn)證簽名
if(signVerfied){
// TODO 驗(yàn)簽成功后
//按照支付結(jié)果異步通知中的描述八酒,對(duì)支付結(jié)果中的業(yè)務(wù)內(nèi)容進(jìn)行1\2\3\4二次校驗(yàn),校驗(yàn)成功后在response中返回success羞迷,校驗(yàn)失敗返回failure
}else{
// TODO 驗(yàn)簽失敗則記錄異常日志,并在response中返回failure.
}