Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling JavaScript events in WKWebView

I'm trying to catch every onClick event in WKWebView. The website is working only with JavaScript so I cannot handle anything in:

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)

How can I do this?

like image 622
Alex Crow Avatar asked Jul 12 '17 16:07

Alex Crow


People also ask

How do I run JavaScript in WKWebView?

Inject JavaScript to WKWebView with WKUserScript viewDidLoad() let config = WKWebViewConfiguration() let js = getMyJavaScript() let script = WKUserScript(source: js, injectionTime: . atDocumentEnd, forMainFrameOnly: false) config. userContentController. addUserScript(script) config.

What are Webkit Messagehandlers?

A message handler is a listener that will fire and return data once some JavaScript event completes. For example, you can have a handler to parse JSON data fetched from a URL. By including these message handlers into your WKUserContentController object, your web view will define a new function window. webkit.

What is WKUserContentController?

Overview. A WKUserContentController object provides a bridge between your app and the JavaScript code running in the web view. Use this object to do the following: Inject JavaScript code into webpages running in your web view. Install custom JavaScript functions that call through to your app's native code.

Is WKWebView secure?

The old one – UIWebView is considered insecure and should no longer be used. WKWebView is the right API to implement WebViews. Unfortunately, using even the modern API may lead to vulnerabilities. Developers have to make sure that their code is not vulnerable to both web-related and native attacks.


2 Answers

you can use a WKUserScript and add it to the userContentController of the WKWebView's configuration.

    let config = WKWebViewConfiguration()
    let source = "document.addEventListener('click', function(){ window.webkit.messageHandlers.iosListener.postMessage('click clack!'); })"
    let script = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
    config.userContentController.addUserScript(script)
    config.userContentController.add(self, name: "iosListener")
    webView = WKWebView(frame: UIScreen.main.bounds, configuration: config)

this will make the script and inject it into the page when the document is finished loading. Now, you need to implement the WKScriptMessageHandler protocol to receive the message:

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        print("message: \(message.body)")
        // and whatever other actions you want to take
    }
like image 112
ɯɐɹʞ Avatar answered Oct 08 '22 05:10

ɯɐɹʞ


If you want to add click listener only for button with id 'buttonX' (<button id="buttonX">Click me</button>) then


let scriptSource = """
var button = document.getElementById('buttonX');
document.body.style.backgroundColor = `red`;
if(button != null) {
    button.addEventListener("click", function(){
        window.webkit.messageHandlers.iosClickListener.postMessage('open_invitation');
        document.body.style.backgroundColor = `green`;
    });
}

"""

        let config = WKWebViewConfiguration()
        let script = WKUserScript(source: scriptSource, injectionTime: .atDocumentEnd, forMainFrameOnly: false)

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


        let webView = WKWebView(frame: view.frame, configuration: config)

        view.addSubview(webView)
        webView.loadHTMLString(html, baseURL: nil) //load your html body here

    }

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if let body = message.body as? String, body == "open_invitation" {
            print("✅ we did it")
        }
    }

Also your view controller should conform to WKScriptMessageHandler protocol

like image 34
milczi Avatar answered Oct 08 '22 06:10

milczi