URL变更后WKUserContentController的消息接收方法未触发
问题分析与解决方案
核心问题拆解
你遇到的didReceive message仅首次触发的情况,主要由两个原因导致:
- 数据类型不匹配:网页脚本用
JSON.stringify(e.data)将消息转为字符串,但原生代码直接尝试把message.body强转为[String: AnyObject],类型不匹配导致后续代码直接返回,看起来像是方法未触发。 - 页面跳转后事件监听失效:若问卷是多页面跳转(非单页应用),虽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
相关产品推荐
相关产品推荐

