iOS WKWebView H5微信支付跳轉(zhuǎn)
需求:iOS客戶端實現(xiàn)嵌入H5進(jìn)行微信支付跳轉(zhuǎn)到微信客戶端端朵,支付完成后再跳轉(zhuǎn)回我們的APP,解決WKWebView無法跳轉(zhuǎn)回APP的BUG.
閱讀前提:
- 了解WKWebView基本初始化及使用
- 了解如何利用URL Schemes進(jìn)行應(yīng)用間跳轉(zhuǎn)
- 公司或個人已經(jīng)在微信后臺注冊了一級域名
GitHub地址(附代碼) : iOS WKWebView H5微信支付跳轉(zhuǎn)
簡書地址 : iOS WKWebView H5微信支付跳轉(zhuǎn)
博客地址 : iOS WKWebView H5微信支付跳轉(zhuǎn)
掘金地址 : iOS WKWebView H5微信支付跳轉(zhuǎn)
更新說明
2019.1.3
- 首先對所有解析的URL進(jìn)行decode,因為服務(wù)器端可能進(jìn)行encode導(dǎo)致帶有redirect url部分無法被正確的加載
- 修改替換redirect url參數(shù)方式,因為redirect url可能含有&等特殊字符燃箭,導(dǎo)致原先方法識別錯誤,當(dāng)然前提是必須把redirect url放到url的最后
- 對一些服務(wù)器加載的特殊Url(非http/https開頭)進(jìn)行處理舍败,防止進(jìn)入到微信跳回后重定向地址的邏輯中.
注意:如對WKWebView基本的初始化代理方法不了解可自行百度谷歌招狸,解釋眾多,本文只針對了解基礎(chǔ)后實現(xiàn)邻薯。
1.在項目的Info.plist中添加一個URL Schemes(用于跳回我們項目)裙戏,如下圖所示
其中我們只要關(guān)心URL Schemes中item的名字例如 xdx.xiaodongxie.cn
- xdx 為前綴,可任意填寫
- xiaodongxie.cn為你們公司在微信后臺注冊的一級域名
注意:xiaodongxie.cn一級域名不可隨意填寫厕诡,否則網(wǎng)頁將報錯:商家參數(shù)格式錯誤累榜,請聯(lián)系商家解決.
2.添加WKNavigationDelegate代理,并實現(xiàn)重定向代理方法
3.通過攔截微信鏈接以實現(xiàn)跳轉(zhuǎn)
3-1. 攔截微信支付地址
前綴https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb的網(wǎng)址灵嫌,該網(wǎng)址即為進(jìn)行微信支付
3-2. 解決完成微信支付后無法跳轉(zhuǎn)回APP
攔截后我們需要首先關(guān)注在原始地址中是否含有redirect_url=字符串壹罚,如果含有該字符串則說明你們后臺人員是利用該字符串在微信支付完成后跳轉(zhuǎn)到支付完成的界面.而我們也需要利用該字段以實現(xiàn)支付完成后跳轉(zhuǎn)回我們的APP.
- 如果包含redirect_url=字段,我們需要先記住后臺重定向的地址寿羞,然后將其替換成我們配置好的URL schemes以實現(xiàn)跳轉(zhuǎn)回我們的APP.然后在跳轉(zhuǎn)回我們APP之后我們會手動再加載一次原先重定向的URL地址猖凛。
- 如果不包含redirect_url=字段,我們只需要添加該字段到原始URL最后面即可
3-3. 使用[[UIApplication sharedApplication] openURL:request.URL];
即可打開微信客戶端
注意
- 我們需要判斷微信地址的同時判斷“redirect_url=xdx.%@://”,因為我們在第一次檢測到后會重新加載該地址绪穆,該地址中也含有
https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb
辨泳,會形成循環(huán)沖突,所以判斷條件如下 - 如我們項目中有支付完成的重定向地址玖院,我們可以在跳轉(zhuǎn)前即加載該地址菠红,否則我們在回到APP后會有明顯的加載過程,界面不友好
- 一般跳轉(zhuǎn)到其他APP時难菌,地址不是以http或https開頭试溯,所以我們在最后的判斷中以此為依據(jù),但注意如果服務(wù)器端加載錯誤的地址可能會走入此邏輯,所以必須對特定的scheme進(jìn)行處理
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURLRequest *request = navigationAction.request;
NSString *scheme = [request.URL scheme];
// decode for all URL to avoid url contains some special character so that it wasn't load.
NSString *absoluteString = [navigationAction.request.URL.absoluteString stringByRemovingPercentEncoding];
NSLog(@"Current URL is %@",absoluteString);
static NSString *endPayRedirectURL = nil;
// Wechat Pay, Note : modify redirect_url to resolve we couldn't return our app from wechat client.
if ([absoluteString hasPrefix:@"https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb"] && ![absoluteString hasSuffix:[NSString stringWithFormat:@"redirect_url=xdx.%@://",CompanyFirstDomainByWeChatRegister]]) {
decisionHandler(WKNavigationActionPolicyCancel);
#warning Note : The string "xiaodongxie.cn://" must be configured by wechat background. It must be your company first domin. You also should configure "URL types" in the Info.plist file.
// 1. If the url contain "redirect_url" : We need to remember it to use our scheme replace it.
// 2. If the url not contain "redirect_url" , We should add it so that we will could jump to our app.
// Note : 2. if the redirect_url is not last string, you should use correct strategy, because the redirect_url's value may contain some "&" special character so that my cut method may be incorrect.
NSString *redirectUrl = nil;
if ([absoluteString containsString:@"redirect_url="]) {
NSRange redirectRange = [absoluteString rangeOfString:@"redirect_url"];
endPayRedirectURL = [absoluteString substringFromIndex:redirectRange.location+redirectRange.length+1];
redirectUrl = [[absoluteString substringToIndex:redirectRange.location] stringByAppendingString:[NSString stringWithFormat:@"redirect_url=xdx.%@://",CompanyFirstDomainByWeChatRegister]];
}else {
redirectUrl = [absoluteString stringByAppendingString:[NSString stringWithFormat:@"&redirect_url=xdx.%@://",CompanyFirstDomainByWeChatRegister]];
}
NSMutableURLRequest *newRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:redirectUrl] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:XDX_URL_TIMEOUT];
newRequest.allHTTPHeaderFields = request.allHTTPHeaderFields;
newRequest.URL = [NSURL URLWithString:redirectUrl];
[webView loadRequest:newRequest];
return;
}
// Judge is whether to jump to other app.
if (![scheme isEqualToString:@"https"] && ![scheme isEqualToString:@"http"]) {
decisionHandler(WKNavigationActionPolicyCancel);
if ([scheme isEqualToString:@"weixin"]) {
// The var endPayRedirectURL was our saved origin url's redirect address. We need to load it when we return from wechat client.
if (endPayRedirectURL) {
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:endPayRedirectURL] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:XDX_URL_TIMEOUT]];
}
}else if ([scheme isEqualToString:[NSString stringWithFormat:@"xdx.%@",CompanyFirstDomainByWeChatRegister]]) {
}
BOOL canOpen = [[UIApplication sharedApplication] canOpenURL:request.URL];
if (canOpen) {
[[UIApplication sharedApplication] openURL:request.URL];
}
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}