web-dev-qa-db-ja.com

Swiftui WkWebViewがURLの変更を検出します

私はSwift学習者です。私は構造体であるSwiftuiと働いています、私はWkWebViewを実装し、その中にURLが動的に変化しています。私はこれらの変更されたURLをキャッチしなければなりませんが、私が試してみたソリューションは機能していません。

例: https://stackoverflow.com/a/48273950/1008824 このコードブロックを試してみましたが、それは機能していて、いくつかのコンパイラエラーを与えます:

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

Class Struct ContentViewでクラスプロトコル 'nsObjectProtocol'エラーに準拠できないクラスのタイプがありません...

WebViewModelという名前のWebViewのObservableObjectモデルクラスを作成するだけです。

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

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

そしてまた輸入されます

import WebKit
import Combine
 _

その後、このコードスニペットをコピーします

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

そしてあなたの眺めについて

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

}

だからこのようにあなたは他の人に応答を委任することができます。

6
Akhtar

これを使用して、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)
}
 _
4
umer farooqi

キー/値の観測を使用して、WKWebViewのURLプロパティへの変更を検出できます。

UIViewRePresemperにwkwebviewをラップする簡単な例です。

プロパティを変更しているため、UIViewRePresentableは構造体ではなくfinal classです。

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

その後、WebViewを保持しているコンテナのonReceive()でURL変更された通知を聞くことができます。

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