今天看了一篇微信支付的文章 感覺說的很詳細(xì),記錄一下,以備不時(shí)之需
1.開始接入微信支付的準(zhǔn)備工作
首先你需要去微信開放平臺(tái)注冊(cè)賬號(hào),在這里要吐槽一下,不知道這個(gè)微信平臺(tái)的賬號(hào)密碼驗(yàn)證機(jī)制,忘了以前的密碼,重新登錄,各種找回密碼都不行,實(shí)在沒轍,去注冊(cè)個(gè)Gmail??,登錄成功后,可以看到如下界面。
點(diǎn)擊右上角的創(chuàng)建移動(dòng)應(yīng)用,一步一步填寫必要填入的信息,在這里就不做多余的贅述了。
需要注意的是這里填入的Bundle ID需要和項(xiàng)目的一一對(duì)應(yīng)
接下來就等一個(gè)星期左右,等待微信審核通過你就可以將微信支付SDK集成到項(xiàng)目中,詳情可以看官方給出的文檔.
pod 集成方法
pod 'WechatOpenSDK'
在Xcode中,選擇你的工程設(shè)置項(xiàng),選中“TARGETS”一欄,在“info”標(biāo)簽欄的“URL type“添加“URL scheme”為你所注冊(cè)的應(yīng)用程序id(如下圖所示)。

完成之后可以獲取到appid(微信開放平臺(tái)為應(yīng)用生成的唯一識(shí)別碼)、商戶id、商戶secretKey。對(duì)于app端來說只用到appid,商戶id最好通過接口從server獲取,商戶secretKey是用來簽名的,一般只有server能用到。
2.支付流程

剛開始看這個(gè)流程圖可能會(huì)覺得很復(fù)雜,所以總結(jié)了我們比較關(guān)系的流程是:
app客戶端向服務(wù)器發(fā)送支付請(qǐng)求
服務(wù)器在收到客戶端請(qǐng)求之后向微信后臺(tái)調(diào)用統(tǒng)一下單API,獲得預(yù)付單信息
服務(wù)端生成帶簽名的客戶端支付信息給app
app客戶端用戶確認(rèn)支付,app喚醒微信客戶端進(jìn)行支付
app獲得支付結(jié)果后向服務(wù)端查詢最終的結(jié)果并顯示
app端的工作:
接入微信支付SDK
向服務(wù)器發(fā)送支付請(qǐng)求
支付信息喚醒微信app,然后進(jìn)行支付
收到微信支付回調(diào)后向服務(wù)器確認(rèn)支付結(jié)果
根據(jù)查詢結(jié)果展示結(jié)果頁面告知用戶支付結(jié)果
服務(wù)器端的工作:
收到app客戶端支付請(qǐng)求后向微信后臺(tái)請(qǐng)求預(yù)支付訂單
服務(wù)器端簽名并返回信息給app客戶端
接收微信后臺(tái)返回的支付結(jié)果,用來app端查詢
服務(wù)器端返回的字段說明:
appId:返回的appid
partnerId: 父級(jí)id
prepayId: 支付id
packages: 包名(微信默認(rèn)的為“Sign=WXPay”)
nonceStr: 生成的隨機(jī)字符串
timesTamp: 時(shí)間戳
sign: 簽名
image.gif
3.iOS端使用
在AppDelegate.m,導(dǎo)入微信SDK頭文件WXApi.h
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[WXApi registerApp:@"注冊(cè)獲得的appid"];//注冊(cè)appid
return YES;
}
//支持所有iOS系統(tǒng)回調(diào)
- (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的回調(diào) [self handleOpenURL:url];
}
return YES;
}- (void)handleOpenURL:(NSURL*)url {
if ([url.host isEqualToString:@"pay"]) { // -- 微信支付
[WXApi handleOpenURL:url delegate:[WXPayService sharedInstance]];
}
}
此處的WXPayService就是自己?jiǎn)为?dú)抽出來寫的一個(gè)類,遵循WXApiManagerDelegate協(xié)議
WXPayService.h
#import <Foundation/Foundation.h>
#import "WXApi.h"
@interface WXPayService : NSObject <WXApiDelegate>
///單例來接收微信請(qǐng)求的回調(diào)
+ (instancetype)sharedInstance;
// -- 根據(jù)接口返回的預(yù)支付信息,構(gòu)造支付請(qǐng)求
+ (PayReq *)getPayRequest:(NSDictionary *)prepayData;
///處理非支付請(qǐng)求的回調(diào)
- (void)onRespCallBack:(void(^)(BaseResp * resp))callback;
///從服務(wù)器端獲取到微信返回的支付請(qǐng)求用到的參數(shù)來發(fā)起支付請(qǐng)求
- (void)startPayWithReq:(PayReq *)req callback:(void(^)(BaseResp * resp))callback; @end
WXPayService.m
#import "WXPayService.h"
@interface WXPayService ()
@property (nonatomic,copy) void(^RespCallBack)(BaseResp *);
@endstatic WXPayService *sharedInstance;
@implementation WXPayService
+ (instancetype)allocWithZone:(struct _NSZone *)zone{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [super allocWithZone:zone]; }); return sharedInstance;}///單例來接收微信請(qǐng)求的回調(diào)+ (instancetype)sharedInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [[self alloc] init]; }); return sharedInstance;}// -- 根據(jù)接口返回的預(yù)支付信息,構(gòu)造支付請(qǐng)求+ (PayReq *)getPayRequest:(NSDictionary *)prepayData { if (prepayData) {// 此處Tools是自己的另一個(gè)工具類,用來判斷字典的 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;}///處理非支付請(qǐng)求的回調(diào)- (void)onRespCallBack:(void(^)(BaseResp * resp))callback { self.RespCallBack = callback;}///從服務(wù)器端獲取到微信返回的支付請(qǐng)求用到的參數(shù)來發(fā)起支付請(qǐng)求- (void)startPayWithReq:(PayReq *)req callback:(void(^)(BaseResp * resp))callback { NSAssert(req !=nil , @"未成功創(chuàng)建微信支付請(qǐng)求"); self.RespCallBack = callback; if ([WXApi isWXAppInstalled]) { // -- 判斷是否安裝微信應(yīng)用 //發(fā)起微信支付,設(shè)置參數(shù) [WXApi sendReq:req]; }else { self.RespCallBack(nil); }}#pragma mark WXApiDelegate- (void)onResp:(BaseResp *)resp { if ([resp isKindOfClass:[PayResp class]]) { // -- 判斷是否為支付的回調(diào) self.RespCallBack(resp); }}@end
在需要支付的ViewController中導(dǎo)入工具類WXPayService
4.注意點(diǎn)及問題
注意點(diǎn):
設(shè)置好scheme,否則應(yīng)用無法跳轉(zhuǎn)到微信客戶端
支付簽名時(shí)的key值全部是小寫的
如果支付顯示驗(yàn)證簽名失敗的時(shí)候,可以將packages設(shè)為默認(rèn)值(Sign=WXPay)試試
問題:
系統(tǒng)版本大于等于iOS9的,調(diào)起微信客戶端之后,可以直接點(diǎn)擊狀態(tài)欄左側(cè)按鈕返回,這時(shí)是不走回調(diào)方法的。
解決方案:
在AppDelegate.m的applicationWillEnterForeground方法中,調(diào)用查詢支付結(jié)果接口然后刷新當(dāng)然頁面。需要設(shè)置bool變量作為標(biāo)志,否則每次應(yīng)用進(jìn)入前臺(tái)都去查詢,就不符合業(yè)務(wù)要求了。
進(jìn)入微信支付頁面之后,不做操作,切換到自己應(yīng)用中,退出當(dāng)前支付頁面,然后再進(jìn)入微信客戶端點(diǎn)擊支付或者取消,此時(shí)自己的應(yīng)用會(huì)崩潰閃退
原因:退出頁面后頁面已經(jīng)出棧被銷毀,但wx回調(diào)時(shí)還是去調(diào)用其中的代理方法,就會(huì)出現(xiàn)野指針。
解決方案:在頁面的viewWillDisappear方法中加入
[WXPayService sharedManager].delegate = nil;