Невозможно внедрить JS в WKWebView в Swift / Какао / NextStep / Push-выбор пользователя на веб-странице в WKWebView в Swift / Какао - PullRequest
0 голосов
/ 18 февраля 2019

Я работаю с приложением 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

Я предполагаю, что должно быть что-то очень простое, что я здесь упускаю.Любая помощь будет принята с благодарностью!

Ответы [ 2 ]

0 голосов
/ 07 марта 2019

Ну, как выясняется, основная часть проблемы заключалась в том, что мне нужно было установить права как для «песочницы приложения», так и для «com.apple.security.files.user-selected.read-only» «обоим»нет "в файле WebTest.entitlements.

Такого не было в предыдущих версиях XCode (я на V10.1), и значения по умолчанию в основном отключали WKWebView для того, что я пытался с ним сделать (т.е. загрузить простую страницу либочерез URL или строку)

Тем не менее, исправление Алекса помогло, как только я решил, что с помощью нескольких небольших настроек (пришлось добавить 'self' в функцию userContentController.add (). Также я добавилмой 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)
        }
    }

}

Спасибо Алексу за все вашифантастическая поддержка!

0 голосов
/ 18 февраля 2019

Вот как я настроил свой WebView на Mac, попробуйте что-то вроде этого

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

}

Надеюсь, это ответило на ваш вопрос и сработает, если не, дайте мне знать, и я попробую разобраться!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...