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

求助:在WKWebView中拦截修改粘贴内容及脚本消息未触发问题

问题解决思路与实现方案

先直接给你解决核心问题,再拆解细节:


问题1:didReceiveScriptMessage未触发的原因

你的JavaScript事件绑定写错了!addEventListener接收的事件名是paste,而不是onpaste——onpaste是DOM0级事件的写法(比如document.onpaste = function() {}),用addEventListener时必须去掉前缀on。

另外要确保WKWebView的配置里启用了JavaScript(默认是开启的,但显式设置更稳妥)。


问题2:拦截并替换粘贴内容的两种可行方案

根据你需要执行耗时异步操作的需求,推荐用「JS拦截事件 + 原生处理内容 + JS插入结果」的协作方案,下面是Swift的完整实现:

步骤1:配置WKWebView并注入正确的监听脚本

import WebKit

class YourViewController: UIViewController {
    private var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 配置用户内容控制器
        let userContentController = WKUserContentController()
        
        // 修正后的粘贴监听JS:拦截事件、阻止默认行为、发送内容给原生
        let pasteJSSource = """
        document.addEventListener('paste', function(event) {
            // 先阻止默认粘贴,避免原始内容直接插入
            event.preventDefault();
            // 获取剪贴板的文本内容(富文本用'text/html')
            const pasteContent = event.clipboardData.getData('text');
            // 把内容发给原生App
            window.webkit.messageHandlers.ComposerListener.postMessage({
                type: 'paste',
                content: pasteContent
            });
        });
        """
        
        let pasteScript = WKUserScript(source: pasteJSSource,
                                       injectionTime: .atDocumentEnd,
                                       forMainFrameOnly: false) // 设为false监听所有iframe的粘贴
        
        userContentController.add(self, name: "ComposerListener")
        userContentController.addUserScript(pasteScript)
        
        // 初始化WebView配置
        let webViewConfig = WKWebViewConfiguration()
        webViewConfig.userContentController = userContentController
        webViewConfig.preferences.javaScriptEnabled = true // 显式启用JS
        
        // 创建WebView
        webView = WKWebView(frame: view.bounds, configuration: webViewConfig)
        webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(webView)
        
        // 加载测试页面(替换成你的目标页面)
        webView.load(URLRequest(url: URL(string: "https://example.com")!))
    }
    
    // 销毁时移除消息处理器,避免内存泄漏
    deinit {
        webView.configuration.userContentController.removeScriptMessageHandler(forName: "ComposerListener")
    }
}

步骤2:实现WKScriptMessageHandler协议处理消息

extension YourViewController: WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        guard message.name == "ComposerListener",
              let body = message.body as? [String: Any],
              let type = body["type"] as? String,
              let rawContent = body["content"] as? String else {
            return
        }
        
        if type == "paste" {
            print("收到粘贴内容:\(rawContent)")
            
            // 执行耗时异步操作(比如网络请求、复杂计算)
            DispatchQueue.global(qos: .background).async {
                // 模拟耗时处理:比如把内容转成大写
                let processedContent = "【处理后】\(rawContent.uppercased())"
                
                // 回到主线程,把处理后的内容插入到WebView光标位置
                DispatchQueue.main.async {
                    let insertScript = """
                    const selection = window.getSelection();
                    if (selection.rangeCount > 0) {
                        const range = selection.getRangeAt(0);
                        range.deleteContents();
                        const textNode = document.createTextNode('\(processedContent)');
                        range.insertNode(textNode);
                        // 调整光标到内容末尾,提升用户体验
                        range.setStartAfter(textNode);
                        range.setEndAfter(textNode);
                        selection.removeAllRanges();
                        selection.addRange(range);
                    }
                    """
                    self.webView.evaluateJavaScript(insertScript, completionHandler: nil)
                }
            }
        }
    }
}

备选方案:纯原生监听(无需JS)

如果你不想用JavaScript,也可以通过监听UIPasteboard的变化来实现,但这种方式无法精准判断粘贴操作是否发生在WKWebView内,适合全局监听场景:

// 在viewDidLoad中添加监听
NotificationCenter.default.addObserver(self, selector: #selector(pasteboardChanged), name: UIPasteboard.changedNotification, object: nil)

// 处理剪贴板变化
@objc private func pasteboardChanged() {
    guard let pasteContent = UIPasteboard.general.string else { return }
    // 执行耗时操作,之后手动修改剪贴板内容(用户粘贴时会用修改后的内容)
    DispatchQueue.global().async {
        let processedContent = "处理后:\(pasteContent)"
        DispatchQueue.main.async {
            UIPasteboard.general.string = processedContent
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 08:47:35