无法在WKWebView到Swift / Cocoa的网页上的Swift / Cocoa / NextStep / Push用户选择中将JS注入WKWebView

问题描述 投票:0回答:2

我正在使用MacOS应用程序,该应用程序需要使用WKUserScript功能将消息从网页发送回MacOS应用程序。我正在使用文章https://medium.com/capital-one-tech/javascript-manipulation-on-ios-using-webkit-2b1115e7e405,它显示了这在iOS中工作并且工作得很好。

然而,我已经挣扎了好几个星期,试图让它在我的MacOS中运行。这是我的代码的例子,它符合罚款并运行,但没有成功打印在处理程序userContentController()中找到的消息

import Cocoa
import WebKit

class ViewController: NSViewController, WKNavigationDelegate {

    @IBOutlet weak var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let userContentController = WKUserContentController()

        // Add script message handlers that, when run, will make the function
        // window.webkit.messageHandlers.test.postMessage() available in all frames.

        userContentController.add(self, name: "test")

        // Inject JavaScript into the webpage. You can specify when your script will be injected and for
        // which frames–all frames or the main frame only.
        let scriptSource = "window.webkit.messageHandlers.test.postMessage(`Hello, world!`);"
        let userScript = WKUserScript(source: scriptSource, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
        userContentController.addUserScript(userScript)

     //   let config = WKWebViewConfiguration()
     //   config.userContentController = userContentController
     //   let webView = WKWebView(frame: .zero, configuration: config)

        webView.navigationDelegate = self
        webView.configuration.userContentController = userContentController

        // Make sure in Info.plist you set `NSAllowsArbitraryLoads` to `YES` to load
        // URLs with an HTTP connection. You can run a local server easily with services
        // such as MAMP.

        let htmlStr = "<html><body>Hello world - nojs</body></html>"
        webView.loadHTMLString(htmlStr, baseURL: nil)

    }
}

extension ViewController: WKScriptMessageHandler {
    // Capture postMessage() calls inside loaded JavaScript from the webpage. Note that a Boolean
    // will be parsed as a 0 for false and 1 for true in the message's body. See WebKit documentation:
    // https://developer.apple.com/documentation/webkit/wkscriptmessage/1417901-body.
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if let messageBody = message.body as? String {
            print(messageBody)
        }
    }
}

另一件奇怪的事情是我似乎无法创建一个加载页面并显示它的简单WKWebView应用程序。这些都只是简单的测试,我的主要应用程序能够使用AlamoFire / loadHTMLString()显示页面来加载/显示网页,我只是无法注入所需的JS。

我在转换中所做的一切都非常简单,除了userContentController的分配外,几乎不需要改变 - 所以也许这就是问题所在?这个例子在iOS中运行得很好,原始样本作为原型。 https://github.com/rckim77/WKWebViewDemoApp/blob/master/WKWebViewDemoApp/ViewController.swift

我猜我必须有一些非常简单的东西。任何帮助将不胜感激!

swift cocoa webkit
2个回答
1
投票

以下是我如何在Mac上设置我的WebView尝试这样的事情

import Cocoa
import WebKit

class ViewController: NSViewController {
    @IBOutlet weak var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let javascript = """
           function printStatement() {
                try {               
                     window.webkit.messageHandlers
                     .callbackHandler.postMessage({'payload': 'Hello World!'})
                } catch(err) {
                    console.log('The native context does yet exist')
                }
           }
        """

        let script = WKUserScript(
            source: javascript,
            injectionTime: WKUserScriptInjectionTime.atDocumentEnd,
            forMainFrameOnly: true
        )

        webView.configuration.userContentController.add(
            name: "callbackHandler"
        )
        webView.configuration.userContentController
            .addUserScript(script)

        webView.navigationDelegate = self

        let html = """
            <div onClick='javascript:printStatement()'>Print Statement</div>
        """

        webView.loadHTMLString(html, nil)
    }

}

extension ViewController: WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {

        if(message.name == "callbackHandler") {
            guard let body = message.body as? [String: Any] else {
                print("could not convert message body to dictionary: \(message.body)")
                return
            }

            guard let payload = body["payload"] as? String else {
                print("Could not locate payload param in callback request")
                return
            }

            print(payload)
        }
    }

}

希望这回答了你的问题,如果不让我知道,我会尝试解决它!


1
投票

好吧,事实证明,问题的一个主要部分是我需要将“App Sandbox”和“com.apple.security.files.user-selected.read-only”的权利设置为“no”in WebTest.entitlements文件。

在以前版本的XCode中我不是这种情况(我在V10.1上),默认值基本上禁用了WKWebView,因为我试图用它做什么(即通过URL或String加载一个简单的页面)

然而,一旦我解决了这个问题,Alex的修复确实有所帮助......只需要一些小的调整(必须在userContentController.add()函数中添加'self'。另外,我添加了我的JS,因为它的原始目的是“推” “每次用户更改页面上的选择时都要使用Swift。

这是我的最终代码:

import Cocoa
import WebKit

class ViewController: NSViewController, WKNavigationDelegate {

    @IBOutlet var webView: WKWebView!
    override func viewDidLoad() {
        super.viewDidLoad()

        let javascript = """
            function printStatement() {
                try {
                     var foo = window.getSelection().toString()
                     window.webkit.messageHandlers.callbackHandler.postMessage({'payload': foo})
                } catch(err) {
                    console.log('The native context does yet exist')
                }
            }
            function getSelectionAndSendMessage() {
                try {
                    var currSelection = window.getSelection().toString()
                    window.webkit.messageHandlers.callbackHandler.postMessage({'payload': currSelection})
                } catch(err) {
                    console.log('The native context does yet exist')
                }
            }
            document.onmouseup      = getSelectionAndSendMessage;
            document.onkeyup        = getSelectionAndSendMessage;
            document.oncontextmenu  = getSelectionAndSendMessage;
        """

        let script = WKUserScript(
            source: javascript,
            injectionTime: WKUserScriptInjectionTime.atDocumentEnd,
            forMainFrameOnly: true
        )

        webView.configuration.userContentController.add(self, name: "callbackHandler")

        webView.configuration.userContentController.addUserScript(script)

        webView.navigationDelegate = self

        let html = """
            <div onClick='javascript:printStatement()'>Print Statement</div>
            This is some sample text to test select with
        """

        webView.loadHTMLString(html, baseURL: nil)
    }

}

extension ViewController: WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {

        if(message.name == "callbackHandler") {
            guard let body = message.body as? [String: Any] else {
                print("could not convert message body to dictionary: \(message.body)")
                return
            }

            guard let payload = body["payload"] as? String else {
                print("Could not locate payload param in callback request")
                return
            }

            print(payload)
        }
    }

}

感谢Alex为您提供的所有支持!

© www.soinside.com 2019 - 2024. All rights reserved.