天天看點

iOS第三方支付內建——微信支付

       近期筆者開發的項目中,需要用到支付寶支付和微信支付。大概一個月前,支付寶就已經內建完畢并可以正常使用。但在內建坑爹的微信支付SDK時,遇到了諸多問題,搞了将近三個星期。期間不斷的跟背景同僚核對代碼(簽名、下單),支付流程,其中的血淚艱辛,不言而喻。現筆者把內建過程中遇到的一些問題記錄下來,供自己和大家參考。如果有什麼不對的地方,也請大家多多指正:

       吐槽完了,下面出正文。

       補充說明:第一準備階段不需要開發者負責操作,如果你是iOS開發人員,隻想找到調用微信支付的代碼,可直接跳過 第一準備階段。

       一、準備階段

       (1)筆者公司使用者是微信開放平台下開通的微信支付功能,網址:https://open.weixin.qq.com/?qq-pf-to=pcqq.c2c。網上大部分資料講的都是微信公衆平台下的微信支付內建,其實原理和代碼實作上大同小異。       

       (2)到微信開放平台的管理中心建立移動應用,待移動應用稽核通過以後,申請獲得微信支付能,這個流程走下來,大概需要 2 - 3 周。筆者建議提前到開放平台稽核為好。網址:https://open.weixin.qq.com/cgi-bin/applist?t=manage/list&lang=zh_CN&token=478d1d01575659fb7b53ee40d1f37c5cfc8689e5

       移動應用稽核通過後,擷取APP_ID和AppSecret,附上截圖:

iOS第三方支付內建——微信支付

       (3)等到移動應用稽核通過,獲得微信支付能力之後,進入微信商戶商戶平台。商戶平台的賬号和密碼,在公司賬号開通微信支付功能以後,财付通就會下發。微信商戶平台網址:https://pay.weixin.qq.com/index.php/home/login?return_url=/

       進入微信商戶平台後,擷取商戶号和商戶API密鑰。附上截圖:

iOS第三方支付內建——微信支付

       二、擷取微信支付IOS頭檔案和庫下載下傳及APP支付示例和解讀

       (1)進入網址https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=11_1,下載下傳微信支付APP支付示例。在APP支付示例中,已經包含了頭檔案和庫,是以不需要在下載下傳頭檔案和庫。

       (2)解壓檔案,會得到檔案名為:wechat_sdk_sample_ios_v3_pay的檔案夾。從名字可以知道,這是一份v3版本的代碼,目前v2版本的微信支付幾乎已經不用,新添加的微信支付SDK幾乎都是v3版本的。內建的時候,要明白這點,很重要。

       (3)檔案目錄及作用

       readme.txt:首次內建微信支付SDK時,讀讀沒壞處。

       設定appid.jpg:直接運作demo是無法調用微信用戶端的,需要按鈕圖檔的内容,設定 URL Schemes 和 APP_ID 才能運作。

       wechat_sdk_sample_ios_payV3:

       ~ lib:配置檔案,配置了微信支付所要設定的相關内容

       ~ SDKExport:微信支付頭檔案和庫檔案

       ~ SDKSample:項目功能實作代碼

       (4)代碼準備工作

       Xcode打開工程代碼,點選AppDelegate.m檔案,可以檢視到微信支付的實作代碼。

       ~[WXApi registerApp:APP_ID withDescription:@"demo 2.0"];向微信注冊,必寫代碼。

       ~ -(void) onReq:(BaseReq*)req:發送資訊給微信用戶端,請檢視微信支付demo具體代碼實作

       ~ -(void) onResp:(BaseResp*)resp:收到微信用戶端資訊的代理方法,請檢視微信支付demo具體代碼實作

       (5)調起微信支付

       重點來了!!!通過調試,我們可以知道,"微信支付測試簽名"、“微信支付demo”兩個按鈕,分别對應的是 

- (void)sendPay 和 - (void)sendPay_demo 兩個方法,那麼這兩個方法都做了什麼呢?什麼是簽名呢?

在解釋上面的問題前,有必要先解釋一下微信支付的簽名流程。

      微信支付demo和微信支付開發文檔多處提到以下幾點:

       ~ 背景伺服器做簽名、下單請求,從微信伺服器擷取到 預支付ID 和 sign 簽名等多個參數;

       ~ APP通過擷取背景傳回的參數(openID、partnerID商戶号、prepayID預支付ID、nonceStr随機字元串、timeStamp時間戳、package包、sign簽名),調用微信支付接口,就可以調用手機微信用戶端進行支付

       ~ 調用微信支付的代碼如下(核心代碼哦,我們所有的操作都是為了這段核心的參數做準備):

//調起微信支付
        PayReq* req             = [[[PayReq alloc] init]autorelease];
        req.openID              = [dict objectForKey:@"appid"];    
        req.partnerId           = [dict objectForKey:@"partnerid"];
        req.prepayId            = [dict objectForKey:@"prepayid"];
        req.nonceStr            = [dict objectForKey:@"noncestr"];
        req.timeStamp           = stamp.intValue;
        req.package             = [dict objectForKey:@"package"];
        req.sign                = [dict objectForKey:@"sign"];
        
        [WXApi sendReq:req];      

       根據上面的說明,童鞋們不知道明白了沒。其實所有的代碼,都是為了上面的核心作準備的,目的地就是為了擷取上面核心代碼的參數,已調用微信支付的接口。我們回到最初點:

       ~ - (void)sendPay:模拟簽名的過程。為了更好的安全性,關于微信支付的下單和簽名的過程,一般都是在背景完成,背景再把這些參數傳回到APP,APP再調用。這個方法卻是在APP端完成下單和簽名的操作,這其實隻是一個示範的過程“//本執行個體隻是示範簽名過程, 請将該過程在商戶伺服器上實作”

       ~ - (void)sendPay_demo:使用微信背景提供的參數,做支付示範。調用這個方法,控制台會列印出這樣一串東西:url:http://wxpay.weixin.qq.com/pub_v2/app/app_pay.php?plat=ios&order_no=1444376336&product_name=Ios%B7%FE%CE%F1%C6%F7%B6%CB%C7%A9%C3%FB%D6%A7%B8%B6%20%B2%E2%CA%D4&order_price=0.01。這串字元串中,包含了調用微信支付接口所需的所有的參數。核心代碼通過使用這些參數,就可以成功調用微信用戶端完成支付。

iOS第三方支付內建——微信支付

     微信支付提供的官方文檔:

     統一下單,擷取預支付ID:https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=9_1

     調起支付接口,調起手機微信用戶端:https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=9_12&index=2

     通過上面的描述,童鞋們明白了簽名、下單、調用微信支付調用的原理和代碼實作了沒?

     三、代碼實作微信支付

     通過上面的描述,我們可以得知一下幾點:

   (0)在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 函數中添加以下代碼://向微信注冊  [WXApi registerApp:APP_ID withDescription:@"demo 2.0"];

   (1)調用微信支付前,需要下單、簽名等操作,以便擷取微信支付所必要的參數。為了提高安全性,下單、簽名操作一般是在背景完成

   參數包括:appid、partid(商戶号)、prepayid(預支付訂單ID)、noncestr(參與簽名的随機字元串)、timestamp(參與簽名的時間戳)、sign(簽名字元串)

   (2)APP端擷取背景的參數資料,調用一下的核心代碼,調起微信支付

//調起微信支付
        PayReq* req             = [[[PayReq alloc] init]autorelease];
        req.openID              = [dict objectForKey:@"appid"];
        req.partnerId           = [dict objectForKey:@"partnerid"];
        req.prepayId            = [dict objectForKey:@"prepayid"];
        req.nonceStr            = [dict objectForKey:@"noncestr"];
        req.timeStamp           = stamp.intValue;
        req.package             = [dict objectForKey:@"package"];
        req.sign                = [dict objectForKey:@"sign"];
        
        [WXApi sendReq:req];      

   (3)筆者提供一段親測成功的核心代碼,示範如何背景擷取參數,調起微信支付:

    //請求網絡資料
    [[TDNetworkingHelper sharedInstane] postRequestWithPath:[NSString stringWithFormat:@"%@%@", BASE_URL, orders_pay_wxpay_sign] parameter:paramDic whenSuccessed:^(id json) {
        
        if ([[json objectForKey:@"code"] integerValue]==1)   //資料擷取成功
        {
            //調用微信支付
            [self sendWeChatReqWithOrderData:[json objectForKey:@"data"]];
        }
        else        //擷取失敗
        {
            ALERT([json objectForKey:@"msg"]);
        }
        
        [self hideHub];
        self.view.userInteractionEnabled = true;
        
    } whenFailed:^(NSError *error) {
        [self hideHub];
        self.view.userInteractionEnabled = true;
        //判斷網絡狀态
        [self judgeNetworkStaus];
    }];
    
    
 -(void)sendWeChatReqWithOrderData:(NSDictionary*)orderData
  {
      NSLog(@"送出的參數:%@", orderData);
        
      //調起微信支付
      PayReq* req             = [[PayReq alloc] init];
      req.openID              = [orderData objectForKey:@"appid"];
      req.partnerId           = [orderData objectForKey:@"partnerid"];
      req.prepayId            = [orderData objectForKey:@"prepayid"];
      req.nonceStr            = [orderData objectForKey:@"noncestr"];
      req.timeStamp           = (UInt32)[[orderData objectForKey:@"timestamp"] integerValue];
      req.package             = [orderData objectForKey:@"package"];
      req.sign                = [orderData objectForKey:@"sign"];
      [WXApi sendReq:req];
  }      

     五、無法完成微信支付的各種異常狀态分與處理

     筆者在開發過程中,也遇到過不少的異常狀态,現記錄如下:

     (1)無法調起手機微信用戶端、無法調起微信用戶端頁面,一閃而過

     原因分析:第一種如果您的APP內建了友盟或者shareSDK的第三方分享SDK,會導緻WechaSDK包的重複沖突;

     處理方法:删除友盟或者shareSDK裡面的WechaSDK包;在調用微信支付接口的檔案裡,字尾改為 .mm

     (2)中間隻有一個确定按鈕,點選按鈕,傳回APP,提示 “支付結果:失敗!retcode=-2,retstr=nil ”

     原因分析:到這裡,說明代碼沒有問題,是傳遞的參數有問題,任何一個參數出錯都可能導緻這樣的問題。

     處理方法:與背景完成簽名、下單的同僚溝通,檢查背景的代碼。

    備注:我就是卡在這裡兩個多星期,後來檢查發現是背景同僚在簽名的時候出現了問題。微信支付要求有兩次簽名,第二次需要timestamp(時間戳)參與簽名。我們隻有一次簽名,一直沒法調起支付界面

     希望這篇可以幫到你,讓你少走彎路。

     對以上内容有任何疑問的童鞋,請留言指教!