iOS: 實現微信支付

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

 

參考博客地址:

http://www.jianshu.com/p/af8cbc9d51b0

http://blog.csdn.net/qq_22080737/article/details/51984801

相關文章
相關標籤/搜索