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

iOS16与Xcode14.2中UITextView.textDidChangeNotification失效问题求助

问题原因

iOS 16 对 WKWebView 的内部文本输入组件实现做了变更,不再依赖 UITextView 作为底层输入容器。旧版 iOS 中,WKWebView 的可编辑区域本质是嵌套的 UITextView,因此 UITextView.textDidChangeNotification 会被触发;但 iOS 16 后苹果替换了内部实现,该通知不再与 WKWebView 的编辑行为绑定,导致原有监听方式失效。

解决办法与替代方案

方案1:JavaScript 注入 + WKScriptMessageHandler(推荐)

通过向 WKWebView 注入 JS 代码监听网页文本输入事件,再通过消息回调传递到原生层,这是不受 iOS 版本变更影响的稳定方案。

步骤如下:

  1. 让控制器遵循 WKScriptMessageHandler 协议,实现消息接收方法:
extension YourViewController: WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "textChanged" {
            textDidChanged()
        }
    }
}
  1. 初始化 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)
  1. 控制器销毁时移除消息处理器,避免内存泄漏:
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 16:37:36