iOS開發微信支付

如今基本全部的App都會接入支付寶支付以及微信支付,也有不少第三方提供給你php

SDK幫你接入,可是這種涉及到支付的東西仍是本身服務器搞來的好一些,其實搞懂了c++

輯很是的簡單,下面直接給你們說說下基本流程和接入須要注意的東西。算法

 

支付寶詳細爬坑接入指南傳送門api

 

前期準備(這個東西通常來說咱們不須要來操心,可是仍是稍微介紹下)安全

1.到微信開放平臺註冊帳號點擊打開連接服務器

2.進入管理中心------移動應用------建立移動應用----根據頁面完善應用資料微信

3.審覈事後,經過應用詳情頁面,查看應用詳情,查看AppID和AppSecret相關信息app

4.建立這些是沒有支付能力的,須要額外申請,仍是根據提示一步步填寫,填寫完以後會發一封郵件到您的預留的郵箱,而後到商戶平臺點擊打開連接填寫資料,最主要的是驗證下開戶收款帳號,會收到一波幾分錢的鉅額財產,那麼這個時候若是你填寫的是你的開戶帳號,直接跑路吧,這些錢夠你在深圳買房了。。。。。。若是你是個好人,那麼找大家財務驗證下是否有收到,就表明經過了,愉快的代碼時間來了異步

   

 

開擼代碼以前先看下基本流程ide

 

商戶系統和微信支付系統主要交互說明:

步驟1:用戶在商戶APP中選擇商品,提交訂單,選擇微信支付。

步驟2:商戶後臺收到用戶支付單,調用微信支付統一下單接口。點擊打開連接

步驟3:統一下單接口返回正常的prepay_id,再按簽名規範從新生成簽名後,將數據傳輸給APP。參與簽名的字段名爲appId,partnerId,prepayId,nonceStr,timeStamp,package。注意:package的值格式爲Sign=WXPay

步驟4:商戶APP調起微信支付。點擊打開連接

步驟5:商戶後臺接收支付通知。點擊打開連接

步驟6:商戶後臺查詢支付結果。點擊打開連接

 

 

看完流程,來看看我們客戶端要作什麼準備

1.SDK接入

2.依賴庫導入(貌似還差個libc++.dylib,也一併加入)

 

3.iOS 9 配置白名單

 

4.配置下Scheme(這填寫的是申請回來的ID)


 

終於能夠愉快的寫代碼了

 

1.向微信註冊你的AppID

 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    //註冊APP,這裏的字符串就是Wechat URL Scheme裏面對應的ID 也是申請回來的ID,必須一致
    [WXApi registerApp:@"這裏填寫申請回來的ID"];
    return YES;
}

2.請求服務器的參數,拉起微信支付App(超級關鍵,注意聽)

 

 

#pragma mark - 微信支付
- (void)wechatPay
{
    // 把生成的訂單信息組裝起來傳給服務器,如何組裝就和服務器約定好
    [[TWTShoppingCartLogic sharedData] goToWechatEasyPay:self.orderStr way:@"2" complete:^(NSError *error, id data) {
       
        NSMutableString *stamp  = [data objectForKey:@"timestamp"];
        
        //調起微信支付
        PayReq* req             = [[PayReq alloc] init];
        req.partnerId           = [data objectForKey:@"partnerid"];
        req.prepayId            = [data objectForKey:@"prepayid"];
        req.nonceStr            = [data objectForKey:@"noncestr"];
        req.timeStamp           = stamp.intValue;
        req.package             = [data objectForKey:@"package"];
        req.sign                = [data objectForKey:@"sign"];
        [WXApi sendReq:req];
        
    }];
}

這裏請求的方法和步驟就不寫了,無非就是post信息給服務器,我們看看須要的數據格式(假數據)

 

{
  "appid" : "wxb4b",微信開放平臺審覈經過的AppID
  "noncestr" : "171127dd056d05e423c8b9e",隨機字符串
  "package" : "Sign=WXPay", 固定值
  "partnerid" : "130", 微信支付分配的商戶ID
  "prepayid" : "wx201609291601", 預支付交易會話ID
  "sign" : "684371081C049B6017641", 簽名,除了sign,剩下6個組合的再次簽名字符串
  "timestamp" : 147513 當前時間
}

 

注意啦!!!!!!

 

第一種:老司機後臺類型

 

其實當你把訂單傳給後臺的時候,後臺事先會把訂單經過微信的生成預支付訂單生成

 

prepayID點擊打開連接,那麼對於老司機來講,怎麼可能把這種返回的數據返回給你?

 

他們會把接受的prepayID根據上面的結構組裝起來,那麼預支付訂單生成的時候也會返

回sign字段,老司機不會直接用,後臺會把這個字段,也就是剩下6個字段再次md5籤

名生成簽名算法新的sign字段組裝完畢返回給你,這種狀況下直接在App上配置模型,

拉起微信支付,很是舒暢,一鼓作氣!!!

 

第二種:沒法理解類型後臺(讓你本身簽名)

 

當你把訂單傳給他的時候,一樣他會生成個預訂單prepayID,那麼這種司機開車特別

猛,直接把返回的參數根據格式組裝後彈回給你,sign字段也是預訂單生成後的,沒有

通過二次md5簽名,他也沒有告訴你,那麼你也特別猛,沒問他,直接用他的字段,組

裝完畢,拉起微信,我擦,你會直接懵逼了,那麼你將會只會看到這個。

 

問題不大,就是本身簽名了,本身寫個本地的md5玩玩(假的千萬別用,網上

找來的分享下)

 

//建立package簽名
-(NSString*) createMd5Sign:(NSMutableDictionary*)dict
{
    NSMutableString *contentString  =[NSMutableString string];
    NSArray *keys = [dict allKeys];
    //按字母順序排序
    NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        return [obj1 compare:obj2 options:NSNumericSearch];
    }];
    //拼接字符串
    for (NSString *categoryId in sortedArray) {
        if (   ![[dict objectForKey:categoryId] isEqualToString:@""]
            && ![categoryId isEqualToString:@"sign"]
            && ![categoryId isEqualToString:@"key"]
            )
        {
            [contentString appendFormat:@"%@=%@&", categoryId, [dict objectForKey:categoryId]];
        }
        
    }
    //添加key字段
    [contentString appendFormat:@"key=%@", self.spKey];
    //獲得MD5 sign簽名
    NSString *md5Sign =[contentString MD5];
    
    return md5Sign;
}

- (NSMutableDictionary*)payWithprePayid:(NSString*)prePayid

{
    if(prePayid == nil)
    {
        NSLog(@"prePayid 爲空");
        return nil;
    }
    
    //獲取到prepayid後進行第二次簽名
    NSString    *package, *time_stamp, *nonce_str;
    //設置支付參數
    time_t now;
    time(&now);
    time_stamp  = [NSString stringWithFormat:@"%ld", now];
    nonce_str = [time_stamp MD5];
    //從新按提交格式組包,微信客戶端暫只支持package=Sign=WXPay格式,須考慮升級後支持攜帶package具體參數的狀況
    //package       = [NSString stringWithFormat:@"Sign=%@",package];
    package         = @"Sign=WXPay";
    //第二次簽名參數列表
    NSMutableDictionary *signParams = [NSMutableDictionary dictionary];
    NSLog(@"%@",signParams);
    [signParams setObject: self.appId  forKey:@"appid"];
    [signParams setObject: self.mchId  forKey:@"partnerid"];
    [signParams setObject: nonce_str    forKey:@"noncestr"];
    [signParams setObject: package      forKey:@"package"];
    [signParams setObject: time_stamp   forKey:@"timestamp"];
    [signParams setObject: prePayid     forKey:@"prepayid"];
    
    //生成簽名
    NSString *sign  = [self createMd5Sign:signParams];
    
    //添加簽名
    [signParams setObject: sign         forKey:@"sign"];
    
    
    //返回參數列表
    return signParams;
}


 

若是真的要在App端二次簽名的話,那加密的時候還要加入申請的密鑰,可是真的很差

 

樣作,其一:服務器已經作過一次簽名了,第二次作了返回給你就行了,不必再給

 

App。其二:不安全,全放在App上,這種東西必定要放到服務器

 

小技巧:其實出現上面那種狀況有幾種可能

1.sign沒有二次簽名

2.noncerStr是服務器返回的,不要本身生成

3.package是寫死的,不要寫錯了

4.timeStamp是10位數

5.本身簽名的sign必定要所有大寫

6.爲了不上面的狀況,交給服務器管理,咱們負責組裝拉起微信支付就行了

 

3.處理回調信息

Appdelegate

 

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
    
    // 跳轉到URL scheme中配置的地址
    //NSLog(@"跳轉到URL scheme中配置的地址-->%@",url);
    return  [WXApi handleOpenURL:url delegate:[WXApiManager sharedManager]];
}
//支付成功時調用,回到第三方應用中
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    if ([url.scheme isEqualToString:WECHAT_APPKEY])//微信調用結束
    {
        return [WXApi handleOpenURL:url delegate:[WXApiManager sharedManager]];
    }
    
}

這裏的處理是根據微信官網提供的方法,代理到專門處理的單利當中去統一處理WXApiManager

 

注意點:有些人用NSNotificationCenter來通知到發出請求的界面去,而後在發起的界面處理回調的邏輯,可是這裏

你要考慮一種非人類的交互,TMD有人在拉起微信支付的時候把本身的App給推出了或者App本身掛了,那麼當回調

生效的時候,原先拉起微信支付App的界面已經消失了,你發的通知他收不到了,這種狀況我是存到本地的

 

[[NSUserDefaultsstandardUserDefaults]setValue:self.orderStrforKey:@"WECHAT_PAY_ORDER_TRADEID"];

[[NSUserDefaultsstandardUserDefaults]synchronize];

處理回調的時候直接從本地讀取

 

最終處理邏輯的地方(這裏不能直接用他的返回接過,要二次確認)

 

//微信回調,有支付結果的時候會回調這個方法
- (void)onResp:(BaseResp *)resp {
    if([resp isKindOfClass:[PayResp class]]){
        //支付返回結果,實際支付結果須要去微信服務器端查詢
        NSString *strMsg,*strTitle = [NSString stringWithFormat:@"支付結果"];
        
        switch (resp.errCode) {
            case WXSuccess:
                strMsg = @"支付結果:成功!";
                NSLog(@"支付成功-PaySuccess,retcode = %d", resp.errCode);
                // 這裏別用返回的狀態來肯定是否正真支付成功了,這樣是不對的,咱們必須拿着存到本地的traderID去服務器再次check,這樣和服務器收到的異步回調結果匹配以後才能確認是否真的已經支付成功了
                [[TWTShoppingCartLogic sharedData] gotoCheckWeChatOrder:tradeID compelete:^(NSError *error, id data) {
                    // 二次確認
                }];
                break;
                
            default:
                strMsg = [NSString stringWithFormat:@"支付結果:失敗!retcode = %d, retstr = %@", resp.errCode,resp.errStr];
                NSLog(@"錯誤,retcode = %d, retstr = %@", resp.errCode,resp.errStr);
                break;
        }
    }

}


 

 

仍是總結下重要的地方吧

 

1.App Scheme必定要配置正確

 

2.千萬不能用生成預訂單返回的Sign,要從新生成(和後臺溝通)

 

3.要考慮拉起App支付的時候本身程序被退出或者自殺了

 

4.必定不能用異步返回給App的參數進行判斷成功與否,須要和後臺進行二次確認,異步返回給後臺的數據纔是最終的

 

看官方給的說法

差很少介紹到這裏了,本身微信遇到的坑沒有接入支付寶的時候多,接過支付寶再接入

微信,真的太簡單了,有空再寫個支付寶支付,以爲有幫到你們的記得給個贊哦~~~

遇到其餘問題了再補充

 

12.6日更新:同一訂單支付兩次的問題,商戶保證支付平臺大姨媽的狀況下去重



遇到了這麼個場景,當你支付完的時候支付寶或者微信沒有及時回調,用戶已經支付,可是平臺還在處理中,也沒有異步通知商戶後臺,例如第一張圖的支付寶同步狀態碼8000 or 6004,第二張圖的-1,那麼這個時候咱們App作完一系列操做以後非人類用戶覺得沒支付,可是其實已經支付了,支付寶和微信大姨媽了,土豪買家又點了支付,這個時候是和9000支付成功不一樣的,成功的時候支付寶是會去重的,不會讓你重複支付的,微信暫時不清楚,這個時候後臺還沒收到任何回調,又拉起了支付,居然還能支付,神奇的兩個訂單產生了,雖然最終最會成功一個訂單,另外一個訂單會支付失敗,這個狀況遇到了仍是很懵逼的,記錄下,有不一樣意見的能夠留言分享下。

個人作法就是:

對於同步回調的狀態碼,讓後臺再開一個接口post給他,他根據這個狀態碼避免同一個已支付的訂單,可是在處理中的時候重複簽名,重複去支付,這樣就又能愉快的玩耍了,雖然是比較罕見的操做,可是也得稍微留意下

 

這裏就沒有Demo了,有個官方的已經很詳細了

點擊打開微信官方Demo連接

相關文章
相關標籤/搜索