WKWebView实现h5微信支付,并跳转回app

3,271 阅读1分钟
  1. info里添加url scheme,例:rd.company.com,添加微信白名单: wechat weixin

  2. 实现WKNavigationDelegate的代理方法,将支付地址中的redirect_url更换成rd.company.com://,记得要在设置的scheme后面加://,不然支付后不能跳转回app

    var redirect_url = "" //记录之前的redirect_url,支付完成后加载获取并显示支付结果
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
            
            var actionPolicy: WKNavigationActionPolicy = .allow
            guard let urlStr = navigationAction.request.url?.absoluteString.removingPercentEncoding else {return}
            let schemeUrl = "rd.company.com://"
            var finalStr = ""
            let wxPayPrefix = "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?"
            if urlStr.hasPrefix(wxPayPrefix), !urlStr.contains("redirect_url=\(schemeUrl)") {
                let tmpStr = urlStr.subString(start: wxPayPrefix.count, length: urlStr.count-wxPayPrefix.count)
                var strArray = tmpStr.components(separatedBy: "&")
                for (i, str) in strArray.enumerated() {
                    if str.hasPrefix("redirect_url") {
                        redirect_url = str.components(separatedBy: "redirect_url=").last ?? ""
                        strArray[i] = "redirect_url=\(schemeUrl)"
                        break
                    }
                }
                finalStr = wxPayPrefix + strArray.joined(separator: "&")
                actionPolicy = .cancel
                // 设置 Referer
                var request:URLRequest = NSURLRequest.init(url: URL.init(string: finalStr)!) as URLRequest
                request.httpMethod = "Get"
                request.setValue(schemeUrl, forHTTPHeaderField: "Referer")
                webView.load(request)
            }
            
            if urlStr.contains("weixin://wap/pay") {
                actionPolicy = .cancel
                if !UIApplication.shared.canOpenURL(URL(string: "weixin://")!) {
                    print("未安装微信")
                    return decisionHandler(actionPolicy)
                }
                if let url = URL(string: urlStr) {
                    if #available(iOS 10.0, *) {
                        UIApplication.shared.open(url, options: [:], completionHandler: nil)
                        UIApplication.shared.open(url, options: convertToUIApplicationOpenExternalURLOptionsKeyDictionary([:]), completionHandler: nil)
                    } else {
                        UIApplication.shared.openURL(url)
                    }
                }
            }
            return decisionHandler(actionPolicy)
        }
    
  3. appdelegate中实现

    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
           if url.scheme == "rd.company.com" {
                NotificationCenter.default.post(name: NSNotification.Name.init(rawValue: h5wxPayResult"), object: nil)
                return true
            }
        }
    
  4. 回到WKWebView显示的视图中接受通知

    NotificationCenter.default.addObserver(self, selector: #selector(gotoRedirect), name: NSNotification.Name.init("h5wxPayResult"), object: nil)
    

    加载之前记录的redirect_url获取支付结果

    @objc func gotoRedirect() {
            guard let url = URL(string: redirect_url) else {return}
            let request = URLRequest(url: url)
            webView.load(request)
     }
    
  5. 返回出现白屏问题,在返回的方法中实现

    func pop() {
         if webView.canGoBack {
             if let urlStr = webView.url?.absoluteString,
                 urlStr.hasPrefix("\(WebHost)/notarization/#/sign/ZL2020010217352263067701257") { //白屏页地址
                 for backItem in webView.backForwardList.backList where backItem.url.absoluteString == "\(WebHost)/notarization/#/list" { //需要返回地址
                     webView.go(to: backItem)
                 }
             }else {
                 webView.goBack()
             }
         } else {
             navigationController?.popViewController(animated: true)
         }
     }