iOS中使用WKWebview支持h5跳轉支付客戶端

大致的業務場景是這樣的:我們的客戶端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。具體代碼大致如下:

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    pushCurrentSnapshotViewWithRequest(request: navigationAction.request)

    guard let curUrl = navigationAction.request.url else {
        decisionHandler(.allow); return
    }

    if curUrl.absoluteString.hasPrefix("alipay://alipayclient/") || curUrl.absoluteString.hasPrefix("weixin://"){
        decisionHandler(WKNavigationActionPolicy.cancel)
        UIApplication.shared.openURL(url)
        return
    }
    decisionHandler(WKNavigationActionPolicy.allow)
}

開心,居然這么簡單。
然后…emmmmm,跳是可以正常跳了,但是好像支付結束后無法跳回APP。
冷靜分析一下,我們都知道iOS內的應用間跳轉,基本都是通過scheme的方式,跳出去如此,要返回也是如此。

花明

先看下支付寶支付:
捕獲支付寶web支付跳轉鏈接如 alipay://alipayclient/?{"requestType":"SafePay","fromAppUrlScheme":"alipays","dataString":"h5_route_token=\"shierRZ25\"&is_h5_route=\"true\""}
發現其中只要將fromAppUrlScheme改為APP內配置的scheme,即可正確跳轉回應用。具體代碼示例如下:

fileprivate func handleAlipayUrl(url: URL) -> URL? {
    if url.absoluteString.hasPrefix("alipay://alipayclient/") {
        // 更換scheme
        var decodePar = url.query ?? ""
        decodePar.urlDecode()
        var dict = JSON(parseJSON: decodePar)
        dict["fromAppUrlScheme"] = "xproject"

        if let strData = try? JSONSerialization.data(withJSONObject: dict.dictionaryObject ?? [:], options: []) {
            var param = String(data: strData, encoding: .utf8)
            param?.urlEncode()

            let finalStr = "alipay://alipayclient/?\(param ?? "")"
            if let finalUrl = URL(string: finalStr) {
                return finalUrl
            }
        }
        return url
    }
    return nil
}

似乎挺順利,再看一下微信,微信的h5支付回調應該是服務端提供的一個h5地址,因此支付完成后默認是跳轉到了Safari,在APP內進行的支付,我們要換掉這個回調,變成我們自己的。

大致步驟是:

  • 工程文件添加Scheme,內容為[APP本地配置的scheme]
  • 捕獲跳轉鏈接 https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb,將其中其中的redirect_url參數換成[APP本地配置的scheme]
  • 重新發起請求,給請求頭加上Referer字段,內容為[APP本地配置的scheme]
  • 使用openUrl發起微信客戶端調用
    這里參考了這篇文章 http://www.lxweimin.com/p/c1973aacc774
    需要注意的一點就是,[APP本地配置的scheme]需要是http的URL形式,而且根域名是要包含在微信支付后臺填寫的白名單內的,譬如白名單域名是abc.com,你可以將你的scheme設置為ios.abc.com,否則也不會生效。

具體代碼大致如下:

let wxpayScheme = "ios.abc.com://"
// 去除原有的URL回調地址,換成自己的配置
if curUrl.absoluteString.hasPrefix("https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb") {
    if var comps = URLComponents(string: curUrl.absoluteString) {
        var needChange = false
        for (idx, item) in (comps.queryItems ?? []).enumerated() {
            if item.name == "redirect_url" && item.value != wxpayScheme {
                needChange = true
                comps.queryItems?.remove(at: idx)
                break
            }
        }
        if needChange {
            comps.queryItems?.append(URLQueryItem(name: "redirect_url", value: wxpayScheme))
            if let finalUrl = comps.url {
                // 給請求頭加上Referer字段
                let mRequest = NSMutableURLRequest(url: finalUrl)
                mRequest.setValue(wxpayScheme, forHTTPHeaderField: "Referer")

                decisionHandler(WKNavigationActionPolicy.cancel)
                webView.load(mRequest as URLRequest)
                return
            }
        }
    }
}

替換的過程有一點繞,其實就是找到相應字段替換掉,有更好地寫法。
嘗試了一下,可以成功跳轉回來了,但是新的問題又出現了→_→

又一村

因為替換了微信支付的回調,h5的跳轉可能會出現白屏的問題,上面的文章也有提到。
我根據自己的實際情況采用了直接強制調用webView.goBack(),因為本身的H5頁面自帶了支付等待完成頁,支付完成后返回APP,確認一下支付狀態就好了。
需要注意的是,調用微信支付5秒后,webview會收到一個鏈接調整,截獲然后進行后退就好:

if curUrl.absoluteString.hasPrefix(wxpayScheme) {
    // 進入空白頁,強制后退
    decisionHandler(WKNavigationActionPolicy.cancel)
    webView.goBack()
    return
}

不過這個白屏問題可能會根據本身h5的不同而采取不同的解決方案,所以這個應該并非萬全之策。

參考文章:
iOS 解決微信h5支付無法直接返回APP的問題
iOS微信H5支付無法返回APP解決方案

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容