Initialisieren Sie das Mitglied in der Ansichtsstruktur

Dec 17 2020

Ich möchte eine WKWebView mit JavaScript-Verarbeitung in SwiftUI haben. Bei der Initialisierung von Swift-Variablen mache ich Folgendes: (Ich verwendehttps://github.com/kylehickinson/SwiftUI-WebViewum einen Wrapper für WKWebViewin SwiftUI bereitzustellen, der auch wertvolle Layouteinschränkungen hinzufügt.)

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

Aber dann habe ich von Instance gelernt, dass Mitglieder nicht für Typen verwendet werden können , die nicht funktionieren, da der Abschluss keinen Bezug zu sich selbst hat. Ich brauche das WKWebView, um ein dediziertes Konfigurationsobjekt zu haben, damit ich nicht einfach den anderen Konstruktor verwenden kann. Ich brauche einen Verweis darauf evaluateJavaScript.

Wie funktioniert das?

BEARBEITEN 1 : Fügen Sie das hinzu bodyund erwähnen Sie das Framework, das zum Umschließen von WKWebView verwendet wird.

BEARBEITEN 2 : Code hinzugefügt, um zu verdeutlichen, dass ich eine bidirektionale Kommunikation von WKWebViewzur nativen App über WKScriptMessageHandler(um benachrichtigt zu werden, wenn das HTML-Dokument fertig ist) und von der nativen App zur WKWebViewvia evaluateJavaScript(um Daten zu übertragen , wenn das HTML-Dokument bereit ist) benötige .

Antworten

1 Asperi Dec 17 2020 at 15:42

Eine mögliche Lösung besteht darin, WKWebView in zu konfigurieren 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

Machen Sie myWebView einfach zu einer lazyVariablen. Dadurch wird sichergestellt, dass der jsHandler vor WebView initialisiert wird.

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