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

时间:2019-02-18 16:47:35

标签: swift cocoa webkit

我正在使用MacOS应用程序,该应用程序需要使用WKUserScript功能将消息从网页发送回MacOS应用程序。我正在研究文章Binding.scala,该文章显示了在iOS中的工作原理,并且效果很好。

但是,我一直在努力尝试使其在MacOS中运行。这是我的代码示例,该代码可以正常运行,但无法成功打印在处理程序userContentController()中找到的消息

p = x %>%
    mutate(k1num  = as.numeric(as.character(k1))) %>%
    mutate(sqr = ifelse(is.na(k1num), "NULL", sqrt(k1num)))

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

我在转换中所做的所有事情都非常简单,除了userContentController的分配外,几乎不需要或不需要任何更改-也许这就是问题所在吗?此示例在iOS中以他的原始示例作为原型时效果很好。 https://medium.com/capital-one-tech/javascript-manipulation-on-ios-using-webkit-2b1115e7e405

我猜测这里一定缺少一些非常简单的东西。任何帮助将不胜感激!

2 个答案:

答案 0 :(得分: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 :(得分:1)

好吧,事实证明,问题的主要部分是我需要将“应用程序沙箱”和“ com.apple.security.files.user-selected.read-only”的授权都设置为“ WebTest.entitlements文件中的“否”。

在以前版本的XCode(我在V10.1上)中不是这种情况,默认值基本上禁用了WKWebView来处理我要执行的操作(即,通过URL或字符串)

但是,一旦我解决了这个问题,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的大力支持!