Search code examples
javascriptswiftmacoswebkitcode-injection

userContentController never called back from JS injection


I've got a WBWebview running into a NSPopover.
I've followed this guide in order to be able to send data back to my Swift application from JS. Unfortunately, userContentController is never called in the Swift app. Here's my Swift app View controller code:

class GSViewController: NSViewController, WKScriptMessageHandler, WKNavigationDelegate {

    var webView: WKWebView?

    var webConfig:WKWebViewConfiguration {
        get {

            // Create WKWebViewConfiguration instance
            let webCfg:WKWebViewConfiguration = WKWebViewConfiguration()

            // Setup WKUserContentController instance for injecting user script
            let userController:WKUserContentController = WKUserContentController()

            // Add a script message handler for receiving  "buttonClicked" event notifications posted from the JS document using window.webkit.messageHandlers.buttonClicked.postMessage script message
            userController.addScriptMessageHandler(self, name: "buttonClicked")

            // Get script that's to be injected into the document
            let js:String = buttonClickEventTriggeredScriptToAddToDocument()

            // Specify when and where and what user script needs to be injected into the web document
            let userScript:WKUserScript =  WKUserScript(source: js, injectionTime: WKUserScriptInjectionTime.AtDocumentEnd, forMainFrameOnly: false)

            // Add the user script to the WKUserContentController instance
            userController.addUserScript(userScript)

            // Configure the WKWebViewConfiguration instance with the WKUserContentController
            webCfg.userContentController = userController;

            return webCfg;
        }
    }

    override func loadView() {
        super.loadView()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        self.webView = WKWebView(frame: self.view.frame, configuration: webConfig)
        self.webView!.navigationDelegate = self
        self.view = webView!

        let username = NSUserName()
        let url = NSURL(string:"someUrl")
        let req = NSURLRequest(URL:url!)
        self.webView!.loadRequest(req)
        self.view.frame = CGRectMake(0, 0, 440, 600)
     }

    func buttonClickEventTriggeredScriptToAddToDocument() ->String{
        let script:String = "webkit.messageHandlers.callbackHandler.postMessage('Does it works?');"
        return script;

    }

    // WKNavigationDelegate
    func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
        NSLog("%s", #function)
    }

    func webView(webView: WKWebView, didFailNavigation navigation: WKNavigation!, withError error: NSError) {
        NSLog("%s. With Error %@", #function, error)
        showAlertWithMessage("Failed to load file with error \(error.localizedDescription)!")
    }

    func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {
        print("called")
        if(message.name == "callbackHandler") {
            print("It does ! \(message.body)")
        }
    }

    // Helper
    func showAlertWithMessage(message:String) {
        let myPopup:NSAlert = NSAlert()
        myPopup.messageText = message
        myPopup.alertStyle = NSAlertStyle.WarningAlertStyle
        myPopup.addButtonWithTitle("OK")
        myPopup.runModal()
    }

}

I'm trying to inject directly the call to Swift callback webkit.messageHandlers.callbackHandler.postMessage('Does it works?');, but it seems not to work.

With different test, I've discovered that the injection actually works in the Swift -> JS way (I've been able to modify CSS of visible HTML elements via injection of JQuery code), but the JS -> Swift bridge just doesn't seem to make it. Does anyone have an idea why?

I'm under OSX 10.11.6, running XCode 7.3.6.

I'm really new into Swift and OSX programming in general, so doesn't hesitate to point out any element I'm missing. I'm voluntary omitting the JS my page uses, since I'm not using any of it in the example.

Thanks.


Solution

  • Found it, was totally my bad. I forgot to rename the message handler when I added my script to the webview configuration.

    userController.addScriptMessageHandler(self, name: "callbackHandler") // was originally "ButtonClicked"