Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect non-navigation button click in WKWebView

I have loaded a webpage into a WKWebView. I want to detect when the user clicks this specific button.

<div class="compacted-item">
    <button class="btn btn-lg btn-primary deploy-button" data-ember-action="1361">
        Deploy
    </button>
</div>

decidePolicyFor navigationAction isn't triggered because it's not a navigation action.

I know how to add a js message handler to the web views user content controller, but since I don't own the webpage, how do I get it to send off a message for me to intercept? Such as:

window.webkit.messageHandlers.buttonClicked.postMessage(messageToPost);

Or is there another way to detect non-navigation button clicks in a WKWebView?

like image 961
Frankie Avatar asked Sep 27 '16 16:09

Frankie


1 Answers

This is technically possible, but you have to get a little hacky to do it. You can inject arbitrary js into a WKWebView, so you can find the element and add an event listener to it. Of course, you run the risk that someone will change the html out from under you and your functionality might break at that point.

I threw together a quick and dirty example project to try it out (I just threw your button into a hard-coded html document). Here's the gist of how to do this. (Note, this is a really quick and dirty implementation and JS isn't really my strong suit, but you definitely want to refine this and at least make sure your query has some results before you start accessing them like I did.). In your implementation of WKScriptMessageHandler, you can do whatever you need to once you receive the message from your injected script.

class ViewController: UIViewController {
    ...
    private func getConfiguredWebview() -> WKWebView {
        let config = WKWebViewConfiguration()
        let js = "document.querySelectorAll('.deploy-button')[0].addEventListener('click', function(){ window.webkit.messageHandlers.clickListener.postMessage('Do something'); })"
        let script = WKUserScript(source: js, injectionTime: .atDocumentEnd, forMainFrameOnly: false)

        config.userContentController.addUserScript(script)
        config.userContentController.add(self, name: "clickListener")

        let webView = WKWebView(frame: .zero, configuration: config)
        return webView
    }
}

extension ViewController: WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        print(message.body)
    }
}

This answer was inspired by https://learnappmaking.com/wkwebview-how-to/ this page.

Also, sorry about resurrecting a really old post hopefully it helps someone. To be honest, I looked at the question and not the date, then got a little carried away figuring out if it was possible or not.

like image 187
Christopher Thiebaut Avatar answered Oct 06 '22 00:10

Christopher Thiebaut