Zainicjuj element członkowski w strukturze widoku

Dec 17 2020

Chcę mieć WKWebView z obsługą JavaScript w SwiftUI. Od inicjalizacji zmiennych Swift wykonuję następujące czynności: (używamhttps://github.com/kylehickinson/SwiftUI-WebViewaby zapewnić opakowanie dla WKWebViewSwiftUI, które również dodaje cenne ograniczenia dotyczące układu).

struct ContentView: View {

    var body: some View {
        WebView(webView: myWebView)
        .onAppear {
            let url = Bundle.main.url(forResource: "index", withExtension: "html")!
            myWebView.loadFileURL(url, allowingReadAccessTo: url)
            let request = URLRequest(url: url)
            myWebView.load(request)
        }
    }

    class JSHandler : NSObject, WKScriptMessageHandler {
        var contentView: ContentView?

        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            print("documentReady")
            contentView!.myWebView.evaluateJavaScript("<Long Script to Transfer Data>") { (result, error) in
            }
        }
    }

    let myJSHandler = JSHandler()

    var myWebView: WKWebView = {
        let config = WKWebViewConfiguration()
        let controller = WKUserContentController()
        controller.add(myJSHandler , name: "documentReady")
        config.userContentController = controller
        return WKWebView(frame: .zero, configuration: config)
    }()
}

Ale potem dowiedziałem się od elementu członkowskiego instancji nie można użyć na typie, że to nie działa, ponieważ zamknięcie nie ma odniesienia do siebie. Potrzebuję WKWebView, aby mieć dedykowany obiekt konfiguracyjny, więc nie mogę po prostu użyć innego konstruktora. Potrzebuję odniesienia do tego, żeby to zrobić evaluateJavaScript.

Jak to działa?

EDYCJA 1 : Dodaj bodyi wspomnij o strukturze używanej do zawijania WKWebView.

EDYCJA 2 : Dodano kod wyjaśniający, że potrzebuję dwukierunkowej komunikacji z WKWebViewaplikacji natywnej za pośrednictwem WKScriptMessageHandler(aby otrzymać powiadomienie, gdy dokument HTML jest gotowy) iz aplikacji natywnej do WKWebViewprzez evaluateJavaScript(aby przesłać dane, gdy dokument HTML jest gotowy).

Odpowiedzi

1 Asperi Dec 17 2020 at 15:42

Jednym z możliwych rozwiązań jest skonfigurowanie WKWebView w init

struct ContentView: View {
    private var myWebView: WKWebView

    init() {
        let config = WKWebViewConfiguration()
        let controller = WKUserContentController()
        controller.add(myJSHandler , name: "documentReady")
        config.userContentController = controller
        myWebView = WKWebView(frame: .zero, configuration: config)
    }

    var body: some View {
        WebView(webView: myWebView)
        .onAppear {
            let url = Bundle.main.url(forResource: "index", withExtension: "html")!
            myWebView.loadFileURL(url, allowingReadAccessTo: url)
            let request = URLRequest(url: url)
            myWebView.load(request)
        }
    }

    class JSHandler : NSObject, WKScriptMessageHandler {

        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            print("documentReady")
            message.webView?.evaluateJavaScript("<Long Script to Transfer Data>") { (result, error) in
            }
        }
    }

    let myJSHandler = JSHandler()

}
Arun Dec 17 2020 at 11:48

Po prostu ustaw myWebView lazyzmienną, dzięki temu jsHandler zostanie zainicjowany przed WebView.

lazy var myWebView: WKWebView = {
    let config = WKWebViewConfiguration()
    let controller = WKUserContentController()
    controller.add(myJSHandler , name: "documentReady")
    config.userContentController = controller
    return WKWebView(frame: .zero, configuration: config)
}()