【问题标题】:Initialize member in view struct在视图结构中初始化成员
【发布时间】:2021-03-27 18:54:46
【问题描述】:

我想在 SwiftUI 中使用带有 JavaScript 处理的 WKWebView。从Swift Variables Initialization,我正在执行以下操作:(我正在使用https://github.com/kylehickinson/SwiftUI-WebView 为SwiftUI 中的WKWebView 提供一个包装器,它还添加了有价值的布局约束。)

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

但后来我从Instance member cannot be used on type 得知这不起作用,因为闭包没有对 self 的引用。我需要 WKWebView 有专用的配置对象,所以我不能只使用其他构造函数。我需要参考它来做evaluateJavaScript

如何做到这一点?

编辑 1:添加 body 并提及用于包装 WKWebView 的框架。

编辑 2:添加了代码以阐明我需要通过 WKScriptMessageHandlerWKWebView 到本机应用程序的两种方式通信(以便在 HTML 文档准备好时得到通知)和从本机应用程序到WKWebView via evaluateJavaScript(在 HTML 文档准备好时传输数据)。

【问题讨论】:

  • WKWebView 包装到 UIViewRepresentable 中,就像在 stackoverflow.com/a/59790493/12299030 中一样。
  • @Asperi 在 struct WebView 中,您使用的是var webview: WKWebView = WKWebView(),但我需要使用带有自定义配置的构造函数。那我不会遇到同样的问题吗? (我已经使用github.com/kylehickinson/SwiftUI-WebView 将 WKWebView 包装到 UIViewRepresentable 中。)
  • 这里是备用stackoverflow.com/a/60173992/12299030。你可以使用任何适合你的。
  • @Asperi 感谢您的解决方案。我想指出,由于配置是在包装器内完成的,所以如果我想用一组不同的 JS 方法制作另一个 WKWebView,我将不得不制作另一个包装器!另一个问题是我需要在我的ContentView 中引用WKWebView,以便我可以调用evaluateJavaScript

标签: ios swift swiftui


【解决方案1】:

一种可能的解决方案是在init中配置WKWebView

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

}

【讨论】:

  • 我刚刚想出了一个解决方案,将 myWebView 移动到 JSHandler 中,但是我不知道如何命名 JSHandler,因为它不仅处理 JavaScript 回调,而且还用作WKWebView 的包装器。这要好得多。感谢您使用message.webView? 而不是顺便引用ContentView 的提示。
  • 你不能使用对 ContentView 的引用,因为它不是引用类型,它会是一个副本。
  • 我没有意识到这一点。我认为将var contentView: ContentView? 放入JSHandler 就像我最初所做的工作一样,因为ContentView? 可能是nil
【解决方案2】:

只需将 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)
}()

【讨论】:

  • 这不适用于 SwiftUI 视图,因为它没有可修改的 self。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-28
  • 2015-02-19
  • 1970-01-01
相关资源
最近更新 更多