iOS H5支付宝 微信支付.

iOS开发中, 如果不想接入支付的SDK 或者 商品只能走内购, 但是又不想要走内购(不想给苹果手续费...), 那么就可以考虑使用支付宝和微信的H5支付.

这里的支付宝支付和微信支付 指的是通过web页, 传给客户端包括订单和其他信息的字符串, 客户端拿到这个特殊的字符串, 进行处理, 然后通过scheme打开支付宝或者微信客户端进行支付.

写在前面:

一般通过WKWebView的

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

方法来拦截要加载的url, 支付宝支付带有订单信息的URL 前缀为 alipay 或者 alipays. 微信的是 https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb.
我们这样子写是有问题的. 这样子写递交审核, 机审的时候, 会扫描出来alipay tenpay的字眼, 可以判定你没有走内购而拒绝你的递交, 甚至会延迟审核. 所以我们要做的是, 把有关alipay 和 tenpay 这些字符串拆成一个个的字符, 然后用到的时候再进行组装比较, 这样子可以绕过苹果的机审.

进入正题
适配支付宝客户端支付:

支付宝支付比较简单一些, 因为 如果安装了支付宝 可以在支付宝客户端上面进行支付, 如果没有安装, 也可以在网页上面支付.
首先截取到支付宝支付加载的URL

// 某宝相关字符串
        let compareArrayCollect1: [Character] = ["a", "l", "i", "p", "a", "y"]
        let compareArrayCollect2: [Character] = ["a", "l", "i", "p", "a", "y", "s"]
        if loadURLString.hasPrefix(charArray: compareArrayCollect1) || loadURLString.hasPrefix(charArray: compareArrayCollect2) {
            //某宝 stringUrl 为webView所加载的url: navigationAction.request.url?.absoluteString.removingPercentEncoding
            if let url = stringUrl, let changeURL = self.changeURLSchemeStr(urlStr: url) {
                // 跳转
                UIApplication.shared.openURL(changeURL)
            }

        }

changeURLSchemeStr 方法作用是:

  • 对url进行解码.
  • 转换成字典.
  • 替换fromAppUrlScheme的值为当前app对应的scheme.
  • 再进行编码 并返回新的URL.
    其中替换fromAppUrlScheme 的作用是 跳转支付宝 交易结束之后, 支付宝要通过你app的scheme 跳回到你的app
    代码如下:
private func changeURLSchemeStr(urlStr: String) -> URL? {
        if urlStr.contains("fromAppUrlScheme") {
            guard var rmPerEncStr = urlStr.removingPercentEncoding else { return nil }
            guard let temDic = self.dictionaryWithUrlString(urlString: rmPerEncStr) else { return nil }
            guard let temValue = temDic["fromAppUrlScheme"] as? String else { return nil }
            rmPerEncStr = rmPerEncStr.replacingOccurrences(of: temValue, with: "yourAppScheme")
            guard let perEncodingStr = rmPerEncStr.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) else { return nil }
            return URL(string: perEncodingStr)
        }
        return nil
    }
private func dictionaryWithUrlString(urlString: String) -> [String: Any]? {
        guard urlString.count != 0 else { return nil }
        let array = urlString.components(separatedBy: "?")
        guard array.count == 2 else { return nil }
        guard let paramStr = array.last else { return nil }
        let rmPerEnStr = paramStr.removingPercentEncoding
        return rmPerEnStr?.convertToDictionary()
    }

微信支付

微信的H5支付稍微要麻烦一些. 主要麻烦的点在于设置 微信的回跳地址 redirect_url 和授权域名 Referer.

  • redirect_url 的设置最好设置为本app的urlScheme, Referer为后端或者产品在注册微信支付时所填写的授权域名.
  • redirect_url: 作用为 当app完成支付(不论是否支付成功), 所跳转的页面, 如果不设置, 那么支付完成之后就会直接跳转到Safari, 打开的是一个支付是否成功的验证页面, 设置redirect_url的目的为了支付完成之后 正常跳转到app 并在app中的web页面中打开支付是否成功的验证页面. 所以在这里也要记录一下原始的redirect_url. 用户回跳之后, 要加载显示的验证页面.
  • Referer: 官方文档上面有说明, Referer如果不设置, 跳转到微信, 打不开支付页面, 验证不通过.
if loadURLString.hasPrefix("https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb") && !loadURLString.contains("redirect_url=your_referer_name//paycallback/") {
            // 某信
            // 先判断有没有安装微信
            let someXinCollect: [Character] = ["w", "e", "i", "x", "i", "n", ":", "/", "/"]
            let someXinStr = String.charCollectTransToString(charArray: someXinCollect)
            guard let sonXinURL = URL(string: someXinStr) else { return false }
            if !UIApplication.shared.canOpenURL(sonXinURL) {
                showToast(text: "请安装微信客户端")
                return false
            }

如果当前加载的url的前缀有某信支付的连接并且不包含 “redirect_url=your_referer_name//paycallback/”的字符串, 那么先判断是否安装微信, 如果没有给出toast提示 需要安装微信客户端.

 // 拼接rturl
            var rtUrl: String = ""
            let authHost = "your_refere_name" //你的微信授权域名
            if loadURLString.contains(rtURLStr) {
                guard let redirectRange = loadURLString.range(of: rtURLStr) else { return true }
                let location: Int = loadURLString.distance(from: loadURLString.startIndex, to: redirectRange.lowerBound)
                rtUrl = loadURLString.substring(to: location - 1) + "\(rtURLStr)\(authHost):\(charCallbackCollectStr)"
                originalRtUrlStr = loadURLString.substring(from: location +
                    rtURLStr.count)
            } else {
                rtUrl = loadURLString + "\(rtURLStr)\(authHost):\(charCallbackCollectStr))" // 替换为你自己的授权域名(也就是你的scheme, 微信完成支付时 会按照这个scheme跳转回你的app)
            }
            guard let requestURL = URL(string: rtUrl) else { return true }
            var request = navigationAction.request
            request.url = requestURL
// 在这一步 设置request的header信息. 加入Referer 参数
            if var headerField = request.allHTTPHeaderFields {
                headerField["Referer"] = authHost
            }
            webView.load(request)
            return false

这一步主要做的工作是: 替换掉前端原本传过来redirect_url, 并且记录原始的redirect_url: originalRtUrlStr. 然后拼接好已经替换的loadURL, 设置request, 并且在请求头中加入Referer参数 进行重新加载.
下一步:

if loadURLString.hasPrefix(charArray: "your_referer_name") {
            guard let requestURL = URL(string: originalRtUrlStr) else { return false }
            var request = navigationAction.request
            request.url = requestURL
            webView.load(request)
            return false
        }
if loadURLString.contains("weixin://") {
            UIApplication.shared.openURL(loadURL)
        }
        return true

这一步是如果loadURL, 是以你的授权域名为开头, 那么就加载这个页面. (实际上是微信支付 验证是否成功的页面.), 最后如果加载的url是以weixin://开头, 这个链接就是带有微信支付信息的连接, 就打开微信进行支付操作.

注意: 以上字符串 如果有关alipay 或者 tenPay 这些字眼, 都要将其进行拆分成字符来表示, 判断的时候, 再用字符数组, 进行拼接. 这样子才能不被苹果扫描到有支付宝或者财付通支付.

你可能感兴趣的:(iOS H5支付宝 微信支付.)