iOS Swift中WKWebView的userContentController无法接收网页回调
iOS端WKWebView无法接收Web端已有JS的点击回调
网页上有点击按钮,Web端已实现对应JavaScript逻辑,但iOS端的userContentController收不到WebView的点击回调。从iOS端注入JS时能正常收到回调,但想直接复用Web端现有JS,当前配置无效。
相关代码
1. iOS注入JS可正常工作的代码
override func viewDidLoad() { super.viewDidLoad() let preferences = WKPreferences() let contentController = WKUserContentController() preferences.javaScriptEnabled = true let source: String = """ window.onload = function() { document.addEventListener("click", function(evt) { var tagClicked = document.elementFromPoint(evt.clientX, evt.clientY); if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.getAccessToken) { window.webkit.messageHandlers.Android.postMessage(JSON.stringify({ properties: { unique_key: "some_unique_key_value" } })); } }); } """ let script: WKUserScript = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: true) contentController.addUserScript(script) let configuration = WKWebViewConfiguration() configuration.preferences = preferences configuration.userContentController = contentController configuration.userContentController.add(self, name: "Android") let webAppInterface = WebAppInterface(viewController: self) self.webView = WKWebView(frame: self.view.frame, configuration: configuration) webView.allowsBackForwardNavigationGestures = true self.webView.uiDelegate = self self.webView.navigationDelegate = self self.webView.scrollView.delegate = self self.view = webView }
2. 尝试使用Web端已有JS的iOS代码
override func viewDidLoad() { super.viewDidLoad() // 初始化WKPreferences并启用JavaScript let preferences = WKPreferences() preferences.javaScriptEnabled = true // 创建WKUserContentController let contentController = WKUserContentController() // 创建WKWebViewConfiguration并设置偏好和内容控制器 let configuration = WKWebViewConfiguration() configuration.preferences = preferences configuration.userContentController = contentController // 添加消息处理器接收Web端消息 let webAppInterface = WebAppInterface(viewController: self) configuration.userContentController.add(webAppInterface, name: "Android") // 使用配置初始化WKWebView self.webView = WKWebView(frame: self.view.frame, configuration: configuration) webView.allowsBackForwardNavigationGestures = true self.webView.uiDelegate = self self.webView.navigationDelegate = self self.webView.scrollView.delegate = self self.view = webView }
3. WebAppInterface代码
import UIKit import WebKit class WebAppInterface: NSObject, WKScriptMessageHandler { weak var viewController: UIViewController? init(viewController: UIViewController) { self.viewController = viewController } func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { guard let messageBody = message.body as? String else { return } postMessage(message: messageBody) } func postMessage(message: String) { do { if let data = message.data(using: .utf8), let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let properties = jsonObject["properties"] as? [String: Any], let uniqueKey = properties["unique_key"] as? String { } } catch { print("解析JSON错误: \(error)") } } }
排查与解决方案
1. 校验Web端JS的核心调用逻辑
- 确保Web端代码里调用的是
window.webkit.messageHandlers.Android.postMessage(...),消息名严格区分大小写,必须和iOS端注册的"Android"完全一致 - 增加环境判断,避免非iOS环境报错:
if (window.webkit?.messageHandlers?.Android) { window.webkit.messageHandlers.Android.postMessage(JSON.stringify({ properties: { unique_key: "your_unique_value" } })); }
2. 修复消息处理器的生命周期问题
你在viewDidLoad中创建的WebAppInterface是局部变量,会被ARC自动释放,导致无法接收消息。需要将其改为类成员变量:
class YourViewController: UIViewController { // 声明为成员变量,防止被提前释放 private var webAppInterface: WebAppInterface! override func viewDidLoad() { super.viewDidLoad() // ...其他配置代码 webAppInterface = WebAppInterface(viewController: self) configuration.userContentController.add(webAppInterface, name: "Android") // ...初始化WebView } }
3. 验证Web端JS的执行时机
- 确保Web端的点击事件在DOM加载完成后绑定,比如放在
DOMContentLoaded或window.onload回调中,避免DOM未就绪导致事件绑定失效 - 通过Safari开发者工具调试WebView,在Web端的点击回调中添加
console.log,确认点击时是否执行到了postMessage逻辑
4. 兼容消息格式的多种情况
iOS端当前只处理String类型的消息体,但Web端可能直接传递JSON对象(而非JSON字符串),导致解析失败。修改代码兼容两种情况:
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { var jsonObject: [String: Any]? // 兼容直接传JSON对象和JSON字符串两种格式 if let bodyDict = message.body as? [String: Any] { jsonObject = bodyDict } else if let bodyString = message.body as? String, let data = bodyString.data(using: .utf8) { do { jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] } catch { print("解析JSON字符串失败: \(error)") } } guard let properties = jsonObject?["properties"] as? [String: Any], let uniqueKey = properties["unique_key"] as? String else { print("消息格式不符合预期") return } // 这里处理获取到的uniqueKey }
5. 确认WebView基础配置
- 确保
preferences.javaScriptEnabled = true已正确设置 - 检查是否有其他WKUserScript或页面逻辑阻止了点击事件冒泡,导致Web端的点击回调无法触发
内容的提问来源于stack exchange,提问作者Kushagra Chandra
相关产品推荐
相关产品推荐

