iOS原生内嵌H5支付

282 阅读2分钟

一、需求

在原生App内镶嵌H5页,由H5页面调起支付

  1. WebView加载H5页面(一般是订单页)
  2. 点击支付,调起支付App客户端进行支付
  3. 支付完成,返回APP

二、微信H5支付

1. 调起微信的项目设置

选中TARGETS一栏,在info中的LSApplicationQueriesSchemes添加weixin,已添加过的可以忽略此步骤

2. 后台通过微信统一下单接口生成下单url

web端通过url请求微信统一下单接口 例如:h5点击【立即支付】按钮,h5通过订单参数创建微信订单,返回相应的支付链接(wx.tenpay.com/cgi-bin/mmp…

3. 拦截WKWebView加载的微信支付统一下单链接, 将redirect_url参数修改为唤起自己App的URLScheme

image.png

4. 跳转 微信支付

image.png

5. URL Types配置

选中TARGETS一栏,在info中的URL Types添加一项,URL Schemes 填写www.xxx.cn

和 redirect_url 一致,为了能使微信回调打开App

6. 微信支付取消或完成回调打开App

AppDelegate

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
        
        if url.scheme == "www.xxx.cn" {
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: kNotifaication_Name_WXPay_H5), object: nil)
            
            return true
        }
        return false
    }

WebViewController

// 在viewDidLoad中监听
NotificationCenter.default.addObserver(self, selector: #selector(dealWXH5PayResult), name: NSNotification.Name(rawValue: kNotifaication_Name_WXPay_H5), object: nil)

@objc func dealWXH5PayResult() {
    // 查询订单信息
}

在app 以下是实现代码:

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        
        guard let url = navigationAction.request.url else {
            decisionHandler(.allow)
            return
        }
        // 拦截微信支付
        let absoluteString = url.absoluteString
        let redirect_url = "www.xxx.cn%3A%2F%2Fwxpaycallback%2F" //www.xxx.cn://wxpaycallback/
        // 拦截微信支付统一下单链接,修改 redirect_url 参数为自定义 URL Scheme
        if absoluteString.hasPrefix("https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb"),
           !absoluteString.hasSuffix("redirect_url=\(redirect_url)") {
            decisionHandler(.cancel)
            
            let redirectUrl: String
            if absoluteString.contains("redirect_url=") {
                if let redirectRange = absoluteString.range(of: "redirect_url=") {
                    redirectUrl = absoluteString[..<redirectRange.lowerBound] +
                    "redirect_url=\(redirect_url)"
                } else {
                    redirectUrl = absoluteString + "redirect_url=\(redirect_url)"
                }
            } else {
                redirectUrl = absoluteString + "&redirect_url=\(redirect_url)"
            }
     
            guard let newUrl = URL(string: redirectUrl) else { return }
            var newRequest = URLRequest(url: newUrl, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 30)
            newRequest.allHTTPHeaderFields = navigationAction.request.allHTTPHeaderFields
            webView.load(newRequest)
            
            return
        }
        // 跳转 微信支付
        if url.scheme == "weixin" {
            decisionHandler(.cancel)
            let canOpen = UIApplication.shared.canOpenURL(navigationAction.request.url!)
            if canOpen {
                UIApplication.shared.open(navigationAction.request.url!)
            }
            return
        }
        decisionHandler(.allow)
    }

三、支付宝支付

支付宝支付相对简单

1. 拦截支付宝H5支付
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        
        guard let url = navigationAction.request.url else {
            decisionHandler(.allow)
            return
        }
        // 支付宝支付
        if url.host == "mclient.alipay.com" {
            decisionHandler(.cancel)
            AlipaySDK.defaultService().payInterceptor(withUrl: navigationAction.request.url?.absoluteString, fromScheme: "QKYC") { [weak self] reponse in
                guard let strongSelf = self else {return}
                // 处理支付成功与否
                strongSelf.dealShopAlipayReponse(reponse)
            }
            
            return
        }
}

支付宝 h5 支付转 native 支付接口

//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////支付宝 h5 支付转 native 支付接口////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
/**
 *  从h5链接中获取订单串并支付接口(自版本15.4.0起,推荐使用该接口)
 *
 *  @param urlStr     拦截的 url string
 *
 *  @return YES为成功获取订单信息并发起支付流程;NO为无法获取订单信息,输入url是普通url
 */
- (BOOL)payInterceptorWithUrl:(NSString *)urlStr
                   fromScheme:(NSString *)schemeStr
                     callback:(CompletionBlock)completionBlock;

2. 在AppDelegate 检测支付宝打开App
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
    
    /// 支付宝支付
    if url.host == "safepay" {
        AlipaySDK.defaultService().processOrder(withPaymentResult: url, standbyCallback: nil)
        return true
    }
    return false
}

四、参考