iOS16与Xcode14.2中UITextView.textDidChangeNotification失效问题求助
问题原因
iOS 16 对 WKWebView 的内部文本输入组件实现做了变更,不再依赖 UITextView 作为底层输入容器。旧版 iOS 中,WKWebView 的可编辑区域本质是嵌套的 UITextView,因此 UITextView.textDidChangeNotification 会被触发;但 iOS 16 后苹果替换了内部实现,该通知不再与 WKWebView 的编辑行为绑定,导致原有监听方式失效。
解决办法与替代方案
方案1:JavaScript 注入 + WKScriptMessageHandler(推荐)
通过向 WKWebView 注入 JS 代码监听网页文本输入事件,再通过消息回调传递到原生层,这是不受 iOS 版本变更影响的稳定方案。
步骤如下:
- 让控制器遵循
WKScriptMessageHandler协议,实现消息接收方法:
extension YourViewController: WKScriptMessageHandler { func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { if message.name == "textChanged" { textDidChanged() } } }
- 初始化 WKWebView 时注册消息处理器并注入监听JS:
let userContentController = WKUserContentController() // 注册原生与网页的消息通道 userContentController.add(self, name: "textChanged") // 注入监听所有可编辑元素输入事件的JS代码 let jsScript = """ document.addEventListener('input', function(e) { const target = e.target; if (target.isContentEditable || target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') { window.webkit.messageHandlers.textChanged.postMessage(null); } }); """ let script = WKUserScript(source: jsScript, injectionTime: .atDocumentEnd, forMainFrameOnly: true) userContentController.addUserScript(script) let configuration = WKWebViewConfiguration() configuration.userContentController = userContentController // 初始化WKWebView let webView = WKWebView(frame: .zero, configuration: configuration)
- 控制器销毁时移除消息处理器,避免内存泄漏:
deinit { webView.configuration.userContentController.removeScriptMessageHandler(forName: "textChanged") }
方案2:监听页面导航完成事件(仅适用于非实时场景)
如果你的场景不需要实时监听输入过程,仅需在编辑完成后检查内容变化,可以配合 WKNavigationDelegate 实现:
extension YourViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { webView.evaluateJavaScript("document.body.innerText") { [weak self] result, error in guard let currentText = result as? String, let self = self else { return } if currentText != self.lastSavedText { self.textDidChanged() self.lastSavedText = currentText } } } }
注意:需提前设置 webView.navigationDelegate = self,并维护 lastSavedText 变量记录上一次的内容。
方案3:KVO 监听滚动视图内容尺寸(补充方案)
部分可编辑 WKWebView 在文本变化时会改变 scrollView 的内容尺寸,可通过 KVO 间接感知,但这种方式可靠性较低(文本换行但尺寸不变时无法触发):
override func viewDidLoad() { super.viewDidLoad() webView.scrollView.addObserver(self, forKeyPath: "contentSize", options: [.new], context: nil) } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if keyPath == "contentSize" && object as? UIScrollView == webView.scrollView { textDidChanged() } } deinit { webView.scrollView.removeObserver(self, forKeyPath: "contentSize") }
总结
优先选择方案1,它能实时、稳定地监听所有可编辑元素的文本变化,完全不受 iOS 版本内部实现变更的影响,也是苹果推荐的原生与网页交互方式。
内容的提问来源于stack exchange,提问作者normidar
相关产品推荐
相关产品推荐

