由于不能在iOS客戶端內(nèi)集成支付寶和微信的App支付SDK(為了防蘋(píng)果審核檢測(cè)SDK),因此使用H5支付,雖然微信和支付寶的H5支付文檔都說(shuō)不要在App內(nèi)使用H5支付而是使用App支付,但辦法總是有的。
這篇講的是微信H5支付如何從App跳轉(zhuǎn)微信以及如何從微信跳轉(zhuǎn)回App,支付寶支付的見(jiàn)這篇:
實(shí)現(xiàn)的效果是:App→微信→支付(成功失敗或取消)→App
前置準(zhǔn)備
準(zhǔn)備時(shí)大家需要看下官方文檔: 微信H5支付開(kāi)發(fā)文檔
本項(xiàng)目使用WKWebView,前置動(dòng)作是后端小伙伴已經(jīng)處理好支付寶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 選項(xiàng)卡最下面的 URL Types內(nèi)設(shè)置。 注意此URL的一級(jí)域名需要與微信商戶后臺(tái)(微信商戶平臺(tái)-產(chǎn)品中心-開(kāi)發(fā)配置-H5支付)設(shè)置的的一級(jí)域名一致,比如微信商戶里設(shè)置的是company.com,那 URL Schemes 可以設(shè)為 a1.company.com,此特性使得一套H5支付可以方便得集成到多個(gè)App。只有一個(gè)App需要H5支付的話也可以直接填與微信后臺(tái)的一致的 company.com 。
如果像上圖那樣填的是 www.company.com,那URL Scheme 只能設(shè)為其三級(jí)域名如 a2.www.company.com 或同樣的 www.company.com

把微信的URL Scheme weixin 和 wechat填入項(xiàng)目的白名單。在 xcodeproj 文件 Info 選項(xiàng)卡內(nèi)的 Custom iOS Target Properties的LSApplicationQueriesSchemes 里添加上述兩個(gè)字符串,若沒(méi)有 LSApplicationQueriesSchemes 就手動(dòng)輸入添加,類型為數(shù)組 Array。
2. WKWebView加載鏈接
添加協(xié)議 WKNavigationDelegate和 WKUIDelegate。
創(chuàng)建一個(gè)WKWebView,并加載統(tǒng)一下單鏈接。
- (void)buildWKWebView {
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, width, 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就是后臺(tái)傳來(lái)的微信H5支付統(tǒng)一下單鏈接,格式為 https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx2016121516420242444321ca0631331346&package=1405458041。
我們需要做的處理是根據(jù)文檔給這個(gè)請(qǐng)求添加請(qǐng)求頭Referer,關(guān)鍵在于這個(gè) a1.company.com://wxpaycallback/既滿足了微信檢測(cè)到有商戶后臺(tái)設(shè)置好的一級(jí)域名,同時(shí)把這個(gè)鏈接做成了 URL Scheme 使得可以在跳轉(zhuǎn)微信客戶端后(不管支付成功還是失?。┠茼樌D(zhuǎn)回自己的App。其中的 host wxpaycallback/可以任意設(shè)置,方便在 AppDelegate 里處理跳轉(zhuǎn)回來(lái)后部署業(yè)務(wù)邏輯。當(dāng)然如果你不需要在 AppDelegate里接收動(dòng)作而是直接跳回支付界面自行后續(xù)處理的話就只用設(shè)為前一步在 URL Scheme a1.company.com://即可。
經(jīng)過(guò)測(cè)試,對(duì)于App 內(nèi)的H5 支付而言,實(shí)際上是下面步驟里
@"https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb"
后接的參數(shù) redirect_url 對(duì)支付后跳回App起作用,Referer 只起到給微信校驗(yàn)的作用。
所以Referer 只需要設(shè)置成微信H5 支付登記的域名的子域名即可,如
[request setValue:@"a1.company.com" forHTTPHeaderField:@"Referer"];
3. 實(shí)現(xiàn)代理方法攔截鏈接并跳轉(zhuǎn)微信
- (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參數(shù)修改為喚起自己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;
}
//攔截重定向的跳轉(zhuǎn)微信的 URL Scheme, 打開(kāi)微信
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 中接收跳轉(zhuǎn)動(dòng)作
當(dāng)然你也不一定需要在AppDelegate里接收返回動(dòng)作,也可以直接返回支付界面,自行操作后續(xù)邏輯。
以下是AppDelegate接收返回動(dòng)作的示例。
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options{
//safepay是支付寶H5支付的回調(diào)host
if ([url.host isEqualToString:@"wxpaycallback"] ) {
// 自行操作業(yè)務(wù)邏輯
}
}
5. 關(guān)于微信H5支付域名設(shè)置
這里額外提一下,截止到2019年4月,微信支付設(shè)置頁(yè)面明確說(shuō)了

添加域名后,其所屬的子域名將都有權(quán)限
也就是說(shuō)只需要填一個(gè)一級(jí)域名比如 company.com ,就可以有無(wú)限多個(gè)二級(jí)域名可供不同App使用,繞過(guò)微信H5支付只能添加5個(gè)域名的限制。如果填的是二級(jí)域名比如 www.company.com,那么只能往下使用三級(jí)域名比如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 |
參考:
https://paaatrick.com/2019-03-22-ios-wxpay-h5-solution/
https://www.cnblogs.com/Life-Record/p/8472319.html