我有一个自定义的 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 个选项:
我想要的是删除打开链接选项并添加我自己的。我对此很困惑,所以非常感谢任何帮助:)
我建议使用 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
}
}