iOS微信支付接入以及工具類封裝

在剛剛結束的一個項目中用到了微信支付,從接入微信支付到工具類的封裝,在本文中作個積累,方便往後使用。安全

1.開始接入微信支付的準備工做

接入流程.png

首先你須要去微信開放平臺註冊帳號,在這裏要吐槽一下,不知道這個微信平臺的帳號密碼驗證機制,忘了之前的密碼,從新登陸,各類找回密碼都不行,實在沒轍,去註冊個Gmail😑,登陸成功後,能夠看到以下界面。bash

1.png

點擊右上角的建立移動應用,一步一步填寫必要填入的信息,在這裏就不作多餘的贅述了。 須要注意的是這裏填入的 Bundle ID須要和項目的一一對應服務器

2.png
接下來就等一個星期左右,等待微信審覈經過你就能夠將微信支付SDK集成到項目中,詳情能夠看官方給出的 文檔. pod 集成方法

pod 'WechatOpenSDK'
複製代碼

在Xcode中,選擇你的工程設置項,選中「TARGETS」一欄,在「info」標籤欄的「URL type「添加「URL scheme」爲你所註冊的應用程序id(以下圖所示)。微信

3.png

完成以後能夠獲取到appid(微信開放平臺爲應用生成的惟一識別碼)、商戶id、商戶secretKey。對於app端來講只用到appid,商戶id最好經過接口從server獲取,商戶secretKey是用來簽名的,通常只有server能用到。app

2.支付流程

支付流程.png

剛開始看這個流程圖可能會以爲很複雜,因此總結了咱們比較關係的流程是:工具

  1. app客戶端向服務器發送支付請求
  2. 服務器在收到客戶端請求以後向微信後臺調用統一下單API,得到預付單信息
  3. 服務端生成帶簽名的客戶端支付信息給app
  4. app客戶端用戶確認支付,app喚醒微信客戶端進行支付
  5. app得到支付結果後向服務端查詢最終的結果並顯示
app端的工做:
  • 接入微信支付SDK
  • 向服務器發送支付請求
  • 支付信息喚醒微信app,而後進行支付
  • 收到微信支付回調後向服務器確認支付結果
  • 根據查詢結果展現結果頁面告知用戶支付結果
服務器端的工做:
  • 收到app客戶端支付請求後向微信後臺請求預支付訂單
  • 服務器端簽名並返回信息給app客戶端
  • 接收微信後臺返回的支付結果,用來app端查詢

服務器端返回的字段說明:微信支付

  • appId:返回的appid
  • partnerId: 父級id
  • prepayId: 支付id
  • packages: 包名(微信默認的爲「Sign=WXPay」)
  • nonceStr: 生成的隨機字符串
  • timesTamp: 時間戳
  • sign: 簽名
    4.png

3.iOS端使用

AppDelegate.m,導入微信SDK頭文件WXApi.hui

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[WXApi registerApp:@"註冊得到的appid"];//註冊appid
    return YES;
}

 //支持全部iOS系統回調
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
//    [self handleOpenURL:url];
    BOOL result = [[UMSocialManager defaultManager] handleOpenURL:url sourceApplication:sourceApplication annotation:annotation];
    if (!result) {
        // 其餘如支付等SDK的回調
        [self handleOpenURL:url];
    }
    return YES;
}
- (void)handleOpenURL:(NSURL*)url {
    if ([url.host isEqualToString:@"pay"]) { // -- 微信支付
        [WXApi handleOpenURL:url delegate:[WXPayService sharedInstance]];
    }
}

複製代碼

此處的WXPayService就是本身單獨抽出來寫的一個類,遵循WXApiManagerDelegate協議atom

WXPayService.h
#import <Foundation/Foundation.h>
#import "WXApi.h"
@interface WXPayService : NSObject <WXApiDelegate>
///單例來接收微信請求的回調
+ (instancetype)sharedInstance;
// -- 根據接口返回的預支付信息,構造支付請求
+ (PayReq *)getPayRequest:(NSDictionary *)prepayData;

///處理非支付請求的回調
- (void)onRespCallBack:(void(^)(BaseResp * resp))callback;
///從服務器端獲取到微信返回的支付請求用到的參數來發起支付請求
- (void)startPayWithReq:(PayReq *)req callback:(void(^)(BaseResp * resp))callback; 
@end
複製代碼
WXPayService.m
#import "WXPayService.h"
@interface WXPayService ()
@property (nonatomic,copy) void(^RespCallBack)(BaseResp *);
@end
static WXPayService *sharedInstance;

@implementation WXPayService
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [super allocWithZone:zone];
    });
    return sharedInstance;
}
///單例來接收微信請求的回調
+ (instancetype)sharedInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

// -- 根據接口返回的預支付信息,構造支付請求
+ (PayReq *)getPayRequest:(NSDictionary *)prepayData {
    if (prepayData) {
//  此處Tools是本身的另外一個工具類,用來判斷字典的
        PayReq *req = [[PayReq alloc] init];
        if ([Tools dicContain:prepayData withKey:@"partnerid"]) {
            req.partnerId = prepayData[@"partnerid"];
        }
        if ([Tools dicContain:prepayData withKey:@"prepayid"]) {
            req.prepayId = prepayData[@"prepayid"];
        }
        if ([Tools dicContain:prepayData withKey:@"noncestr"]) {
            req.nonceStr = prepayData[@"noncestr"];
        }
        if ([Tools dicContain:prepayData withKey:@"timestamp"]) {
            req.timeStamp = [prepayData[@"timestamp"] intValue];
        }

        req.package =@"Sign=WXPay";
        req.sign =  @"null";
        //日誌輸出
        NSLog(@"appid=%@/npartid=%@/nprepayid=%@/nnoncestr=%@/ntimestamp=%ld/npackage=%@/nsign=%@",[prepayData objectForKey:@"appid"],req.partnerId,req.prepayId,req.nonceStr,(long)req.timeStamp,req.package,req.sign);
        return req;
    }
    return nil;
}

///處理非支付請求的回調
- (void)onRespCallBack:(void(^)(BaseResp * resp))callback {
    self.RespCallBack = callback;
}
///從服務器端獲取到微信返回的支付請求用到的參數來發起支付請求
- (void)startPayWithReq:(PayReq *)req callback:(void(^)(BaseResp * resp))callback {
    NSAssert(req !=nil , @"未成功建立微信支付請求");
    self.RespCallBack = callback;
    if ([WXApi isWXAppInstalled]) { // -- 判斷是否安裝微信應用
        //發起微信支付,設置參數
        [WXApi sendReq:req];
    }else {
        self.RespCallBack(nil);
    }
}

#pragma mark WXApiDelegate
- (void)onResp:(BaseResp *)resp {
    if ([resp isKindOfClass:[PayResp class]]) { // -- 判斷是否爲支付的回調
        self.RespCallBack(resp);
    }
}
@end
複製代碼

在須要支付的ViewController中導入工具類WXPayService url

5.png

4.注意點及問題

注意點:

  • 設置好scheme,不然應用沒法跳轉到微信客戶端
  • 支付簽名時的key值所有是小寫的
  • 若是支付顯示驗證簽名失敗 的時候,能夠將packages設爲默認值(Sign=WXPay)試試

問題:

系統版本大於等於iOS9的,調起微信客戶端以後,能夠直接點擊狀態欄左側按鈕返回,這時是不走回調方法的。

解決方案: 在AppDelegate.m的applicationWillEnterForeground方法中,調用查詢支付結果接口而後刷新固然頁面。須要設置bool變量做爲標誌,不然每次應用進入前臺都去查詢,就不符合業務要求了。

進入微信支付頁面以後,不作操做,切換到本身應用中,退出當前支付頁面,而後再進入微信客戶端點擊支付或者取消,此時本身的應用會崩潰閃退

緣由:退出頁面後頁面已經出棧被銷燬,但wx回調時仍是去調用其中的代理方法,就會出現野指針。 解決方案:在頁面的viewWillDisappear方法中加入

[WXPayService sharedManager].delegate = nil;
複製代碼

5.結束語

微信支付簽名建議和服務端協商作二次簽名,以保證支付的安全性。 ps: 若有不對的地方,歡迎批評指正,更多文章請點擊這裏

若有須要,請關注公衆號JackerooChu,瞭解更多文章

公衆號
相關文章
相關標籤/搜索