iOS微信H5支付没法返回APP解决方案

本文只讨论已成功调起微信支付后,没法返回本身的APP的问题,iOS微信H5支付不在讨论范围内。提供下列参考:
微信H5支付官方文档
微信H5支付官方Demophp

本文实现的效果:你的App->微信客户端->支付或取消->你的App
此方案支持多App,不一样的App添加处理后不会出现返回混乱的状况。html

另附,iOS支付宝H5支付没法返回APP解决方案web

解决思路

微信官方文档中关于“回调页面”有这么一段话:api

正常流程用户支付完成后会返回至发起支付的页面,如需返回至指定页面,则能够在MWEB_URL后拼接上redirect_url参数,来指定回调页面。微信

如,您但愿用户支付完成后跳转至www.wechatpay.com.cn,则能够作以下处理:
假设您经过统一下单接口获到的
MWEB_URL= https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx20161110163838f231619da20804912345&package=1037687096
则拼接后的地址为
MWEB_URL= https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx20161110163838f231619da20804912345&package=1037687096&redirect_url=https%3A%2F%2Fwww.wechatpay.com.cnmarkdown

微信H5支付,在中间页面的URL上提供了一个redirect_url参数,用于指定支付结束后的回调页面(默认是没有redirect_url参数的,微信会取请求头中referer参数的值做为回调页)。微信客户端会经过[[UIApplication sharedApplication] openURL:url]方法来返回回调页。若是咱们把redirect_ur设置成咱们App的URLSchemes是否是就能够返回咱们的App了?ide

解决方案

  1. 在微信商户后台(微信商户平台-产品中心-开发配置-H5支付(最下面那个))注册一级域名,好比 company.com。

这里的company.com请和你微信下单时的一级域名保持一致,即与微信中间页wx.tenpay.com**请求头**中的Referer字段对应的值一致。由于在微信中间页会去校验Referer和redirect_url的值是否在微信后台注册过。 2. 在APP工程配置中设置URL Scheme,好比 A.company.com(A你能够随便写,后面的域名得和1.中一致) 3. 在webView代理方法中拦截微信中间页请求(注意是请求不是返回结果),在这个请求的基础上新建一个请求,追加参数redirect_url=URLEncode(A.company.com://),cancel掉原来的请求,webView从新加载这个新的请求。oop

//以WKWebView为例(下面的代码可能不严谨,只是表达一个思路,请根据本身实际状况调整)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    NSURLRequest *request = navigationAction.request;
    //下面这个这个字符串不要直接写在代码中,不然会被苹果机审扫描到pay字段,致使被拒绝。能够自行加密处理或让后台返回
    NSString *wxPre = @"https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb";
    if ([request.URL.absoluteString hasPrefix:wxPre] && [request.URL.absoluteString rangeOfString:@"redirect_url"].length==0) {
        //开始微信支付会走这里
        //将要请求微信中间页,且中间页没有追加过redirect_url参数,追加redirect_url
        NSMutableURLRequest *newRequest = [[NSMutableURLRequest alloc] init];
        newRequest.allHTTPHeaderFields = request.allHTTPHeaderFields;
        NSString *newURLStr = nil;
        //TODO: 对newURLStr追加参数redirect_url=URLEncode(@"A.company.com://")
        newRequest.URL = [NSURL URLWithString:newURLStr];
        [webView loadRequest:newRequest];
        decisionHandler(WKNavigationActionPolicyCancel);
    }
    else if ([request.URL.scheme rangeOfString:@"company.com"].length!=0) {
        //微信支付结束(完成\取消\超时)后会走这里
        //TODO: 关闭微信中间页,好比dismiss webViewController,或[webView goBack]
    }
    else {
      decisionHandler(WKNavigationActionPolicyAllow);
    }
}
复制代码
  1. 微信支付结束后,你的webView会发起重定向到redirect_url的请求,即会请求"company.com://",拦截这个请求关闭微信中间页。(后文会细说)

须要注意的问题

  1. Referer头和redirect_url中的域名,都必须在微信后台注册过。不然微信中间页会报错“商家存在未配置的参数,请联系商家解决”。常见错误类型
  2. redirect_url须要连同冒号反斜杠一块儿URLEncode处理。
  3. 微信支付完成回调redirect_url的时机并不可靠,可能微信支付还没结束就回调了。

微信官方文档对redirect_url的描述:
因为设置redirect_url后,回跳指定页面的操做可能发生在:1,微信支付中间页调起微信收银台后超过5秒 2,用户点击“取消支付“或支付完成后点“完成”按钮。所以没法保证页面回跳时,支付流程已结束,因此商户设置的redirect_url地址不能自动执行查单操做,应让用户去点击按钮触发查单操做post

  1. 拦截微信中间页请求的前缀字符串不要直接写在代码里,不然会被机审扫描到"pay"字段致使被拒,请自行加密处理或后台返回。
  2. 微信后台注册一级域名的缘由是,这样能够支持"多App",你的第一个App的URLScheme叫A.company.com,第二个App的URLScheme叫B.company.com,而不用再次去微信后台注册域名了。

微信支付返回后白屏问题

白屏问题我之前也没搞清楚缘由,只知道怎么规避,此次整理这篇博客时又好好研究了一下,终于弄清除缘由了。微信支付

现象:
首先,不使用这篇文章中的方法时,微信支付结束后,手动回到App,不会有白屏的问题。
其次,若是使用了这篇文章中的方法,有些读者反映,虽然微信支付结束后可以自动跳回App,可是App会整个白屏,没法继续操做。

添加redirect_url后白屏的缘由

微信中间页wx.tenpay.com/cgi-bin/mmp…

window.onload = function() {
...省略
    var url = "weixin://wap/pay?prepayid%3Dwx18xxxxxxxxx&package=156xxxxxx&noncestr=157xxxxx&sign=719bxxxxxxxxxxx";
    var redirect_url = "A.company.com://";
    top.location.href = url;

    if (redirect_url) {
        setTimeout(function() {
            top.location.href = redirect_url;
        },
        5000);
    } else {
        setTimeout(function() {
            window.history.back();
        },
        5000);
    }
}
复制代码

看完是否是就豁然开朗了。

白屏缘由总结:
发起微信支付时,会把页面重定向到中间页,也能够理解为校验页,有错误提示错误缘由(以下图),没错误就是纯白色页面同时拉起微信客户端支付,中间页的js代码里面会判断是否有redirect_url的值,若是没有则5s后返回上一页window.history.back(),也就返回支付前的H5页面了;若是redirect_url有值,则重定向到redirect_url页面,而redirect_url=“A.company.com://“,重定向会失败,就停留在微信中间页了,这就是白屏的缘由。

微信中间页

白屏问题如何解决

在支付结束后关闭微信中间页便可解决白屏问题。
有两个点,一个是支付结束的时机,一个是关闭微信中间页。

支付结束的时机,我上文提到过

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    NSURLRequest *request = navigationAction.request;
    if ([request.URL.scheme rangeOfString:@"company.com"].length!=0) {
        //微信支付结束(完成\取消\超时)后会走这里
        //TODO: 关闭微信中间页,好比dismiss webViewController,或[webView goBack]
    }
    ...
}
复制代码

关闭微信中间页,我这里提供两种思路:

  1. 新开一个原生的webViewController来加载你的收银台页面(选择微信、支付宝那个页面),在支付结束后dismiss这个webViewController。
  2. 借鉴微信的思路,在支付结束后,[webView goBack]来返回原来的页面。

常见问题自查

1.按文章步骤操做后,App跳转微信后,支付或取消没有返回App而是跳转到Safari

  1. 检查redirect_url中的域名(有冒号反斜杠)、App URLScheme(没有冒号反斜杠),是否填写正确,是否一致,微信商户后台是否注册了对应的域名。
  2. 检查是不是URLEncode(redirect_url)的过程出现了问题,若是你URLEncode后仍然有 :// ,这是不对的,你能够拿你URLEncode后的值和在线URLEncode网站对比差别。

若是以为这篇文章对你有帮助,请点个赞吧。若是有疑问能够关注个人公众号给我留言。
转载请注明出处,谢谢!

参考连接:
iOS 解决微信h5支付没法直接返回APP的问题
iOS实现微信外部H5支付完成后返回原APP(多APP也可实现)

相关文章
相关标签/搜索