【问题标题】:WKWebView JavaScript communication on page load页面加载时的 WKWebView JavaScript 通信
【发布时间】:2019-05-28 13:17:04
【问题描述】:

编辑

以下示例可以工作。我犯了一个愚蠢的错误,没有在我的网络应用程序中调用正确的页面。我将把这个留在这里,让其他寻找如何做我正在做的事情的人。


我有 Native -> WKWebView JavaScript 通信为我的项目工作,除了一件事:当我的网页加载时,我无法识别 postMessage() 调用。

我添加了一个名为“contentLoaded”的消息处理程序,我试图从我的 webview 中像这样触发它:

window.addEventListener('load', (event) => {
    window.webkit.messageHandlers.contentLoaded.postMessage("content has loaded");
});

我也试过了:

window.addEventListener('DOMContentLoaded', (event) => {
    window.webkit.messageHandlers.contentLoaded.postMessage("content has loaded");
});

此外,我实际上使用的是 Vue.js,所以我也尝试像这样挂钩 Vue 的 created()mounted() 钩子:

mounted() {
    window.webkit.messageHandlers.contentLoaded.postMessage("content has loaded");    
}

或者这个:

mounted() {
    window.webkit.messageHandlers.contentLoaded.postMessage("content has loaded");    
}

这些都不会真正触发“contentLoaded”消息处理程序。

但是,如果我与网页进行一些交互,我可以触发消息处理程序,例如:

// This works!
button.addEventListener('click', () => {
   window.webkit.messageHandlers.contentLoaded.postMessage("content has loaded");  
})

我的代码的 Swift 方面如下。这里有什么建议吗?

import UIKit
import WebKit

class MainViewController: UIViewController, WKUIDelegate {
    var webView: WKWebView!

    override func loadView() {
        super.loadView()

        let contentController = WKUserContentController()

        contentController.add(self, name: "contentLoaded")

        let webConfiguration = WKWebViewConfiguration()
        webConfiguration.userContentController = contentController
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        webView.navigationDelegate = self
        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let myURL = URL(string:"https://example.com")
        var myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }
}

extension MainViewController: WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        print("received")

        if message.name == "contentLoaded", let messageBody = message.body as? String {
            print(messageBody)
        }
    }
}

extension MainViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        print("didFinish navigation")
    }

    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        print("didStartProvisionalNavigation")
    }
}

【问题讨论】:

    标签: javascript swift wkwebview


    【解决方案1】:

    您是否尝试过使用webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) 方法作为窗口加载时的回调来代替javascript 回调?

    Swift 通常不会与 WKWebView 中的窗口进行通信,直到它完全加载——此时首先调用 didFinish 方法。假设您只需要知道何时加载窗口/内容,我会在 JS 上使用该委托方法。

    编辑:如果您需要在网页加载时从浏览器中检索某种数据,您可以从返回它的 didFinish 块调用 Javascript 方法,假设您已经写了一个这样的Javascript方法来做到这一点。

    public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        webView.evaluateJavaScript("getData()", completionHandler: { (data, error) in
            if let data = data {
                print("Received: ", data)
            }
            if let error = error {
                print(error)
            }
        })
    }
    

    【讨论】:

    • 是的。我试图触发一个从webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) 返回到 WebView 的 JavaScript 事件,然后触发contentLoaded 消息处理程序,然后将其发送回本机应用程序,但这也不起作用。我的用例是我想将数据从 webview 发送到本机应用程序,以便我可以使用它来自定义一些 UI。
    • 通常我在这种情况下所做的只是在didFinish 块中使用webView.evaluateJavaScript,然后调用一些返回我需要的数据的Javascript方法,然后将其作为响应进行处理。这是您可以访问的浏览器中的本地内容吗?编辑:用上面的代码编辑了我的答案。
    • 当我尝试得到:Error Domain=WKErrorDomain Code=5 "JavaScript execution returned a result of an unsupported type" UserInfo={NSLocalizedDescription=JavaScript execution returned a result of an unsupported type}。我的回报在 JavaScript 方面必须是什么样子?我正在尝试返回一个对象或一个字符串。
    • Swift 无法识别 javascript 对象。字符串很好。如果您想发送一个对象,您可以尝试将其转换为 JS 中的字符串并在 swift 中将其解释为对象,或者使用 JSON。 Swift 可以将 JSON 转换为字典或将其解码为带有 Codable API 的对象,我强烈推荐
    • 感谢您的所有帮助。我的代码实际上是可以工作的,但是我有一个非常愚蠢的疏忽,并且没有在我的应用程序中调用正确的页面。我在原始帖子中添加了注释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-04
    相关资源
    最近更新 更多