大致的业务场景是这样的:我们的客户端APP本身不包含支付SDK,但是在APP内打开的HTML5是包含了第三方支付的,而且在Safari内是可以正常调起支付宝/微信客户端进行支付的,然而在APP的webview内打开同样的URL则毫无反应。
原因大致是支付宝/微信的h5支付sdk没有对客户端支持,当然也存在一些系统的限制。
现在就来解决一下这个问题。
柳暗
经过稍微的查询和参考,解决方案其实非常简单,只需要在WKWebView
的代理方法func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)
内监听微信/支付宝的特定前缀URL,然后使用openUrl
方法打开这个URL就可以触发支付宝/微信的scheme。具体代码大致如下:
1 | func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { |
开心,居然这么简单。
然后…emmmmm,跳是可以正常跳了,但是好像支付结束后无法跳回APP。
冷静分析一下,我们都知道iOS内的应用间跳转,基本都是通过scheme的方式,跳出去如此,要返回也是如此。
花明
先看下支付宝支付:
捕获支付宝web支付跳转链接如 alipay://alipayclient/?{"requestType":"SafePay","fromAppUrlScheme":"alipays","dataString":"h5_route_token=\"shierRZ25\"&is_h5_route=\"true\""}
发现其中只要将fromAppUrlScheme改为APP内配置的scheme,即可正确跳转回应用。具体代码示例如下:
1 | fileprivate func handleAlipayUrl(url: URL) -> URL? { |
似乎挺顺利,再看一下微信,微信的h5支付回调应该是服务端提供的一个h5地址,因此支付完成后默认是跳转到了Safari,在APP内进行的支付,我们要换掉这个回调,变成我们自己的。
大致步骤是:
- 工程文件添加Scheme,内容为[APP本地配置的scheme]
- 捕获跳转链接 https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb,将其中其中的redirect_url参数换成[APP本地配置的scheme]
- 重新发起请求,给请求头加上Referer字段,内容为[APP本地配置的scheme]
- 使用openUrl发起微信客户端调用
这里参考了这篇文章 https://www.jianshu.com/p/c1973aacc774
需要注意的一点就是,[APP本地配置的scheme]需要是http的URL形式,而且根域名是要包含在微信支付后台填写的白名单内的,譬如白名单域名是abc.com,你可以将你的scheme设置为ios.abc.com,否则也不会生效。
具体代码大致如下:
1 | let wxpayScheme = "ios.abc.com://" |
替换的过程有一点绕,其实就是找到相应字段替换掉,有更好地写法。
尝试了一下,可以成功跳转回来了,但是新的问题又出现了→_→
又一村
因为替换了微信支付的回调,h5的跳转可能会出现白屏的问题,上面的文章也有提到。
我根据自己的实际情况采用了直接强制调用webView.goBack()
,因为本身的H5页面自带了支付等待完成页,支付完成后返回APP,确认一下支付状态就好了。
需要注意的是,调用微信支付5秒后,webview会收到一个链接调整,截获然后进行后退就好:
1 | if curUrl.absoluteString.hasPrefix(wxpayScheme) { |
不过这个白屏问题可能会根据本身h5的不同而采取不同的解决方案,所以这个应该并非万全之策。