web-dev-qa-db-fra.com

SWIFTUI WKWebView Détecter la modification de l'URL

Je suis un Swift apprenant. Je travaille avec Swiftui, qui est une structure, je dois mettre en œuvre une WKWebView et, dans cela, une URL change de manière dynamique. Je dois attraper ces URL changeantes, mais Des solutions que j'ai essayées ne fonctionnent pas.

Par exemple: https://stackoverflow.com/a/48273950/1008824 J'ai essayé ce bloc de code mais cela ne fonctionne pas et cela me donne des erreurs de compilation:

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()
    }
}

J'ai un type de classement 'contentview' ne peut pas être conforme au protocole de classe "NSOBJUSTPROTOCOL" ERREUR AT LINE SHORT CONTENUVIEW ...

J'ai trouvé une très bonne solution à ma question. Je vais le poster ici. Peut-être que quelqu'un veut le voir et pourrait leur être utile.

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

Vous pouvez simplement créer une classe de modèle ObservableObject de WebView avec le nom "WebviewModel" comme

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

    init (link: String) {
        self.link = link
    }
} 

et aussi importer

import WebKit
import Combine

puis copiez ces extraits de code

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")!))
    }
}

et en vous voir

 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 
                }
   }
   }

}

donc, de cette façon, vous pouvez obtenir la réponse des déléguements des autres.

6
Akhtar

Vous pouvez utiliser l'observation de la clé/de la valeur pour détecter les modifications apportées à la propriété URL de WKWebView.

Voici un exemple simple d'emballage d'une WKWEBVIEW dans un UIViewrevisceptable.

Notez que parce que nous modifions une propriété, l'UIViewrePresentable est un final class plutôt qu'une structure.

import Combine
import SwiftUI
import WebKit

final class WebView: UIViewRepresentable {

    @Published var url: URL? = nil {
        didSet {
            if url != nil {
                willChange.send(url)
            }
        }
    }

    private let view = WKWebView()

    private var urlChangedObservation: NSKeyValueObservation?
    private let willChange = PassthroughSubject<URL?, Never>()

    func makeUIView(context: Context) -> WKWebView {
        return makeWebView()
    }

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

    func display(_ html: String) {
        self.view.loadHTMLString(html, baseURL: nil)
    }

    public func load(_ url: String) -> WebView {
        let link = URL(string: url)!
        let request = URLRequest(url: link)
        self.view.load(request)
        return self
    }

    func makeWebView() -> WKWebView {
        self.urlChangedObservation = self.view.observe(\WKWebView.url, options: .new) { view, change in
            if let url = view.url {
                self.url = url
            }
        }
        return self.view
    }
}

Vous pouvez ensuite écouter la notification modifiée par l'URL dans l'ONRECEIVE () du conteneur Holding the webview:

.onReceive(self.webview.$url) { url in
                    if let url = url {
                }
}
1
Gene Z. Ragan