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

URL变更后WKUserContentController的消息接收方法未触发

问题分析与解决方案

核心问题拆解

你遇到的didReceive message仅首次触发的情况,主要由两个原因导致:

  1. 数据类型不匹配:网页脚本用JSON.stringify(e.data)将消息转为字符串,但原生代码直接尝试把message.body强转为[String: AnyObject],类型不匹配导致后续代码直接返回,看起来像是方法未触发。
  2. 页面跳转后事件监听失效:若问卷是多页面跳转(非单页应用),虽WKUserScript默认会在新页面注入,但可能存在注入时机或事件绑定的隐性问题;若是单页路由变化,原监听虽有效,但可能网页端消息发送逻辑有变动。

具体解决方案

方案1:修正数据传递与解析逻辑

去掉脚本中的JSON.stringify,直接传递原始数据,让原生可以直接解析为字典:

private lazy var webView: WKWebView = {
    let config = WKWebViewConfiguration()
    let source = """
        window.addEventListener('message', function(e) {
            window.webkit.messageHandlers.message.postMessage(e.data);
        });
        """
    // 仅主框架注入即可,设为true更高效
    let script = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
    config.userContentController.addUserScript(script)
    config.userContentController.add(self, name: "message")
    
    let webView = WKWebView(frame: .zero, configuration: config)
    webView.translatesAutoresizingMaskIntoConstraints = false
    webView.addObserver(self, forKeyPath: "URL", options: .new, context: nil)
    webView.navigationDelegate = self
    return webView
}()

同时更新消息接收方法,兼容多种数据类型:

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    print("收到消息:\(message.name)")
    // 优先解析字典类型
    if let dict = message.body as? [String: Any] {
        print("消息内容:\(dict)")
        // 根据网页约定的字段判断是否为结果页,比如"isResultPage"
        if dict["isResultPage"] as? Bool == true {
            // 执行到达最终结果页的业务逻辑
        }
    } else if let rawString = message.body as? String {
        // 兼容字符串类型消息
        print("字符串消息:\(rawString)")
    }
}

方案2:兼容JSON序列化的字符串消息

如果网页端必须使用JSON.stringify,则在原生中手动反序列化字符串:

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    print("收到消息:\(message.name)")
    guard let jsonString = message.body as? String,
          let jsonData = jsonString.data(using: .utf8),
          let dict = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] else {
        return
    }
    print("消息内容:\(dict)")
    // 判断是否为结果页
    if dict["isResultPage"] as? Bool == true {
        // 处理结果页逻辑
    }
}

方案3:确保多页面跳转后脚本生效

若问卷是多页面跳转,可在页面加载完成后手动注入脚本,确保事件监听绑定成功:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    let source = """
        window.addEventListener('message', function(e) {
            window.webkit.messageHandlers.message.postMessage(e.data);
        });
        """
    webView.evaluateJavaScript(source) { _, error in
        if let error = error {
            print("脚本注入失败:\(error)")
        }
    }
}

额外辅助:通过URL判断结果页

除了监听postMessage,还可结合URL变化辅助判断:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "URL", let newURL = change?[.newKey] as? URL {
        print("当前URL:\(newURL.absoluteString)")
        // 根据结果页URL的特征判断,比如包含"result"关键词
        if newURL.absoluteString.contains("result") {
            // 执行结果页逻辑
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 13:05:39