Inisialisasi anggota dalam tampilan struct

Dec 17 2020

Saya ingin memiliki WKWebView dengan penanganan JavaScript di SwiftUI. Dari Inisialisasi Variabel Swift , saya melakukan hal berikut: (Saya menggunakanhttps://github.com/kylehickinson/SwiftUI-WebViewuntuk menyediakan pembungkus WKWebViewdi SwiftUI yang juga menambahkan batasan tata letak yang berharga.)

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

Tapi kemudian saya belajar dari anggota Instance tidak dapat digunakan pada tipe yang ini tidak berfungsi karena closure tidak mengacu pada diri sendiri. Saya memerlukan WKWebView untuk mendedikasikan objek konfigurasi sehingga saya tidak bisa hanya menggunakan konstruktor lain. Saya perlu referensi untuk melakukannya evaluateJavaScript.

Bagaimana cara membuatnya bekerja?

EDIT 1 : Tambahkan bodydan sebutkan kerangka kerja yang digunakan untuk membungkus WKWebView.

EDIT 2 : Menambahkan kode untuk mengklarifikasi bahwa saya memerlukan komunikasi dua arah dari WKWebViewke aplikasi asli melalui WKScriptMessageHandler(untuk mendapatkan pemberitahuan ketika dokumen HTML siap) dan dari aplikasi asli ke WKWebViewmelalui evaluateJavaScript(untuk mentransfer data setelah dokumen HTML siap).

Jawaban

1 Asperi Dec 17 2020 at 15:42

Salah satu solusi yang mungkin adalah mengonfigurasi WKWebView di 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

Buat saja myWebView sebagai lazyvariabel, Ini memastikan bahwa jsHandler diinisialisasi sebelum 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)
}()