解决方案:
- 在微信支付管理后台注册一级域名,比如 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解决方案
网友评论