ビュー構造体でメンバーを初期化します

Dec 17 2020

SwiftUIでJavaScriptを処理するWKWebViewが必要です。Swift Variables Initializationから、私は次のことを行っています:(私は使用していますhttps://github.com/kylehickinson/SwiftUI-WebViewWKWebViewSwiftUIでラッパーを提供し、貴重なレイアウト制約も追加します。)

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

しかし、インスタンスメンバーから、クロージャーが自分自身を参照していないため、これが機能しないことを型で使用できないことを学びました。WKWebViewに専用の構成オブジェクトが必要なので、他のコンストラクターを使用することはできません。するためにそれへの参照が必要ですevaluateJavaScript

これを機能させる方法は?

編集1bodyWKWebViewをラップするために使用されるフレームワークを追加して言及します。

編集2WKWebViewネイティブアプリからの双方向通信WKScriptMessageHandler(HTMLドキュメントの準備ができたときに通知を受け取るため)とネイティブアプリからWKWebView経由への双方向通信(HTMLドキュメントの準備ができたときにevaluateJavaScriptデータを転送するため)が必要であることを明確にするコードを追加しました。

回答

1 Asperi Dec 17 2020 at 15:42

考えられる解決策の1つは、で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

myWebViewをlazy変数にするだけです。これにより、jsHandlerが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)
}()