iOS中使用WKWebview支持h5跳轉(zhuǎn)支付客戶端

大致的業(yè)務(wù)場(chǎng)景是這樣的:我們的客戶端APP本身不包含支付SDK,但是在APP內(nèi)打開的HTML5是包含了第三方支付的,而且在Safari內(nèi)是可以正常調(diào)起支付寶/微信客戶端進(jìn)行支付的,然而在APP的webview內(nèi)打開同樣的URL則毫無反應(yīng)。
原因大致是支付寶/微信的h5支付sdk沒有對(duì)客戶端支持,當(dāng)然也存在一些系統(tǒng)的限制。
現(xiàn)在就來解決一下這個(gè)問題。

柳暗

經(jīng)過稍微的查詢和參考,解決方案其實(shí)非常簡(jiǎn)單,只需要在WKWebView的代理方法func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)內(nèi)監(jiān)聽微信/支付寶的特定前綴URL,然后使用openUrl方法打開這個(gè)URL就可以觸發(fā)支付寶/微信的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)
}

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

花明

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

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支付回調(diào)應(yīng)該是服務(wù)端提供的一個(gè)h5地址,因此支付完成后默認(rèn)是跳轉(zhuǎn)到了Safari,在APP內(nèi)進(jìn)行的支付,我們要換掉這個(gè)回調(diào),變成我們自己的。

大致步驟是:

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

具體代碼大致如下:

let wxpayScheme = "ios.abc.com://"
// 去除原有的URL回調(diào)地址,換成自己的配置
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 {
                // 給請(qǐng)求頭加上Referer字段
                let mRequest = NSMutableURLRequest(url: finalUrl)
                mRequest.setValue(wxpayScheme, forHTTPHeaderField: "Referer")

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

替換的過程有一點(diǎn)繞,其實(shí)就是找到相應(yīng)字段替換掉,有更好地寫法。
嘗試了一下,可以成功跳轉(zhuǎn)回來了,但是新的問題又出現(xiàn)了→_→

又一村

因?yàn)樘鎿Q了微信支付的回調(diào),h5的跳轉(zhuǎn)可能會(huì)出現(xiàn)白屏的問題,上面的文章也有提到。
我根據(jù)自己的實(shí)際情況采用了直接強(qiáng)制調(diào)用webView.goBack(),因?yàn)楸旧淼腍5頁面自帶了支付等待完成頁,支付完成后返回APP,確認(rèn)一下支付狀態(tài)就好了。
需要注意的是,調(diào)用微信支付5秒后,webview會(huì)收到一個(gè)鏈接調(diào)整,截獲然后進(jìn)行后退就好:

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

不過這個(gè)白屏問題可能會(huì)根據(jù)本身h5的不同而采取不同的解決方案,所以這個(gè)應(yīng)該并非萬全之策。

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 由于公司的業(yè)務(wù)需要,為了節(jié)省申請(qǐng)開通微信支付的時(shí)間和人力,公司決定使用微信h5支付。這樣即節(jié)省了時(shí)間,同時(shí)以后所有...
    大寶來巡山閱讀 7,947評(píng)論 1 9
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,188評(píng)論 25 708
  • 番外短篇之~~辰塵(二) 傾絡(luò)一路馬不停蹄的趕到昆侖虛,剛進(jìn)大門便看到少綰正匆匆往外走,傾絡(luò)趕緊給少綰請(qǐng)安,少綰看...
    墨冉_諾諾閱讀 2,837評(píng)論 6 16
  • 現(xiàn)在天氣漸漸轉(zhuǎn)涼,火鍋成為了人們的最愛吃的美食。中國人吃火鍋的歷史,要追溯到上古時(shí)期。根據(jù)考古出土的資料顯示,距今...
    猜哪生活圈閱讀 314評(píng)論 0 0
  • 我喜歡的人 他不需要是個(gè)蓋世英雄 他只要是他自己 我希望 我們的相遇 會(huì)有金屬相碰的聲音 ...
    汪陳閱讀 149評(píng)論 2 3

友情鏈接更多精彩內(nèi)容