1. 程式人生 > >支付寶、微信、銀聯移動支付整合

支付寶、微信、銀聯移動支付整合

一、支付寶移動支付

業務流程:

這裡寫圖片描述

SDK整合:

解壓介面壓縮檔案(檔名是 WS_MOBILE_PAY_SDK_BASE.zip),找到 IOS 的壓縮檔案(檔名是支付寶移動支付 SDK 標準版(iOS).zip)。

  1. 匯入程式碼

步驟1: 啟動IOS開發軟體(如Xcode),把IOS的壓縮檔案中以下檔案拷貝到專案資料夾下,並匯入到開發環境中。

AlipaySDK.bundle
AlipaySDK.framework

步驟2: 在需要使用SDK的檔案中,增加標頭檔案引用。

#import <AlipaySDK/AlipaySDK.h>

步驟3: 配置請求資訊。

Order *order = [[Order alloc] init];
order.partner = partner;
order.seller = seller;
order.tradeNO = [self generateTradeNO]; //訂單ID(由商家自行制定) 
order.productName = product.subject; //商品標題 order.productDescription = product.body; //商品描述
order.amount = [NSString stringWithFormat:@"%.2f",product.price]; //商 品價格
order.notifyURL = @"http://www.xxx.com"; //回撥URL order.service = @"mobile.securitypay.pay"; order.paymentType = @"1"; order.inputCharset = @"utf-8"; order.itBPay = @"30m"; //應用註冊scheme,在AlixPayDemo-Info.plist定義URL types NSString *appScheme = @"alisdkdemo"; //將商品資訊拼接成字串 NSString *orderSpec = [order description]; NSLog
(@"orderSpec = %@",orderSpec); //獲取私鑰並將商戶資訊簽名,外部商戶可以根據情況存放私鑰和簽名,只需要遵循 RSA 簽名規範, 並將簽名字串 base64 編碼和 UrlEncode id<DataSigner> signer = CreateRSADataSigner(privateKey); NSString *signedString = [signer signString:orderSpec]; //將簽名成功字串格式化為訂單字串,請嚴格按照該格式 NSString *orderString = nil; if (signedString != nil) { orderString = [NSString stringWithFormat:@"%@&sign=\"%@\"&sign_type=\"%@\"", orderSpec, signedString, @"RSA"]; [[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) { NSLog(@"reslut = %@",resultDic); }]; [tableView deselectRowAtIndexPath:indexPath animated:YES]; }

詳細可參見示例檔案

  • AliSDKDemo\APViewController.h
  • AliSDKDemo\APViewController.m
  • AliSDKDemo\Order.h
  • A liSDKDemo\Order.m

步驟4: 配置返回處理程式碼
在 AliSDKDemo\APAppDelegate.m 檔案中,增加引用程式碼:

#import <AlipaySDK/AlipaySDK.h>

在@implementation AppDelegate 中增加如下程式碼:

 1. (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
//如果極簡 SDK 不可用,會跳轉支付寶錢包進行支付,需要將支付寶錢包的支付結果回傳給 SDK 
if ([url.host isEqualToString:@"safepay"]) {
[[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
          NSLog(@"result = %@",resultDic);
       }];
}
if ([url.host isEqualToString:@"platformapi"]){//支付寶錢包快登授權返回 authCode
[[AlipaySDK defaultService] processAuthResult:url standbyCallback:^(NSDictionary *resultDic) {
          NSLog(@"result = %@",resultDic);
       }];
}
return YES; 
}
  1. 針對Demo的執行注意
    (1) 關於簽名程式碼問題
    AliSDKDemo\Util 及下面所有檔案
    AliSDKDemo\openssl 及下面所有檔案
    libcrypto.a
    libssl.a
    這些檔案是為客戶端簽名功能服務的,僅作為示例使用。商戶在接入支付寶產品時, 請使用商戶專案自己的服務端的簽名驗籤程式碼。
    (2) 點選專案名稱,點選“Build Settings”選項卡,在搜尋框中,以關鍵字“search” 搜尋,對“Framework Search Paths”、“Header Search Paths”、“Libraray Search Paths”增加標頭檔案路徑:$(SRCROOT)/專案名稱。如果標頭檔案資訊已增加,可不必再增加。
    (3) 點選專案名稱,點選“Build Phases”選項卡,在“Link Binary with Librarles” 選項中,新增“AlipaySDK.framework”和“SystemConfiguration.framework” 兩個系統庫檔案。如果商戶專案中已有這兩個庫檔案,可不必再增加。
    (4) 點選專案名稱,點選“Info”選項卡,在“URL Types”選項中,點選“+”, 在“URL Schemes”中輸入“alisdkdemo”,Schemes要於發起支付請求時設定的一致。
  2. 配置基本資訊
NSString *partner = @"";
NSString *seller = @"";
NSString *privateKey = @"";//商戶製作生成的PKCS8 編碼的私鑰

PS:
回撥後臺需要設定指定後臺的URL,支付完成後,支付寶伺服器會非同步呼叫該地址
order.notifyURL = @"http://www.xxx.com"; //回撥URL

關於privateKey私鑰,是需要商戶去生成金鑰(生成的pem公鑰最後需要上傳到支付寶,請檢視https://b.alipay.com/order/pidAndKey.htm )。
製作私鑰步驟:
1.開啟下載的SDK包,開啟 openssl 資料夾下的 bin 資料夾,執行 openssl.exe 檔案
2.生成RSA私鑰
輸入genrsa -out rsa_private_key.pem 1024命令,回車後,在當前 bin 檔案目 錄中會新增一個 rsa_private_key.pem 檔案,其檔案為原始的商戶私鑰(請妥善保 存該檔案,PHP 開發語言中需要使用該檔案)
3.生成RSA公鑰,通過私鑰生成公鑰,上傳到支付寶商戶中心。
輸入rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem命令回車 後,在當前 bin 檔案目錄中會新增一個 rsa_public_key.pem 檔案,其檔案為原始 的商戶公鑰(請妥善儲存該檔案,PHP 開發語言中需要使用該檔案)

4.生成PKCS8 編碼的私鑰
輸入命令pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt並回車,當前介面中會直接顯示出生成結果(很長的一串字串),
此時繼續右鍵點選 openssl 視窗上邊邊緣,選擇“編輯→複製”,把複製的內容粘 貼進一個新的記事本中,可隨意命名,只要知道這個是 PKCS8 格式的私鑰即可(請妥善儲存該檔案),改私鑰便是移動支付簽名需要用到的私鑰。

2分鐘快速整合支付寶支付

二、微信移動支付

業務流程:

這裡寫圖片描述

商戶系統和微信支付系統主要互動說明:
步驟1:使用者在商戶APP中選擇商品,提交訂單,選擇微信支付。
步驟2:商戶後臺收到使用者支付單,呼叫微信支付統一下單介面。參見【統一下單API】。
步驟3:統一下單介面返回正常的prepay_id,再按簽名規範重新生成簽名後,將資料傳輸給APP。參與簽名的欄位名為appId,partnerId,prepayId,nonceStr,timeStamp,package。注意:package的值格式為Sign=WXPay
步驟4:商戶APP調起微信支付。api參見本章節【app端開發步驟說明
步驟5:商戶後臺接收支付通知。api參見【支付結果通知API
步驟6:商戶後臺查詢支付結果。,api參見【查詢訂單API

SDK整合:

1.解壓SDK包,把裡面的libWeChatSDK.a,WXApi.h,WXApiObject.h匯入工程。
2.配置專案
(1)“Library Search Paths”增加庫檔案路徑:$(PROJECT_DIR)/SDKDir
(2)用XCode開啟專案,【專案屬性】-【Info】-【URL Schemes】設定微信開放平臺申請的應用APPID(如wxb4ba3c02aa476ea1)。如果這的APPID設定不正確將無法調起微信支付
參考檢視https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=8_5
(3)引人系統庫“libc++.tbd”“libz.tbd”“libsqlite3.0.tbd”“CoreTelephony.framework”“Security.framework”“SystemConfiguration.framework”(xcode7的靜態庫字尾名為tbd,舊版本為a)

3.發起支付

PayReq *request = [[[PayReq alloc] init] autorelease];
request.partnerId = @"10000100";//商家向財付通申請的商家id
request.prepayId= @"1101000000140415649af9fc314aa427";//預支付訂單
request.package = @"Sign=WXPay";//商家根據財付通文件填寫的資料和簽名
request.nonceStr= @"a462b76e7436e98e0ed6e13c64b4fd1c";//隨機串,防重發
request.timeStamp= @"1397527777";//時間戳,防重發
request.sign= @"582282D72DD2B03AD892830965F428CB16E7A256";//商家根據微信開放平臺文件對資料做的簽名
[WXApi sendReq:request];

PS:開發過程中,以上發起呼叫起支付的引數,包括預支付訂單這些,一般是先請求後臺,後臺通過微信統一API請求(包括APP請求支付後,微信支付系統回撥後臺的回撥地址也是在這裡由後臺設定好傳給支付系統)獲得預支付單號等資訊後返回給APP,返回時的內容請參考http://wxpay.weixin.qq.com/pub_v2/app/app_pay.php?plat=ios

4.支付結果回撥
實現onResp函式,支付完成後,微信APP會返回到商戶APP並回調onResp函式,開發者需要在該函式中接收通知,判斷返回錯誤碼,如果支付成功則去後臺查詢支付結果再展示使用者實際支付結果。注意 一定不能以客戶端返回作為使用者支付的結果,應以伺服器端的接收的支付通知或查詢API返回的結果為準

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
    return  [WXApi handleOpenURL:url delegate:self];
}

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    return [WXApi handleOpenURL:url delegate:self];
}

//實現委託
-(void)onResp:(BaseResp*)resp{
    if ([resp isKindOfClass:[PayResp class]]){
        PayResp*response=(PayResp*)resp;
        switch(response.errCode){
            case WXSuccess:
                //伺服器端查詢支付通知或查詢API返回的結果再提示成功
            {
                ALERT_SHOW(@"支付成功");
            }

                break;
            default:
            {
                NSLog(@"支付失敗,retcode=%d",resp.errCode);
                ALERT_SHOW(@"支付失敗");
            }
                break;
        }
    }
}

三、銀聯移動整合

SDK開放臺:

業務流程:

這裡寫圖片描述

SDK整合:

1.使用UPPaymentControl需要將paymentcontrol/inc目錄下UPPaymentControl.h檔案和paymentcontrol/libs目錄下的libPaymentControl.a檔案新增到商戶應用的工程中

2.配置專案
(1)“Library Search Paths”增加庫檔案路徑,將libPaymentControl.a目錄設定進去,如$(PROJECT_DIR)/SDKDir
(2)在工程info.plist設定中新增一個URL Types回撥協議(如工程中使用“UPPayDemo”),用於在支付完成後返回商戶客戶端。
(3)引人系統庫
CFNetwork.framework、SystemConfiguration.framework 、libz.a(tbd)
(4)選擇工程targets——》build settings ->Linking->other linker flags ,新增-ObjC

3.發起支付
tn為交易流水號,商戶App從商戶伺服器獲取tn,當tn不為空時,呼叫支付介面;
model 為環境引數,00表示正式環境,01表示開發環境;
scheme為info.plist設定中設定URL Types;
viewController為 發起呼叫的檢視控制器,商戶應用程式呼叫銀聯手機支付控制元件的檢視控制器;

//當獲得的tn不為空時,呼叫支付介面
  if (tn != nil && tn.length > 0)
  {
        [[UPPaymentControl defaultControl] 
                startPay:tn 
fromScheme:@"UPPayDemo" 
       mode:@"01" 
    viewController:self]; 
}

檢測是否已安裝銀聯App介面呼叫可使用:

if([[UPPaymentControl defaultControl] isPaymentAppInstalled])   
  {
      //當判斷使用者手機上已安裝銀聯App,商戶客戶端可以做相應個性化處理
}

4.返回結果介面呼叫
支付控制元件結果處理函式handlePaymentResult: completeBlock:需要在工程AppDelegate檔案的application: openURL: sourceApplication: annotation: 方法中進行呼叫。
支付控制元件結果處理函式handlePaymentResult: completeBlock:包含兩個引數,引數1url為支付結果串,由handlePaymentResult: completeBlock:方法解析url內容;引數2completionBlock為商戶APP定義的結果處理方法,包含兩個傳入引數code和data,其中code表示支付結果,取值為suceess,fail,cancel分別表示支付成功、支付失敗和支付取消,data表示結果簽名資料,商戶使用銀聯公鑰驗證結果真實性。

對於新增的簽名信息需注意以下幾點:

  • 前臺返回的支付結果中包含銀聯簽名,要在商戶後臺對簽名進行校驗後才能展示結果。
  • 前臺簽名使用的金鑰和演算法與後臺結果中的簽名一致。
  • 如果商戶APP在客戶端內進行簽名驗證,要自行實現簽名金鑰更新的機制,否則更換金鑰後會導致驗籤失敗。(不推薦)
  • 商戶訂單是否成功支付應該以商戶後臺收到全渠道返回的支付結果為準,此處支付控制元件返回的結果僅作為參考。
- (BOOL) application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
        [[UPPaymentControl defaultControl] handlePaymentResult:url completeBlock:^(NSString *code, NSDictionary *data) {

        //結果code為成功時,先校驗簽名,校驗成功後做後續處理
        if([code isEqualToString:@"success"]) {

            //資料從NSDictionary轉換為NSString
            NSDictionary *data;
            NSData *signData = [NSJSONSerialization dataWithJSONObject:data
                                                               options:0
                                                                 error:nil];
            NSString *sign = [[NSString alloc] initWithData:signData encoding:NSUTF8StringEncoding];

            //判斷簽名資料是否存在
            if(data == nil){
                //如果沒有簽名資料,建議商戶app後臺查詢交易結果
                return;
            }

            //驗簽證書同後臺驗簽證書
            //此處的verify,商戶需送去商戶後臺做驗籤
            if([self verify:sign]) {
                //支付成功且驗籤成功,展示支付成功提示
            }
            else {
                //驗籤失敗,交易結果資料被篡改,商戶app後臺查詢交易結果
            }
        }
        else if([code isEqualToString:@"fail"]) {
            //交易失敗
        }
        else if([code isEqualToString:@"cancel"]) {
            //交易取消
        }
    }];

  return YES;
}

completeBlock中的NSDictionary *data結構如下:

sign —— 簽名後做Base64的資料 
data —— 用於簽名的原始資料,結構如下:
     pay_result —— 支付結果success,fail,cancel
     tn          —— 訂單號

Data轉換為String後的示例如下:

"{"sign":"ZnZY4nqFGu/ugcXNIhniJh6UDVriWANlHtIDRzV9w120E6tUgpL9Z7jIFzWrSV73hmrkk8BZMXMc/9b8u3Ex1ugnZn0OZtWfMZk2I979dxp2MmOB+1N+Zxf8iHr7KNhf9xb+VZdEydn3Wc/xX/B4jncg0AwDJO/0pezhSZqdhSivTEoxq7KQTq2KaHJmNotPzBatWI5Ta7Ka2l/fKUv8zr6DGu3/5UaPqHhnUq1IwgxEWOYxGWQgtyTMo/tDIRx0OlXOm4iOEcnA9DWGT5hXTT3nONkRFuOSyqS5Rzc26gQE6boD+wkdUZTy55ns8cDCdaPajMrnuEByZCs70yvSgA==","data":"pay_result=success&tn=201512151321481233778"}"

5.常見問題總結
更多請參見https://open.unionpay.com幫助中心-FAQ
5.1 怎樣加-ObjC巨集
選擇工程targets——》build settings ->Linking->other linker flags

5.2 編譯時提示Undefined for architecture XXX 錯誤
1)由於支付控制元件使用到了C、C++和OC混編的情況,所以商戶工程引入UPPaymentControl.h標頭檔案以後可能會出現連結錯誤,這個時候可以通過以下三種方式解決:
① 將涉及到引用UPPaymentControl.h的原始檔的字尾名都改為.mm;
② 如果商戶不想修改原始檔的字尾名,可以在工程中新增一個空的繼承自NSObject的類,並將檔案.m字尾名該改為.mm即可方法為new file->Objective-C class->類名自取->儲存->修改後綴名為.mm;
③ 將工程的compile source as 選項的值設定為Objective–C++;
2)由於在UPPayDemo工程中添加了自定義的庫檔案libPaymentControl.a
,當編譯Demo工程時,應該檢查工程設定Search Paths裡的Framework Search Paths、Header Search Paths、Library Search Paths的路徑設定,看設定路徑是否正確,另外還要注意裡邊是否多餘一些不確定的路徑。
3) 將xcode工程中Build Setting -> Apple LLVM compiler Language 標籤下的C++ Language Dialect 和 C++ Standard Library 屬性值修改為 Compiler Default如實在無法解決,嘗試新增-ObjC巨集的地方修改為 -force_load+空格+控制元件路徑,如:-force_load $(PROJECT_DIR)/ libPaymentControl.a,如果還報錯,上下文應該會有libPaymentControl.a檔案找不到異常,比如ld: file not found: /Users/apple/Desktop/Communication 2/ libPaymentControl.a
clang: error: linker command failed with exit code 1 (use -v to see invocation)
請確定libPaymentControl.a檔案確實存在於此路徑,可能為上下文路徑配錯。

5.3 控制元件閃退異常’NSInvalidArgumentException’, reason: ‘-[__NSCFConstantString newSizeWithFont:詳略]’
‘NSInvalidArgumentException’, reason: ‘-[__NSCFConstantString newSizeWithFont:以下略]: unrecognized selector sent to instance 0x[隨機數]’
出現以上問題是由於新增-ObjC巨集的地方沒有配置正確,如果配-ObjC實在解決不了的話,可嘗試去掉-ObjC,改為-force_load+空格+控制元件路徑,如:-force_load $(PROJECT_DIR)/ libPaymentControl.a。

5.4 orientation異常
詳細現象為控制元件崩潰,報錯資訊:Terminating app due to uncaught exception ‘UIApplicationInvalidInterfaceOrientation’, reason: ‘Supported orientations has no common orientation with the application, and shouldAutorotate is returning YES’
請勿修改橫豎屏配置,iphone控制元件只能豎屏,ipad控制元件才支援橫豎屏。

關於iOS9適配問題

1.以iOS9 SDK編譯的工程會預設以SSL安全協議進行網路傳輸,即HTTPS,如果依然使用HTTP協議請求網路會報系統異常並中斷請求。可在info.plist的NSAppTransportSecurity下新增NSAllowsArbitraryLoads並設定為YES,指定所有HTTP連線都可正常請求

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

2.應用跳轉(SSO等)
如果你的應用使用瞭如SSO授權登入或跳轉分享功能,在iOS9下就需要增加一個可跳轉的白名單,指定對應跳轉App的URL Scheme,否則將在第三方平臺判斷是否跳轉時用到的canOpenURL時返回NO,進而只進行webview授權或授權/分享失敗。
同樣在info.plist增加:

<key>LSApplicationQueriesSchemes</key>
<array>
    <!-- 微信 URL Scheme 白名單-->
    <string>wechat</string>
    <string>weixin</string>

    <!-- 支付寶 白名單-->
    <string>alipayauth</string>
    <string>alipay</string>

    <!-- 銀聯 白名單-->
    <string>uppaysdk</string>
    <string>uppaywallet</string>
    <string>uppayx1</string>
    <string>uppayx2</string>
    <string>uppayx3</string>
</array>

3.應用瘦身(App Thining)
iOS9 SDK新增了對App瘦身的功能,詳情見App Thining。目前各個第三方平臺正在進行App thining的支援,所以為了正常使用第三方SDK及分享SDK,需要在Build Setting中將Enable bitcode關閉,或設定編譯標識ENABLE_BITCODE=NO。
注:bitcode僅在Xcode7以上顯示並預設開啟。