1、介紹:php
如今的消費愈來愈方便,直接帶個手機用各類三方的支付平臺進行支付就行,例如微信、支付寶。如今正好我所作的項目中用到了微信支付,今天就來整理一下。git
2、準備:github
一、去微信官方開發者平臺註冊開發者帳號:https://open.weixin.qq.com算法
二、而後登錄開發平臺:json
三、給項目對應的Bundle ID建立應用程序(默認有登錄和分享功能,固然須要花300塊錢申請支付功能,通常公司會購買,完成這些操做就是等待審覈了,通常一到兩個星期就搞定了)api
四、審覈經過,能夠看到以下顯示:會生成AppID(很重要,開發時會用到,用來註冊微信支付時使用的)服務器
五、選擇APP支付方式,參看文檔進行集成微信
六、下載資源包:(通常都是最新的版本,須要在Xocde8.0上編譯,我在後面使用的是1.7.1版,在Xcode7.3.1上編譯)網絡
七、參考APP端開發步驟,配置屬性session
(1)我下載的是1.7.1版本,最好手動把SDK拖入到項目中,很簡單,主要有四個文件:libWeChatSDK.a靜態包、WechatAuthSDK.h、WXApi.h、WXApiObject.h
(2)設置plist網絡請求字段(iOS9.0以上須要設置)
(3)添加依賴庫後編譯,Build success
(4)項目設置APPID.
商戶在微信開放平臺申請開發APP應用後,微信開放平臺會生成APP的惟一標識APPID。在Xcode中打開項目,設置項目屬性中的URL Schemes爲您的APPID。如圖:
(5)進入項目,寫代碼,註冊APPID
商戶APP工程中引入微信lib庫和頭文件,調用API前,須要先向微信註冊您的APPID,代碼以下:
[WXApi registerApp:@"wxd930xxxxxxxxx" withDescription:@"wxchatpay"]; //註冊微信的AppID
(6)商戶服務器生成支付訂單,先調用【統一下單API】生成預付單,獲取到prepay_id後將參數再次簽名傳輸給APP發起支付,給出的參數不少,就不所有截圖了。
(7)隨機字符串和簽名都必須按照微信所給出的算法生成,並且參數都是以xml格式放入到請求正文裏
a.隨機字符串算法:咱們推薦生成隨機數算法以下:調用隨機數函數生成,將獲得的值轉換爲字符串。
#pragma mark - 產生隨機字符串 //生成隨機數算法 ,隨機字符串,不長於32位 //微信支付API接口協議中包含字段nonce_str,主要保證簽名不可預測。 //咱們推薦生成隨機數算法以下:調用隨機數函數生成,將獲得的值轉換爲字符串。 + (NSString *)generateTradeNO { static int kNumber = 15; NSString *sourceStr = @"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; NSMutableString *resultStr = [[NSMutableString alloc] init]; // srand函數是初始化隨機數的種子,爲接下來的rand函數調用作準備。 // time(0)函數返回某一特定時間的小數值。 // 這條語句的意思就是初始化隨機數種子,time函數是爲了提升隨機的質量(也就是減小重複)而使用的。 // srand(time(0)) 就是給這個算法一個啓動種子,也就是算法的隨機種子數,有這個數之後才能夠產生隨機數,用1970.1.1至今的秒數,初始化隨機數種子。 // Srand是種下隨機種子數,你每回種下的種子不同,用Rand獲得的隨機數就不同。爲了每回種下一個不同的種子,因此就選用Time(0),Time(0)是獲得當前時時間值(由於每時每刻時間是不同的了)。 srand((unsigned int)time(0)); for (int i = 0; i < kNumber; i++) { unsigned index = rand() % [sourceStr length]; NSString *oneStr = [sourceStr substringWithRange:NSMakeRange(index, 1)]; [resultStr appendString:oneStr]; } return resultStr; }
b.簽名生成算法查看連接:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3
也能夠模擬簽名生成接口,做爲一次性測試使用:https://pay.weixin.qq.com/wiki/tools/signverify/,須要填寫對應的字段參數,點擊生成便可:如圖
c、填寫參數,使用AFN,進行統一下單,最終的全部的參數統一爲xml,不是json,格式以下:
d、返回發送下單請求後的反饋結果:
統一下單代碼:
// 交易類型 #define TRADE_TYPE @"APP" // 交易結果通知網站此處用於測試,隨意填寫,正式使用時填寫正確網站 #define NOTIFY_URL @"http://wxpay.weixin.qq.com/pub_v2/pay/notify.v2.php" // 交易價格1表示0.01元,10表示0.1元 #define PRICE @"1" #pragma mark - 客戶端操做/ 實際操做由服務端操做 // 隨機字符串變量 這裏最好使用和安卓端一致的生成邏輯 NSString *tradeNO = [self generateTradeNO]; // 設備IP地址,請在wifi環境下測試,不然獲取的ip地址爲error,正確格式應該是8.8.8.8 //NSString *addressIP = [self fetchIPAddress]; NSString *addressIP = [[IPToolManager sharedManager] currentIpAddress]; // 隨機產生訂單號用於測試,正式使用請換成你從本身服務器獲取的訂單號 NSString *orderno = [NSString stringWithFormat:@"%ld",time(0)]; // 獲取SIGN簽名 DataMD5 *data = [[DataMD5 alloc] initWithAppid:WX_APPID mch_id:MCH_ID nonce_str:tradeNO partner_id:WX_PartnerKey body:@"充值" out_trade_no:orderno total_fee:PRICE spbill_create_ip:addressIP notify_url:NOTIFY_URL trade_type:TRADE_TYPE]; // 轉換成XML字符串,這裏知識形似XML,實際並非正確的XML格式,須要使用AF方法進行轉義 NSString *string = [[data dic] XMLString]; AFHTTPSessionManager *session = [AFHTTPSessionManager manager]; // 這裏傳入的XML字符串只是形似XML,但不是正確是XML格式,須要使用AF方法進行轉義 session.responseSerializer = [[AFHTTPResponseSerializer alloc] init]; [session.requestSerializer setValue:@"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; [session.requestSerializer setValue:WXUNIFIEDORDERURL forHTTPHeaderField:@"SOAPAction"]; [session.requestSerializer setQueryStringSerializationWithBlock:^NSString *(NSURLRequest *request, NSDictionary *parameters, NSError *__autoreleasing *error) { return string; }]; [session POST:WXUNIFIEDORDERURL parameters:string progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { // 輸出XML數據 NSString *responseString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding] ; // 將微信返回的xml數據解析轉義成字典 NSDictionary *dic = [NSDictionary dictionaryWithXMLString:responseString]; // 判斷返回的許可 if ([[dic objectForKey:@"result_code"] isEqualToString:@"SUCCESS"] &&[[dic objectForKey:@"return_code"] isEqualToString:@"SUCCESS"] ) { //這裏面調起支付 (就是下面的第8步) //............pay code....... } } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"%@",error); }];
(8)下單成功後,調起支付
// 發起微信支付,設置參數 PayReq *request = [[PayReq alloc] init]; request.openID = [dic objectForKey:WXAPPID]; request.partnerId = [dic objectForKey:WXMCHID]; request.prepayId= [dic objectForKey:WXPREPAYID]; request.package = @"Sign=WXPay"; request.nonceStr= [dic objectForKey:WXNONCESTR]; // 將當前時間轉化成時間戳 NSDate *datenow = [NSDate date]; NSString *timeSp = [NSString stringWithFormat:@"%ld", (long)[datenow timeIntervalSince1970]]; UInt32 timeStamp =[timeSp intValue]; request.timeStamp= timeStamp; // 簽名加密 DataMD5 *md5 = [[DataMD5 alloc] init]; request.sign=[md5 createMD5SingForPay:request.openID partnerid:request.partnerId prepayid:request.prepayId package:request.package noncestr:request.nonceStr timestamp:request.timeStamp]; // 調用微信 [WXApi sendReq:request];
支付的接口參數和返回結果截圖以下:
(9)設置支付代理,能夠設置APPDelegate爲代理,也能夠本身創下建立單例工具類做爲代理,處理支付回調結果。照微信SDK Sample,在類實現onResp函數,支付完成後,微信APP會返回到商戶APP並回調onResp函數,開發者須要在該函數中接收通知,判斷返回錯誤碼,若是支付成功則去後臺查詢支付結果再展現用戶實際支付結果。注意 必定不能以客戶端返回做爲用戶支付的結果,應以服務器端的接收的支付通知或查詢API返回的結果爲準。代碼示例以下:
-(void)onResp:(BaseResp*)resp{ if ([respisKindOfClass:[PayRespclass]]){ PayResp*response=(PayResp*)resp; switch(response.errCode){ caseWXSuccess: //服務器端查詢支付通知或查詢API返回的結果再提示成功 NSlog(@"支付成功"); break; default: NSlog(@"支付失敗,retcode=%d",resp.errCode); break; } } }
好了,大體差很少就能夠了,下面是我用真機測試的結果,測試宏定義設置的一分錢:點擊綠色的微信支付按鈕
(10)demo
本人demo地址以下(demo中須要在pch文件和info.plist文件設置appID等屬性):https://github.com/xiayuanquan/WXChatPay
另外ip地址的獲取也很重要,本人demo地址:https://github.com/xiayuanquan/IP_Test
借鑑的支付demo(demo中須要在pch文件和info.plist文件設置appID等屬性):https://github.com/lyoniOS/WxPayDemo
參考博客地址: