1. 程式人生 > >iOS端移動支付的一些坑

iOS端移動支付的一些坑

已經很久沒有寫部落格了,最近剛好工作比較輕鬆,希望能重新撿起來。

那麼來簡單說一下在iOS上做支付的一些東西 ( ̄▽ ̄*) 這裡主要說支付寶和微信這樣的第三方支付,像iOS本身的支付不做探究,話說,這個30%的過路費。。。簡直不人道啊。。。。

  • 簡單介紹
  • 支付寶SDK接入
  • 微信支付接入

簡單介紹

移動支付在iOS中主要指使用支付寶或則微信支付(調起app進行支付),那麼期間整體的流程應該是這樣的:

iOS發起訂單生成請求 -> 伺服器生成訂單資訊 -> iOS端根據訂單資訊呼叫第三方支付的SDK -> 等待第三方SDK喚起app執行回撥 -> 回撥裡獲取支付的結果(支付成功/失敗) -> 與伺服器進行校驗,確定交易是否成功(有可能支付成功了,但是交易失敗)

流程確定好了,在最開始生成訂單資訊的時候,因為支付寶跟微信支付所需要的訂單資訊完全不同,當然,如果做銀聯支付或者內購功能的話,所需生成的訂單資訊也是完全不同的,畢竟是不同的第三方提供的SDK麼ㄟ( ▔ —— ▔ )ㄏ

所以支付寶跟微信我接下來分開聊

支付寶SDK接入

iOS整合支付寶,其實在眾多的第三方SDK中,支付寶的開發文件是真的很良心的,基本只要跟著開發文件走就能做完整個支付模組,開發文件要去螞蟻金服裡面找,這裡給一下URL地址:支付寶開發文件

在這裡我簡單歸納一下下,就是在你需要進行支付的時候,支付模組需要訪問一個API介面來獲取訂單資訊,具體到支付寶所需要的訂單資訊有:

  1. appid :這個是申請的時候獲取的,是支付模組的一個常量
  2. privateKey :跟appid一樣,也是申請的時候拿到的,這個比較長,是一大串字元,注重安全的話,這些應該放到伺服器上,然後做加密
  3. notify_url :這是一個坑(敲黑板),因為不寫也可以走完支付的流程,但是支付成功之後你的服務端不會受到回撥,也就是說付了錢,但是沒有通知你的伺服器說使用者付錢啦.
  4. timestamp :時間戳,當前時間點,這個跟著demo走就行,沒下demo的話就去看看開發文件的吧,要求yyyy-MM-dd HH:mm:ss這樣的formatter
  5. version :這個是寫好的1.0
  6. sign_type :RSA,這個指的是RSA簽名規範,跟著demo走就好
  7. 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訪問,校驗交易結果
}

那麼第三方支付這塊就聊到這裡吧。