iOS端移動支付的一些坑
已經很久沒有寫部落格了,最近剛好工作比較輕鬆,希望能重新撿起來。
那麼來簡單說一下在iOS上做支付的一些東西 ( ̄▽ ̄*) 這裡主要說支付寶和微信這樣的第三方支付,像iOS本身的支付不做探究,話說,這個30%的過路費。。。簡直不人道啊。。。。
- 簡單介紹
- 支付寶SDK接入
- 微信支付接入
簡單介紹
移動支付在iOS中主要指使用支付寶或則微信支付(調起app進行支付),那麼期間整體的流程應該是這樣的:
iOS發起訂單生成請求 -> 伺服器生成訂單資訊 -> iOS端根據訂單資訊呼叫第三方支付的SDK -> 等待第三方SDK喚起app執行回撥 -> 回撥裡獲取支付的結果(支付成功/失敗) -> 與伺服器進行校驗,確定交易是否成功(有可能支付成功了,但是交易失敗)
流程確定好了,在最開始生成訂單資訊的時候,因為支付寶跟微信支付所需要的訂單資訊完全不同,當然,如果做銀聯支付或者內購功能的話,所需生成的訂單資訊也是完全不同的,畢竟是不同的第三方提供的SDK麼ㄟ( ▔ —— ▔ )ㄏ
所以支付寶跟微信我接下來分開聊
支付寶SDK接入
iOS整合支付寶,其實在眾多的第三方SDK中,支付寶的開發文件是真的很良心的,基本只要跟著開發文件走就能做完整個支付模組,開發文件要去螞蟻金服裡面找,這裡給一下URL地址:支付寶開發文件
在這裡我簡單歸納一下下,就是在你需要進行支付的時候,支付模組需要訪問一個API介面來獲取訂單資訊,具體到支付寶所需要的訂單資訊有:
- appid :這個是申請的時候獲取的,是支付模組的一個常量
- privateKey :跟appid一樣,也是申請的時候拿到的,這個比較長,是一大串字元,注重安全的話,這些應該放到伺服器上,然後做加密
- notify_url :這是一個坑(敲黑板),因為不寫也可以走完支付的流程,但是支付成功之後你的服務端不會受到回撥,也就是說付了錢,但是沒有通知你的伺服器說使用者付錢啦.
- timestamp :時間戳,當前時間點,這個跟著demo走就行,沒下demo的話就去看看開發文件的吧,要求yyyy-MM-dd HH:mm:ss這樣的formatter
- version :這個是寫好的1.0
- sign_type :RSA,這個指的是RSA簽名規範,跟著demo走就好
- biz_content:商品的資料(這個是一個單獨的類,而不是像上面的是一些NSString)
特別指出商品資料應該怎麼來構建
// NOTE: 商品資料
order.biz_content = [BizContent new];
order.biz_content.body = @"我是測試資料";
order.biz_content.subject = @"1";
order.biz_content.out_trade_no = [self generateTradeNO]; //訂單ID(由商家自行制定)
order.biz_content.timeout_express = @"30m"; //超時時間設定
order.biz_content.total_amount = [NSString stringWithFormat:@"%.2f", 0.01]; //商品價格
到這裡其實訂單的資料就已經準備好了,接下來做的是加密部分,加密完就可以調起支付寶SDK了
//將商品資訊拼接成字串
NSString *orderInfo = [order orderInfoEncoded:NO];
NSString *orderInfoEncoded = [order orderInfoEncoded:YES];
// NOTE: 獲取私鑰並將商戶資訊簽名,外部商戶的加簽過程請務必放在服務端,防止公私鑰資料洩露;
// 需要遵循RSA簽名規範,並將簽名字串base64編碼和UrlEncode
id<DataSigner> signer = CreateRSADataSigner(privateKey);
NSString *signedString = [signer signString:orderInfo];
從上面的程式碼可以看到,加密之後字串(orderInfoEncoded)與未加密的(orderInfo)是下面調起支付寶SDK要用到的,而signer只是用來判斷是否訂單資訊是不是已經正確填寫了if (signedString != nil)
//應用註冊scheme,在AliSDKDemo-Info.plist定義URL types
NSString *appScheme = @"alisdkdemo";
// NOTE: 將簽名成功字串格式化為訂單字串,請嚴格按照該格式
NSString *orderString = [NSString stringWithFormat:@"%@&sign=%@",
orderInfoEncoded, signedString];
// NOTE: 呼叫支付結果開始支付
[[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
NSLog(@"reslut = %@",resultDic);
}];
上面程式碼塊中的appScheme就是你app的scheme,當正確設定的時候,使用Safari開啟網址scheme://
會開啟你的app,這裡填寫時為了在支付之後重新喚醒你的app.
呼叫SDK的callback回撥block在支付寶回撥你的app時並不會執行,app的回撥我們接下來講,這裡的回撥block會在當用戶的iPhone並沒有安裝支付寶的時候,也就是支付寶SDK調起網頁進行支付,不論使用者直接返回還是正常進行支付流程,
當返回的時候會執行這個block裡面的程式碼.
支付寶app的回撥會執行AppDelgate的下面兩個方法
//(iOS版本不同執行不同方法,iOS9以上會執行第一個方法....)
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation;
//iOS8呼叫這個方法
-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options;
但是兩者的返回處理是一致的,返回方法引數裡面url可以用來識別是不是支付寶調起的返回
if ([url.host isEqualToString:@"safepay"]){
//是支付寶調起的返回,處理返回結果
[[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
NSLog(@"result = %@",resultDic);
}];
}
那麼iOS整合支付寶就說到這裡.
微信支付接入
相對於支付寶專門做的支付SDK,微信支付是從屬於微信SDK的一個功能模組,與微信SDK的互動其實跟使用微信SDK來做分享是一樣一樣的,都是使用了‘[WXApi sendReq:req];’這個方法。
但是跟微信分享不一樣的地方在於,傳入的req不再是SendMessageToWXReq了,而是PayReq了,當然PayReq也是繼續至BaseReq的,照著開發文件來就好,這個如果是在已經有微信分享功能的app裡面新增,甚至看看SDK程式碼和註釋就好,根本用不著仔細看開發文件ㄟ( ▔, ▔ )ㄏ 。
下面來看看PayReq要怎麼構造
PayReq* req = [[PayReq alloc] init];
req.partnerId = [data objectForKey:@"partnerid"];
req.prepayId = [data objectForKey:@"prepayid"];
req.nonceStr = [data objectForKey:@"noncestr"];
req.timeStamp = [[data objectForKey:@"timestamp"] intValue];
req.package = [data objectForKey:@"package"];
req.sign = [data objectForKey:@"sign"];
跟支付寶不一樣,微信支付的訂單生成是服務端去做的(支付寶實際上服務端是生成訂單資訊,然後由支付寶的SDK呼叫來進行訂單生成),所以在支付訂單資訊裡面的timeStamp需要服務端生成訂單時候的時間戳,而不是手機系統的時間戳。
構建好了request之後,呼叫WXApi來發送
[WXApi sendReq:req];
接下來說說回撥
跟支付寶的回到類似,微信SDK通過微信app喚起你的app,來進行回撥,所以入口同樣是下面的兩個
//(iOS版本不同執行不同方法,iOS9以上會執行第一個方法....)
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation;
//iOS8呼叫這個方法
-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options;
而分辨方法在於:傳參的url裡面,微信的回撥會返回你申請時候獲取的APPID
/*** 微信回撥(支付、登入、分享) ***/
//if is has prefix wx
if ([url.absoluteString hasPrefix:@"你的微信appId"]) {
return[WXApi handleOpenURL:url delegate:self];
}
從上面的程式碼塊可以看到,其實微信的支付、登入和分享都會共享回撥,而分辨則是通過delegate來實現的,也就是說上面的程式碼塊[WXApi handleOpenURL:url delegate:self];
,你傳入的delegate必須實現WXApiDelegate協議。
最重要的是實現下面的方法
/*! @brief 傳送一個sendReq後,收到微信的迴應
*
* 收到一個來自微信的處理結果。呼叫一次sendReq後會收到onResp。
* 可能收到的處理結果有SendMessageToWXResp、SendAuthResp等。
* @param resp具體的迴應內容,是自動釋放的
*/
-(void) onResp:(BaseResp*)resp;
其中,可以通過resp的型別判斷來識別是什麼操作的回撥
if([resp isKindOfClass:[PayResp class]]){
//支付成功!
//這裡只返回支付過程是否成功,但支付過後,可能會出現別的原因,導致交易失敗,但是支付過程是成功的...
if (resp.errCode == 0) {
}
else {
}
//這裡應該拿著支付結果再進行API訪問,校驗交易結果
}
那麼第三方支付這塊就聊到這裡吧。