天天看點

iOS 微信支付內建

1. 準備

微信平台分為微信公衆平台和微信開放平台,公衆平台是營運微信公衆号的管理系統,開放平台主要針對app、網站開發,提供登入、分享、支付等功能。

注冊開放平台之後,建立應用,填寫應用資訊(Android、iOS等資訊),建立之後需要等待稽核(這個稽核很快的,幾個小時就通過了)。

然後是為該應用申請支付功能,要注意個人是無法申請的,具體可參考微信支付申請條件和資格。這裡牽涉到一系列公司資質的稽核和費用支付,需要幾個工作日的時間

完成之後可以擷取到appid(微信開放平台為應用生成的唯一識别碼)、商戶id、商戶secretKey。對于app端來說隻用到appid,商戶id最好通過接口從server擷取,商戶secretKey是用來簽名的,一般隻有server能用到。

2. 支付流程

先上一個開放平台給出的流程圖:

iOS 微信支付內建

支付流程.png

這個圖很實用很詳細很清晰,但一開始看可能會覺得複雜。其實對開發者來說,比較關心的流程是:

app向server發起支付請求

server收到請求後向微信背景調用統一下單API,獲得預付單資訊

server生成帶簽名的用戶端支付資訊并傳回給app

使用者确認支付,app調起微信用戶端進行支付

app獲得支付結果後向server查詢最終結果并顯示

流程了解之後,了解下需要定義的接口和前後端的具體工作:

新接口:

app向server發起請求,獲得簽名後的app支付資訊

app支付之後向server查詢支付結果(微信回調的結果不可信,必須以server的結果為準)

app需要做的:

項目接入微信支付sdk

向server請求支付資訊

用支付資訊調起微信用戶端,然後支付

收到微信回調之後向server查詢支付結果

根據支付結果展示頁面

server需要做的:

收到app端支付請求後調用統一下單API向微信背景擷取預支付資訊

将app端需要的支付資訊簽名之後傳回給app

接收微信背景回調資訊(支付結果),以供app查詢

3. iOS開發

開發文檔:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_1

下載下傳并運作demo

其實把demo看明白了,直接運用到自己的app裡,也不是不可以的

設定項目

在Xcode中,projectName-->Info-->URL Types 添加appid。設定之後才能實作應用間跳轉

iOS 微信支付內建

urltypes.png

導入sdk

iOS 微信支付內建

sdk.png

如果使用了pod,直接在Podfile中添加pod 'WechatOpenSDK' 然後執行 pod update即可。如果沒有使用pod,在添加了sdk檔案包之後,需要在pojectName-->General-->Linked Frameworks and Libraries 中添加相應内容

iOS 微信支付內建

libs.png

代碼

AppDelegate.m

didFinishLaunchingWithOptions方法中

[WXApi registerApp:@"wx000999888777"];//注冊appid

openUrl、handleOpenURL方法

- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url {

return[WXApi handleOpenURL:url delegate:[PaymentManager sharedManager]];}

- (BOOL)application:(UIApplication*)application openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation {

return[WXApi handleOpenURL:url delegate:[PaymentManager sharedManager]];

}

//NOTE:9.0以後使用新API接口

- (BOOL)application:(UIApplication*)app openURL:(NSURL*)url options:(NSDictionary *)options{

return[WXApi handleOpenURL:url delegate:[PaymentManager sharedManager]];

}

如果之前項目中使用了友盟等第三方架構,直接并排寫就可以:

- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url{    [WXApi handleOpenURL:url delegate:[PaymentAction sharedPayment]];    [UMSocialSnsService handleOpenURL:url];returnYES;}

另外,這個地方的delegate也可以直接設定成nil,表示用目前AppDelegate作為微信支付的代理,這樣一來支付回調寫在AppDelegate.m中即可。

但不推薦這種做法,我是設定了PaymentManager作為代理,這是項目中專門管理支付的一個類,包括之前的支付寶支付。這也是微信demo中的做法。(支付寶是用block擷取回調的,個人感覺代碼更緊湊,不容易亂;微信是用的代理,剛開始看暈乎乎的)

PaymentManager

首先是遵守協定WXApiDelegate

然後在PayVC中通過接口擷取支付資訊

然後調起微信用戶端:

- (void)weiXinPayWithDic:(NSDictionary *)wechatPayDic {   

     PayReq *req = [[PayReq alloc] init];   

     req.openID = [wechatPayDic objectForKey:@"appId"];   

     req.partnerId = [wechatPayDic objectForKey:@"partnerId"];  

      req.prepayId = [wechatPayDic objectForKey:@"prepayId"];  

      req.package= [wechatPayDic objectForKey:@"packages"];   

     req.nonceStr = [wechatPayDic objectForKey:@"nonceStr"];   

     req.timeStamp = [[wechatPayDic objectForKey:@"timesTamp"] intValue];

       req.sign = [wechatPayDic objectForKey:@"sign"];  

      [WXApi sendReq:req];

}

這裡的資料wechatPayDic一定是server經過二次簽名的

回調

// 微信支付傳回結果回調

- (void)onResp:(BaseResp *)resp {if([resp isKindOfClass:[PayRespclass]]) {   

             PayResp *response = (PayResp *)resp;

if(_delegate && [_delegate respondsToSelector:@selector(managerDidRecvPaymentResponse:)]) {    

        [_delegate managerDidRecvPaymentResponse:response];      

  }  

  }}

當然前提是在PaymentManager.h中已經定義了代理:

@[email protected]

- (void)managerDidRecvPaymentResponse:(PayResp *)response;@[email protected]:[email protected](nonatomic,assign)id delegate;

這個代理是用來處理回調結果,展示頁面的,是以設定成PayVC控制器

處理回調結果

PayVC.m

遵守協定WXApiManagerDelegate

在viewDidLoad中設定[PaymentManager sharedManager].delegate = self;

- (void)managerDidRecvPaymentResponse:(PayResp *)response {switch(response.errCode) {

caseWXSuccess:                [selfcheckWechatPayResult];break;caseWXErrCodeUserCancel:          

      [[HintManager shareManager] showHint:@"中途取消"];break;default:{        

        [[HintManager shareManager]showHint:@"支付失敗"];       

     }break;     

   }}

然後在checkWechatPayResult向server查詢支付結果,重新整理頁面

哦了~~ 潑佛客特

4. 出現的問題

當然了,并不潑佛客特

系統版本大于等于iOS9的,調起微信用戶端之後,可以直接點選狀态欄左側按鈕傳回,這時是不走回調方法的。

這樣在支付成功之後,不走回調方法,就無法知道支付狀态,目前頁面無法給出提示。

解決方案是,在AppDelegate.m的applicationWillEnterForeground方法中,調用查詢支付結果接口然後重新整理當然頁面。需要設定bool變量作為标志,否則每次應用進入前台都去查詢,就不符合業務要求了。

進入微信支付頁面之後,不做操作,切換到自己應用中,退出目前支付頁面,然後再進入微信用戶端點選支付或者取消,此時自己的應用會崩潰閃退

原因是退出頁面後頁面已經出棧被銷毀,但wx回調時還是去調用其中的代理方法,就會出現野指針。

解決方法是,在頁面的viewWillDisappear方法中加入[PaymentManager sharedManager].delegate = nil;。

5. 需要注意的點

一定設定好scheme,否則應用無法跳轉

在調起微信支付使用的PayReq類,一定要用WXApi中自帶的類,不要自己建立新類。我之前自己建立的類,定義了同樣的變量,同樣繼承了BaseReq,然并卵,sendReq方法一直傳回false

調起微信支付的資料,一定是server經過二次簽名的,不要把調用統一下單API擷取到的資料直接返給app

雖然類中的變量命名是駝峰式,但簽名時的key值全部是小寫的,簽名時不要忘了後面加上商戶key。

6. 簽名

可能某些server端由于這樣那樣的原因不願意做二次簽名,app可以自己做。(不過因為簽名需要用到secretKey,讓app端做簽名是有風險的)

下面是簽名代碼:

iOS 微信支付內建
iOS 微信支付內建

個人建議像微信支付、支付寶支付最後都由背景完成,送出相應的資料給背景,讓背景生成訂單并傳回以下參數就可以了,這樣微信就會異步通知背景  支付完成後傳回APP  由APP直接向背景請求訂單支付成功了沒有, 這樣可以保證支付不會出現一些小問題  

iOS 微信支付內建