Cédric Portmann Cédric Portmann - 21 days ago 9
Javascript Question

Detect if a specific button has been clicked in Android WebView

I am currently working on an android app. This app consists of a WebView and displays a website which I don't own. (F.e. a WebStore)

The app is supposed to recognize/detect when a user clicks a specific button on this website (f.e a "Buy Product" button). If a user clicks such a button, then the app makes a toast pop up.

I know this will be different for every website, however how would I program the click detection in general? I read a few articles about injecting JavaScript etc, however I dont really understand how this is supposed to work. Is there a way to say: If a user clicks on the button with id=buy_button, then show toast?

Thanks for your help!

Answer

The biggest problem you're going to have is if the button has another onClickListener already attached to it from the DOM, if you start overriding listeners, you're potentially going to break functionality in the website.

However you can do something like this, if you're sure you're not going to break functionality. If you are going to break functionality, you'll have to wrap both the normal on click and the updated one (below) in another function and call both. Ugly JavaScript.

private void prepareClickListener(){
    loadEvent(clickListener())
}

private void loadEvent(String javascript){
    Log.i(TAG, "Loading command: "+javascript);
    webView.loadUrl("javascript:"+javascript);
}

private String clickListener(){
    return "document.getElementById('buy_button').addEventListener('click', myBoundJavascriptMethod)";
}

After you do that, you'll need to bind the JavaScript in the WebView as documented here: https://developer.android.com/guide/webapps/webview.html#BindingJavaScript

-- EDIT --

For your specific example of http://store.nike.com/ch/de_de/pd/mercurial-superfly-v-tech-craft-2-herren-fussballschuh-fur-normalen-rasen/pid-11229711/pgid-11626158

{
    ...

    webview.getSettings().setJavaScriptEnabled(true);
    webview.getSettings().setDomStorageEnabled(true);
    webview.addJavascriptInterface(new MyJavaScriptInterface(this), "HtmlViewer");

    webview.setWebViewClient(new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
            loadEvent(clickListener());
        }

        private void loadEvent(String javascript){
            webview.loadUrl("javascript:"+javascript);
        }

        private String clickListener(){
            return getButtons()+ "for(var i = 0; i < buttons.length; i++){\n" +
                    "\tbuttons[i].onclick = function(){ console.log('click worked.'); HtmlViewer.boundMethod('button clicked'); };\n" +
                    "}";
        }

        private String getButtons(){
            return "var buttons = document.getElementsByClassName('add-to-cart'); console.log(buttons.length + ' buttons');\n";
        }
    });

    webview.loadUrl("http://store.nike.com/ch/de_de/pd/mercurial-superfly-v-tech-cra\u200C\u200Bft-2-herren-fussballschuh-fur-normalen-rasen/pid-11229711/pgid-11626158");

    ...
}


class MyJavaScriptInterface {

    private Context ctx;

    MyJavaScriptInterface(Context ctx) {
        this.ctx = ctx;
    }

    @JavascriptInterface
    public void boundMethod(String html) {
        new AlertDialog.Builder(ctx).setTitle("HTML").setMessage("It worked")
                .setPositiveButton(android.R.string.ok, null).setCancelable(false).create().show();
    }

}

That'll change the onClick for the button to what you need.

For everyone else, it looks like there's either a page-specific issue with getElementById() or an Android issue, but getting the elements by class (getElementsByClassName()) worked as expected. Furthermore, it might be necessary to replace getElementsByClassName() by getElementsByName('AddProductToCart') such as for example on this website: https://www.digitec.ch/de/s1/product/lexon-flip-wecker-3522142.