SwiftUI WKWebView 检测 url 更改

Alp*_*ğlu 7 ios swift wkwebview swift5

我是一个快速学习者。我使用 SwiftUI,它是一个结构体,我必须实现一个 WKWebView,并且其中的 url 正在动态更改。我必须捕捉这些不断变化的网址,但我尝试过的解决方案不起作用。

例如:https : //stackoverflow.com/a/48273950/10088243 我试过这个代码块,但它不起作用,它给了我一些编译器错误:

import SwiftUI
import WebKit

struct ContentView: UIViewRepresentable, WKNavigationDelegate {

    let request = URLRequest(url: URL(string: "https://apple.com")!)

    func makeUIView(context: Context) -> WKWebView  {
    let preferences = WKPreferences()
    preferences.javaScriptEnabled = true
    preferences.javaScriptCanOpenWindowsAutomatically = true

    let configuration = WKWebViewConfiguration()
    configuration.preferences = preferences
    let webView = WKWebView(frame: .zero, configuration: configuration)
    webView.allowsBackForwardNavigationGestures = true


    return webView
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 
 // 'override' can only be specified on class membe
  if keyPath == #keyPath(WKWebView.url) {
    print("### URL:", self.webView.url!)
  }

  if keyPath == #keyPath(WKWebView.estimatedProgress) {
    // When page load finishes. Should work on each page reload.
    if (self.webView.estimatedProgress == 1) {
      print("### EP:", self.webView.estimatedProgress)
    }
  }
}

func updateUIView(_ uiView: WKWebView, context: Context) {
    uiView.load(request)
}

func webViewDidFinishLoad(webView : WKWebView) {
    print("Loaded: \(String(describing: webView.url))")
}

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    print("Loaded: \(String(describing: webView.url))")
    //progressView.isHidden = true
}

func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
    //progressView.isHidden = false
    print("Loaded: \(String(describing: webView.url))")
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Run Code Online (Sandbox Code Playgroud)

我在 struct ContentView 行有一个非类类型“ContentView”不能符合类协议“NSObjectProtocol”错误...

Akh*_*tar 14

您可以简单地创建一个名为“WebViewModel”的 webview 的 ObservableObject 模型类,例如

class WebViewModel: ObservableObject {
    @Published var link: String
    @Published var didFinishLoading: Bool = false

    init (link: String) {
        self.link = link
    }
} 
Run Code Online (Sandbox Code Playgroud)

并且还进口

import WebKit
import Combine
Run Code Online (Sandbox Code Playgroud)

然后复制此代码片段

struct SwiftUIWebView: UIViewRepresentable {
    @ObservedObject var viewModel: WebViewModel

    let webView = WKWebView()

    func makeUIView(context: UIViewRepresentableContext<SwiftUIWebView>) -> WKWebView {
        self.webView.navigationDelegate = context.coordinator
        if let url = URL(string: viewModel.link) {
            self.webView.load(URLRequest(url: url))
        }
        return self.webView
    }

    func updateUIView(_ uiView: WKWebView, context: UIViewRepresentableContext<SwiftUIWebView>) {
        return
    }

    class Coordinator: NSObject, WKNavigationDelegate {
        private var viewModel: WebViewModel

        init(_ viewModel: WebViewModel) {
            self.viewModel = viewModel
        }

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            //print("WebView: navigation finished")
            self.viewModel.didFinishLoading = true
        }
    }

    func makeCoordinator() -> SwiftUIWebView.Coordinator {
        Coordinator(viewModel)
    }
}



struct SwiftUIWebView_Previews: PreviewProvider {
    static var previews: some View {
        
        SwiftUIWebView(viewModel: WebViewModel(link: "https://google.com"))
        //WebView(request: URLRequest(url: URL(string: "https://www.apple.com")!))
    }
}
Run Code Online (Sandbox Code Playgroud)

在你看来

struct AnyView: View {
    @ObservedObject var model = WebViewModel(link: "https://www.wikipedia.org/")

    
var body: some View {
        
        
    NavigationView {
       SwiftUIWebView(viewModel: model)
                if model.didFinishLoading {
                    //do your stuff 
                }
        }
   }}
Run Code Online (Sandbox Code Playgroud)

所以通过这种方式你可以得到其他代表的回应。

  • 谢谢,这是一个非常好的答案,但目前我不会在生产中使用 SwiftUI。我回到故事板。 (2认同)
  • @Akhtar 你能修复 AnyView 中的缩进吗? (2认同)

ume*_*oqi 5

您使用它来代表 WKNavigationProtocol 来执行(例如允许或取消 URL 加载)您的操作

    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    if let host = navigationAction.request.url?.host {
        if host.contains("facebook.com") {
            decisionHandler(.cancel)
            return
        }
    }

    decisionHandler(.allow)
}
Run Code Online (Sandbox Code Playgroud)


Alp*_*ğlu -1

我找到了一个非常好的解决方案来解决我的问题。我将把它发布在这里。也许有人想看它并且可能对他们有用。

observe.observation = uiView.observe(\WKWebView.url, options: .new) { view, change in
    if let url = view.url {
        // do something with your url
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 抱歉,这个答案没有描述如何实施。“观察。观察”?你从哪里得到的?你把它放在哪里?实际完整的工作代码怎么样? (2认同)