?
iOS集成H5微信支付實現跳轉與回調的解決方案
?
iOS集成支付寶H5支付實現跳轉與回調的解決方案
?
?
前言
最近有個需求,不能在iOS客戶端內集成支付寶和微信的App支付SDK(為了防蘋果審核檢測SDK)桨踪,因此使用H5支付,雖然微信和支付寶的H5支付文檔都說不要在App內使用H5支付而是使用App支付缅叠,但辦法總是有的悄泥。
這篇講的是H5微信支付如何從App跳轉微信以及如何從微信跳轉回App虏冻,支付寶的見這篇:
實現的效果是:App→微信→支付(成功失敗或取消)→App
前置準備
本項目使用WKWebView,前置動作是后端小伙伴已經處理好微信H5支付下單鏈接弹囚,客戶端接收到下單鏈接后的操作厨相。
下單鏈接即為微信支付文檔-統(tǒng)一下單API中返回的 mweb_url
,格式為 https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx2016121516420242444321ca0631331346&package=1405458241
鸥鹉。
操作步驟
1. 添加 URL Scheme 并把微信加入白名單
添加 URL Scheme蛮穿。在 xcodeproj
文件 Info
選項卡最下面的 URL Types
內設置。 注意此URL的一級域名需要與微信商戶后臺(微信商戶平臺-產品中心-開發(fā)配置-H5支付)設置的的一級域名一致毁渗,比如微信商戶里設置的是company.com
践磅,那 URL Schemes 可以設為 a1.company.com
,此特性使得一套H5支付可以方便得集成到多個App灸异。只有一個App需要H5支付的話也可以直接填與微信后臺的一致的 company.com
府适。
2019年4月10日更新
如果像上圖那樣填的是www.company.com
羔飞,那 URL Scheme 只能設為其三級域名如a2.www.company.com
或同樣的www.company.com
把微信的 URL Scheme weixin
和 wechat
填入項目的白名單。在 xcodeproj
文件 Info
選項卡內的 Custom iOS Target Properties
的 LSApplicationQueriesSchemes
里添加上述兩個字符串檐春,若沒有 LSApplicationQueriesSchemes
就手動輸入添加逻淌,類型為數組 Array。
2. WKWebView加載鏈接
添加協(xié)議 WKNavigationDelegate
和WKUIDelegate
疟暖。
創(chuàng)建一個WKWebView卡儒,并加載統(tǒng)一下單鏈接。
- (void)buildWKWebView {
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, NAV_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT - NAV_HEIGHT)];
[self.view addSubview:webView];
webView.navigationDelegate = self;
webView.UIDelegate = self;
NSURL *payURL = [NSURL URLWithString:self.payString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:payURL];
[request setValue:@"a1.company.com://wxpaycallback/" forHTTPHeaderField:@"Referer"];
[webView loadRequest:request];
}
此處self.payString就是后臺傳來的微信H5支付統(tǒng)一下單鏈接俐巴,格式為 https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx2016121516420242444321ca0631331346&package=1405458041
骨望。
我們需要做的處理是根據文檔給這個請求添加請求頭 Referer
,關鍵在于這個 a1.company.com://wxpaycallback/
既滿足了微信檢測到有商戶后臺設置好的一級域名窜骄,同時把這個鏈接做成了 URL Scheme 使得可以在跳轉微信客戶端后(不管支付成功還是失斀跄肌)能順利跳轉回自己的App。其中的 host wxpaycallback/
可以任意設置邻遏,方便在 AppDelegate
里處理跳轉回來后部署業(yè)務邏輯糠亩。當然如果你不需要在 AppDelegate
里接收動作而是直接跳回支付界面自行后續(xù)處理的話就只用設為前一步在 URL Scheme a1.company.com://
即可。
2019.4.10 更新
經過測試准验,對于App內的H5支付而言赎线,實際上是下面步驟里
@"https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb"
后接的參數redirect_url
對支付后跳回App起作用,Referer
只起到給微信校驗的作用糊饱。所以
Referer
只需要設置成微信H5支付登記的域名的子域名即可垂寥,如
[request setValue:@"a1.company.com" forHTTPHeaderField:@"Referer"];
3. 實現代理方法攔截鏈接并跳轉微信
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURLRequest *request = navigationAction.request;
NSString *absoluteString = [navigationAction.request.URL.absoluteString stringByRemovingPercentEncoding];
// 攔截WKWebView加載的微信支付統(tǒng)一下單鏈接, 將redirect_url參數修改為喚起自己App的URLScheme
if ([absoluteString hasPrefix:@"https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb"] && ![absoluteString hasSuffix:[NSString stringWithFormat:@"redirect_url=a1.company.com://wxpaycallback/"]]) {
decisionHandler(WKNavigationActionPolicyCancel);
NSString *redirectUrl = nil;
if ([absoluteString containsString:@"redirect_url="]) {
NSRange redirectRange = [absoluteString rangeOfString:@"redirect_url"];
redirectUrl = [[absoluteString substringToIndex:redirectRange.location] stringByAppendingString:[NSString stringWithFormat:@"redirect_url=a1.company.com://wxpaycallback/"]];
} else {
redirectUrl = [absoluteString stringByAppendingString:[NSString stringWithFormat:@"redirect_url=a1.company.com://wxpaycallback/"]];
}
NSMutableURLRequest *newRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:redirectUrl] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30];
newRequest.allHTTPHeaderFields = request.allHTTPHeaderFields;
newRequest.URL = [NSURL URLWithString:redirectUrl];
[webView loadRequest:newRequest];
return;
}
//攔截重定向的跳轉微信的 URL Scheme, 打開微信
if ([absoluteString hasPrefix:@"weixin://"]) {
decisionHandler(WKNavigationActionPolicyAllow);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if ([[UIApplication sharedApplication] canOpenURL:navigationAction.request.URL]) {
[[UIApplication sharedApplication] openURL:navigationAction.request.URL];
} else {
//未安裝微信, 自行處理
}
});
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
return;
}
4. AppDelegate 中接收跳轉動作
當然你也不一定需要在AppDelegate里接收返回動作,也可以直接返回支付界面另锋,自行操作后續(xù)邏輯滞项。
以下是AppDelegate接收返回動作的示例。
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options{
//safepay是支付寶H5支付的回調host
if ([url.host isEqualToString:@"wxpaycallback"] || [url.host isEqualToString:@"safepay"]) {
// 自行操作業(yè)務邏輯夭坪,比如使用通知請求查詢訂單狀態(tài)文判,popView回上級頁面等
UITabBarController *tabBarVC = (UITabBarController *)topRootViewController;
UINavigationController *navVC = tabBarVC.viewControllers[tabBarVC.selectedIndex];
[navVC popViewControllerAnimated:YES];
NSString *orderId = [[NSUserDefaults standardUserDefaults] objectForKey:@"PayOrderId"];
NSString *payFee = [[NSUserDefaults standardUserDefaults] objectForKey:@"PayFee"];
//以及更多參數
NSDictionary *resultDict = @{@"order_id":orderId, @"payFee":payFee};
[[NSNotificationCenter defaultCenter] postNotificationName:@"htmlPaymentNotification" object:self userInfo:resultDict];
}
}
5. 關于微信H5支付域名設置
2019年4月10日更新
這里額外提一下,截止到2019年4月室梅,微信支付設置頁面明確說了
添加域名后戏仓,其所屬的子域名將都有權限
也就是說只需要填一個一級域名比如 company.com
,就可以有無限多個二級域名可供不同App使用亡鼠,繞過微信H5支付只能添加5個域名的限制赏殃。如果填的是二級域名比如 www.company.com
,那么只能往下使用三級域名比如 a1.www.company.com
以微信H5支付域名填了 company.com
為例间涵,那可以這樣操作
App | Alpha | Beta-A1 | Beta-A2 | Gamma |
---|---|---|---|---|
添加的Referer | alpha.company.com | a1.beta.company.com | a2.beta.company.com | gamma.company.com |
要替換的redirect_url | alpha.company.com://optional | a1.beta.company.com:// | a2.beta.company.com://optional | gamma.company.com:// |
URL Scheme | alpha.company.com | a1.beta.company.com | a2.beta.company.com | gamma.company.com |