You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Swift如何监听WKWebView中网页发送的window.postMessage消息?

没问题,这事儿我熟!电商APP里用WKWebView处理下单支付后监听网页的window.postMessage回调是非常常见的需求,我给你一套完整的Swift实现方案,直接就能落地:

完整实现步骤

1. 配置WKWebView并注入拦截脚本

首先,我们需要给WKWebView配置消息处理器,同时注入一段JS脚本——因为WKWebView默认监听的是webkit.messageHandlers的消息,而网页用的是全局的window.postMessage,所以得把网页的postMessage消息转发到我们的处理器上。

import WebKit

class OrderPayViewController: UIViewController, WKScriptMessageHandler {
    private var webView: WKWebView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupWebView()
        loadPayPage()
    }
    
    private func setupWebView() {
        // 初始化WKWebView配置
        let config = WKWebViewConfiguration()
        let userContentController = WKUserContentController()
        
        // 注册消息处理器,名字"orderCallback"要和后面JS里的对应
        userContentController.add(self, name: "orderCallback")
        
        // 注入JS脚本:拦截window.postMessage并转发给APP
        let interceptScript = """
        // 保存原生postMessage方法,避免覆盖后影响网页内部逻辑
        const originalPostMessage = window.postMessage;
        window.postMessage = function(message, targetOrigin, transfer) {
            // 把消息转发给APP的WKWebView处理器
            window.webkit.messageHandlers.orderCallback.postMessage(message);
            // 执行原生postMessage逻辑(如果网页本身有其他监听,保留这个很重要)
            originalPostMessage(message, targetOrigin, transfer);
        };
        """
        let userScript = WKUserScript(source: interceptScript, 
                                     injectionTime: .atDocumentStart, 
                                     forMainFrameOnly: true)
        userContentController.addUserScript(userScript)
        
        config.userContentController = userContentController
        
        // 创建并添加WKWebView到页面
        webView = WKWebView(frame: view.bounds, configuration: config)
        view.addSubview(webView)
        
        // 适配安全区域(可选,根据你的布局调整)
        webView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            webView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
        ])
    }
    
    private func loadPayPage() {
        // 替换成你的下单支付网页URL
        guard let payUrl = URL(string: "https://your-shop.com/pay") else { return }
        webView.load(URLRequest(url: payUrl))
    }
}

2. 实现消息接收与处理逻辑

接下来实现WKScriptMessageHandler协议的方法,接收网页发来的消息,并执行APP内的后续操作:

// MARK: - WKScriptMessageHandler
extension OrderPayViewController {
    func userContentController(_ userContentController: WKUserContentController, 
                               didReceive message: WKScriptMessage) {
        // 只处理我们注册的"orderCallback"消息
        guard message.name == "orderCallback" else { return }
        
        // 解析消息内容(根据网页实际发送的格式调整,这里假设是字符串)
        switch message.body {
        case let successMsg as String where successMsg == "order_paid":
            // 订单支付成功:比如跳转订单详情、弹出成功提示
            print("订单已支付成功!")
            showSuccessAlert()
            navigateToOrderDetail()
        case let cancelMsg as String where cancelMsg == "order_canceled":
            // 订单取消:返回上一页或关闭当前页面
            print("用户取消了订单")
            navigationController?.popViewController(animated: true)
        default:
            print("收到未知回调消息:\(message.body)")
        }
    }
    
    // 示例:弹出成功提示
    private func showSuccessAlert() {
        let alert = UIAlertController(title: "支付成功", message: "你的订单已完成支付", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default))
        present(alert, animated: true)
    }
    
    // 示例:跳转到订单详情页
    private func navigateToOrderDetail() {
        let detailVC = OrderDetailViewController()
        navigationController?.pushViewController(detailVC, animated: true)
    }
}

3. 避免内存泄漏的关键操作

WKWebView对WKScriptMessageHandler的引用是强引用,如果直接用ViewController作为处理器,可能会导致内存泄漏。可以用一个弱引用代理类来解决:

// 弱引用代理类,避免WKWebView强引用ViewController
class WeakScriptMessageProxy: NSObject, WKScriptMessageHandler {
    weak var delegate: WKScriptMessageHandler?
    
    init(delegate: WKScriptMessageHandler) {
        self.delegate = delegate
        super.init()
    }
    
    func userContentController(_ userContentController: WKUserContentController, 
                               didReceive message: WKScriptMessage) {
        delegate?.userContentController(userContentController, didReceive: message)
    }
}

然后修改注册处理器的代码:

// 原来的userContentController.add(self, name: "orderCallback") 替换成:
userContentController.add(WeakScriptMessageProxy(delegate: self), name: "orderCallback")

同时,记得在ViewController销毁时移除处理器:

deinit {
    webView.configuration.userContentController.removeScriptMessageHandler(forName: "orderCallback")
    print("OrderPayViewController已销毁")
}

测试小技巧

你可以在网页里加个测试按钮,快速验证回调是否生效:

<button onclick="window.postMessage('order_paid', '*')">模拟支付成功</button>
<button onclick="window.postMessage('order_canceled', '*')">模拟取消订单</button>

点击这些按钮,就能看到APP里对应的逻辑是否执行啦。

内容的提问来源于stack exchange,提问作者KP26

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:15:45