解決方案:
- 在微信支付管理后臺注冊一級域名,比如 company.com
- 在APP工程配置中設置URL Scheme,比如 A.company.com(A你可以隨便寫,后面的域名得和1.中一致)
- 在webView代理方法中攔截微信下單請求(注意是下單請求不是下單返回結果!!!),在這個請求的基礎上生成新的請求,新的請求追加或修改參數redirect_url為你的URLScheme,即redirect_url=URLEncode(A.company.com://),cancel掉原來的請求,webView加載這個新的請求。
具體的:
需要攔截的請求前綴為,https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb
UIWebView在 webView:shouldStartLoadWithRequest:navigationType: 代理方法中攔截
WKWebView在 webView:decidePolicyForNavigationAction:decisionHandler: 代理方法中攔截
#pragma mark -
#pragma mark ============== webview相關 回調及加載 ==============
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSLog(@"截取到URL:%@",request.URL);
if ([[request.URL absoluteString] rangeOfString:kAlipay_url].length != 0) {
//新版本的H5攔截支付對老版本的獲取訂單串和訂單支付接口進行合并,推薦使用該接口
YXWeakSelf
BOOL isIntercepted = [[AlipaySDK defaultService] payInterceptorWithUrl:[request.URL absoluteString] fromScheme:@"zanxiaoqu" callback:^(NSDictionary *result) {
// 處理支付結果
NSLog(@"%@", result);
// isProcessUrlPay 代表 支付寶已經處理該URL
if ([result[@"isProcessUrlPay"] boolValue]) {
// returnUrl 代表 第三方App需要跳轉的成功頁URL
NSString* urlStr = result[@"returnUrl"];
[weakSelf loadWithUrlStr:urlStr];
}
}];
if (isIntercepted) {
return NO;
}
return YES;
}else if ([[request.URL absoluteString] hasPrefix:kWXPay_url]) {
NSDictionary *headers = [request allHTTPHeaderFields];
BOOL hasReferer = [headers objectForKey:@"Referer"]!=nil;
if (hasReferer) {
// .. is this my referer?
return YES;
} else {
// relaunch with a modified request
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSURL *url = [request URL];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[request setHTTPMethod:@"GET"];
[request setValue:@"xxx.com://" forHTTPHeaderField: @"Referer"];
[self.webView loadRequest:request];
});
});
return NO;
}
}
return YES;
}
(可選)微信支付結束(可能不是真正結束后面會細說)會發起redirect_url的重定向,webView攔截 request.URL.scheme 包含 company.com:// 的請求,在這里可以做一些后續操作,比如 刷新頁面,通知前端支付完成等。如果支付跳轉后出現白屏問題,可以在這里處理,比如干掉webView或刷新。
如這里微信H5下單接口參數返回redirect_url路徑的情況,我們可以將url轉字典,判斷字典中是否有返回的redirect_url字段,進行截取在去下單,這樣從支付界面在返回app就不會再返回到Safari瀏覽器中了
NSMutableString *mString = [NSMutableString stringWithString:[request.URL absoluteString]];
NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:[self dictionaryWithUrlString:mString]];
// 判斷字典中是否有返回的redirect_url
if ([[dic allKeys] containsObject:@"redirect_url"]) {
[dic removeObjectForKey:@"redirect_url"];
}
NSString *urlStr = [NSString stringWithFormat:@"%@?prepay_id=%@&package=%@",kWXPay_url,dic[@"prepay_id"],dic[@"package"]];
[self loadWithUrlStr:urlStr];
/**
url 轉字典
*/
-(NSDictionary *)dictionaryWithUrlString:(NSString *)urlStr
{
if (urlStr && urlStr.length && [urlStr rangeOfString:@"?"].length == 1) {
NSArray *array = [urlStr componentsSeparatedByString:@"?"];
if (array && array.count == 2) {
NSString *paramsStr = array[1];
if (paramsStr.length) {
NSMutableDictionary *paramsDict = [NSMutableDictionary dictionary];
NSArray *paramArray = [paramsStr componentsSeparatedByString:@"&"];
for (NSString *param in paramArray) {
if (param && param.length) {
NSArray *parArr = [param componentsSeparatedByString:@"="];
if (parArr.count == 2) {
[paramsDict setObject:parArr[1] forKey:parArr[0]];
}
}
}
return paramsDict;
}else{
return nil;
}
}else{
return nil;
}
}else{
return nil;
}
}
需要注意的問題:
- 微信H5下單接口(https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb)請求header中有個Referer字段,如果這個請求中沒有redirect_url參數,微信支付結束后默認回調Referer字段中地址
- Referer頭和redirect_url中的域名,都必須在微信后臺注冊過
- redirect_url回調并不可靠,可能微信支付還沒結束就回調了。
微信官方文檔對redirect_url的描述:
由于設置redirect_url后,回跳指定頁面的操作可能發生在:1,微信支付中間頁調起微信收銀臺后超過5秒 2,用戶點擊“取消支付“或支付完成后點“完成”按鈕。因此無法保證頁面回跳時,支付流程已結束,所以商戶設置的redirect_url地址不能自動執行查單操作,應讓用戶去點擊按鈕觸發查單操作
支付完成返回app后
有人提問:就是通過這種方式,跳轉微信支付,成功或者取消,返回自己的app后,怎么判斷是成功,取消,失敗的情況 ?
這里給出的建議:無法判斷成功還是失敗。唯一的方式就是回來之后請求自己的后臺接口去判斷這筆訂單是否成功
本文參考:
iOS微信H5支付無法返回APP解決方案