如何在自定义 WKWebView 实现中打开新选项卡

问题描述 投票:0回答:1

我有一个自定义的 webview 实现,如下所示:

struct WebView : UIViewRepresentable {
    @ObservedObject var navigationState: NavigationState
    @Binding var proxy: GeometryProxy
    
    func makeUIView(context: Context) -> UIView  {
        return UIView()
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {
        guard let webView = navigationState.selectedWebView else {
            return
        }
        if webView != uiView.subviews.first {
            uiView.subviews.forEach { $0.removeFromSuperview() }
            
            webView.frame = CGRect(origin: .zero, size: proxy.size)
            uiView.addSubview(webView)
            
            // Inject JavaScript to capture long-press on a specific button
            let script = """
                document.querySelector('#specificButtonId').addEventListener('contextmenu', function(event) {
                    event.preventDefault();
                    window.webkit.messageHandlers.buttonLongPress.postMessage(null);
                });
                """
            let userScript = WKUserScript(source: script, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
            webView.configuration.userContentController.addUserScript(userScript)
        }
    }
}

class NavigationState : NSObject, ObservableObject {
    @Published var currentURL : URL?
    @Published var webViews : [WKWebView] = []
    @Published var selectedWebView : WKWebView?
    
    var buttonLongPressPublisher = PassthroughSubject<Void, Never>()
    var nextURL: URL?
    
    @discardableResult func createNewWebView(withRequest request: URLRequest) -> WKWebView {
        let wv = WKWebView()
        wv.navigationDelegate = self
        webViews.append(wv)
        selectedWebView = wv
        wv.load(request)
        return wv
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        currentURL = webView.url
    }
    
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        if let url = navigationAction.request.url {
            
            nextURL = url
        }
        decisionHandler(.allow)
    }
    
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "buttonLongPress" {
            print("Presssed")
            buttonLongPressPublisher.send()
        }
    }
    
}

struct WebViewWrapper: View {
    @ObservedObject var navigationState: NavigationState
    let proxy: GeometryProxy
    let isSideMenuAttached: Bool
    @Binding var width: Int
    @Binding var contextMenuVisible: Bool
    
    var body: some View {
        WebView(navigationState: navigationState, proxy: .constant(proxy))
            .frame(width: isSideMenuAttached ? proxy.size.width : proxy.size.width - CGFloat(width))
            .cornerRadius(15)
            .onReceive(navigationState.buttonLongPressPublisher) { _ in
                if let webView = navigationState.selectedWebView {
                    webView.evaluateJavaScript("document.URL") { result, _ in
                        if let urlString = result as? String, let url = URL(string: urlString) {
                            // Perform the desired action, e.g., print the URL
                            print("Long-pressed URL: \(url)")
                        }
                    }
                }
            }
    }
}

现在,我只想打印视图将要访问的下一个 URL。例如,如果我访问 apple.com,左上角有苹果徽标,我希望用户按住该位置并看到打印下一个 URL 的选项。目前,如果我这样做,我会看到 4 个选项:

  • 打开链接(指向 Safari,而不是我的应用程序中的新选项卡)
  • 添加到阅读列表
  • 复制链接
  • 分享

我想要的是删除打开链接选项并添加我自己的。我对此很困惑,所以非常感谢任何帮助:)

swiftui webkit
1个回答
0
投票

我建议使用 makeUIView 来制作 webview,而不是在导航状态下创建它们。状态应该只存储当前 URL、URL 历史记录等内容,您知道状态。

makeUIView() 应该创建 webview 并返回它而不是空的 UIView,并且每当任何状态更新时都会调用 updateView。您使用 updateView 加载新的 URL 等。

您需要在 WebView 中创建一个 Coordinator 类,并让该协调器符合 WKWebView 的委托。 (我相信你的情况是导航代表)。在 makeUIView() 中,将协调器指定为委托。例如

webview.navigationDelegate = context.coordinator

例如:

struct WebView : UIViewRepresentable {
…
    func makeUIView(context: Context) -> UIView  {
        let webView = WKWebView…
        …
        webView.navigationDelegate = context.coordinator
        return webview
    }

    func updateUIView(_ uiView: UIView, context: Context) {
        guard let webView = uiView as? WKWebView else { return }
        // update the webView based on navigation state
    }

    func makeCoordinator() -> Coordinator {
        Coordinator()
    }

    class Coordinator: WKNavigationDelegate {
        // implement navigation delegate methods here
    }
}

© www.soinside.com 2019 - 2024. All rights reserved.