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

自定义WKWebView中如何修改长按链接菜单并添加自定义功能

解决方案

要实现长按链接时打印目标URL、移除系统默认的“在Safari中打开链接”选项并添加自定义选项,需要从JS事件拦截和WKWebView上下文菜单自定义两方面入手,以下是具体修改步骤:

1. 让NavigationState遵守WKUIDelegate

通过WKUIDelegate接管WebView的上下文菜单配置,修改类声明:

class NavigationState : NSObject, ObservableObject, WKNavigationDelegate, WKUIDelegate {
    // 原有代码保持不变
}

2. 修改WKWebView初始化逻辑

创建WebView时设置uiDelegate,同时添加消息处理器接收JS传递的链接信息:

@discardableResult func createNewWebView(withRequest request: URLRequest) -> WKWebView {
    let config = WKWebViewConfiguration()
    // 添加消息处理器,接收JS传递的链接数据
    config.userContentController.add(self, name: "linkLongPress")
    
    let wv = WKWebView(frame: .zero, configuration: config)
    wv.navigationDelegate = self
    wv.uiDelegate = self // 设置UIDelegate
    webViews.append(wv)
    selectedWebView = wv
    wv.load(request)
    return wv
}

3. 替换JS脚本,拦截所有链接的长按事件

将原有针对特定按钮的JS替换为监听所有<a>标签的长按事件,阻止默认行为并传递链接URL给原生:

// 在WebView的updateUIView方法中替换原有script
let script = """
document.querySelectorAll('a').forEach(link => {
    link.addEventListener('contextmenu', function(event) {
        event.preventDefault();
        // 将链接的href传递给原生
        window.webkit.messageHandlers.linkLongPress.postMessage(this.href);
    });
});
"""
let userScript = WKUserScript(source: script, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
webView.configuration.userContentController.addUserScript(userScript)

4. 存储长按的链接URL

在NavigationState中新增属性存储当前长按的链接:

class NavigationState : NSObject, ObservableObject, WKNavigationDelegate, WKUIDelegate {
    // 原有属性
    @Published var longPressedLinkURL: URL? // 新增:存储长按的链接URL
    
    // 原有方法
}

5. 处理JS传递的链接消息

修改消息处理方法,接收并存储链接URL,同时打印:

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    if message.name == "buttonLongPress" {
        print("Pressed")
        buttonLongPressPublisher.send()
    } else if message.name == "linkLongPress" {
        if let urlString = message.body as? String, let url = URL(string: urlString) {
            longPressedLinkURL = url
            // 打印长按的链接URL
            print("Long-pressed link URL: \(url)")
        }
    }
}

6. 自定义上下文菜单:移除系统选项+添加自定义选项

实现WKUIDelegate方法,过滤系统默认选项并添加自定义菜单项:

func webView(_ webView: WKWebView, contextMenuConfigurationForElement elementInfo: WKContextMenuElementInfo, completionHandler: @escaping (UIContextMenuConfiguration?) -> Void) {
    // 获取系统默认菜单配置
    webView.defaultContextMenuConfigurationForElement(elementInfo) { defaultConfig in
        var modifiedActions = [UIMenuElement]()
        
        // 过滤掉"在Safari中打开链接"选项
        if let defaultActions = defaultConfig?.menuItems {
            modifiedActions = defaultActions.filter { item in
                return item.title != NSLocalizedString("Open in Safari", comment: "")
            }
        }
        
        // 添加自定义菜单选项
        let customAction = UIAction(title: "我的自定义操作", image: UIImage(systemName: "star.fill")) { [weak self] _ in
            if let url = self?.longPressedLinkURL {
                // 自定义操作逻辑:比如打印URL或其他处理
                print("自定义操作触发,链接URL:\(url)")
            }
        }
        modifiedActions.append(customAction)
        
        // 构建新的菜单配置
        let modifiedConfig = UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
            UIMenu(title: "", children: modifiedActions)
        }
        
        completionHandler(modifiedConfig)
    }
}

7. 清理冗余代码

如果不再需要原有特定按钮的长按逻辑,可以删除buttonLongPressPublisher及对应JS脚本。


关键说明

  • JS拦截contextmenu事件,既可以传递链接信息给原生,也能配合系统菜单自定义控制行为。
  • 通过WKUIDelegate的上下文菜单配置方法,实现系统选项过滤和自定义菜单项添加。
  • 存储的长按链接URL可直接用于自定义操作的逻辑处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 14:55:12