Görünüm yapısında üyeyi başlat

Dec 17 2020

SwiftUI'de JavaScript işlemeli bir WKWebView'a sahip olmak istiyorum. Gönderen Swift Değişkenler Başlatma , ben aşağıdakileri yapıyorum: (kullanıyorumhttps://github.com/kylehickinson/SwiftUI-WebViewWKWebViewSwiftUI için değerli düzen kısıtlamaları da ekleyen bir sarmalayıcı sağlamak .)

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

Ancak daha sonra Instance üyesinden , kapanışın self'e referansı olmadığı için çalışmadığını tür üzerinde kullanılamayacağını öğrendim . WKWebView'a adanmış yapılandırma nesnesine ihtiyacım var, bu yüzden diğer kurucuyu kullanamam. Yapmak için bir referansa ihtiyacım var evaluateJavaScript.

Bu nasıl çalışır?

DÜZENLEME 1 : bodyWKWebView'ı sarmak için kullanılan çerçeveyi ekleyin ve bahsedin.

DÜZENLEME 2 : WKWebViewYerel uygulamadan WKScriptMessageHandler(HTML belgesi hazır olduğunda bildirim almak için) ve yerel uygulamadan WKWebViewyoluyla evaluateJavaScript(HTML belgesi hazır olduğunda verileri aktarmak için) iki yönlü iletişime ihtiyacım olduğunu açıklığa kavuşturmak için kod eklendi .

Yanıtlar

1 Asperi Dec 17 2020 at 15:42

Olası bir çözüm, WKWebView'ı 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

Sadece myWebView bir lazydeğişken yapın. Bu, jsHandler'ın WebView'dan önce başlatıldığından emin olmanızı sağlar.

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