0

Setup: An android app that is supposed to show you your shopping behavior and sum up total online expenses I would like to analyse data that is displayed on a website, which I DON'T own using webview in my android app.

Problem: So i.e. the app should be capable of detecting what a user has in his "shopping cart", and when he presses the button to "buy" the products.

I read about JavaScriptInterfaces, however I really don't know anything about javascript and how the whole process of analysing should be constructed. If you could send me a few examples, or explain the process I would be very happy!

Cédric Portmann
  • 1,014
  • 1
  • 9
  • 22
  • If that site is using security i.e access token for users ...then you'll never be able to parse data from it by your native app... the only way to use a webview to load that site to display those data. – noman404 Nov 16 '16 at 12:43
  • @Al Noman, thats exactly what I am doing, I am loading the website inside an webview. And now I would like to "extract" the data I am looking for. – Cédric Portmann Nov 16 '16 at 12:47
  • you can grab the loading URL & some activities, inside of your webview by using WebViewClient. https://developer.android.com/reference/android/webkit/WebViewClient.html Or WebChromeClient https://developer.android.com/reference/android/webkit/WebChromeClient.html – noman404 Nov 16 '16 at 12:52
  • @AlNoman yes this is what I thought about too. Probably just going to have a look for an URL that contains "checkout" or something similar. – Cédric Portmann Nov 16 '16 at 16:50
  • Exactly .... have a look at here https://developer.android.com/guide/webapps/webview.html#UsingJavaScript – noman404 Nov 17 '16 at 05:56

2 Answers2

1

1) Implementation of a click detection on a button do the following:

Let me provide you a full example. For your the website 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), "ButtonRecognizer");

    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.'); ButtonRecognizer.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.

Getting the elements by class (getElementsByClassName()) worked as expected, however not: getElementById(). Furthermore, it might be necessary to replace getElementsByClassName() by getElementsByName() such as for example on this website: https://www.digitec.ch/de/s1/product/lexon-flip-wecker-3522142. Where you would put getElementsByName('AddProductToCart')

Info: the \n and the weird combination of strings inside the clickListener method are set like this, because of the IDE. ( ";" are causing problems inside a string).


2) Implementation of a website data analysis such as detecting what a customer puts inside his shopping cart:

(The code takes website specific parts which are defined by tags/names etc and outputs them inside the Android Monitor). You have to define the tags and names for every website. To get them, simply have a look at the html code of the website.

import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class ShoppingCartAnalyzerActivity extends AppCompatActivity {


    String adidas_tag = "product";
    String nike_tag = "ch4_cartItem";
    String zalando_tag = "z-coast-fjord_article";
    String digitec_tag = "item-description";

    String adidas_shoppingcart_url = "https://www.adidas.ch/on/demandware.store/Sites-adidas-CH-Site/de_CH/Cart-Show";
    String nike_shoppingcart_url = "https://secure-store.nike.com/ch/checkout/html/cart.jsp?";
    String zalando_shoppingcart_url = "https://www.zalando_tag.ch/cart/";
    String digitec_shoppingcart_url = "https://www.digitec.ch/";

    WebView webview;
    private String[] shoppingCartItems;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        webview = new WebView(this);
        setContentView(webview);


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

        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 getProducts() + "for(var i = 0; i < products.length; i++){\n" +
                        "\tconsole.log(products[i].innerText); ShoppingCartAnalyser.boundMethod(products[i].innerText,i,products.length); \n" +
                        "}";
            }

            private String getProducts() {
                return "var products = document.getElementsByClassName('" + zalando_tag + "'); console.log(products.length + ' products');\n";
            }
        });

        webview.loadUrl(zalando_shoppingcart_url);
    }

    private void displayItems() {
        for (String shoppingCartItem : shoppingCartItems) {
            Log.d("ShoppingCart", cleanString(shoppingCartItem));
        }
    }

    private String cleanString(String shoppingCartItem) {
        shoppingCartItem = shoppingCartItem.replace("Ändern", "");
        shoppingCartItem = shoppingCartItem.replace("Entfernen", "");
        shoppingCartItem = shoppingCartItem.replace("Bearbeiten", "");
        shoppingCartItem = shoppingCartItem.replace("Löschen", "");
        shoppingCartItem = shoppingCartItem.replace("icon-cart-minus", "");
        shoppingCartItem = shoppingCartItem.replace("icon-cart-plus", "");
        shoppingCartItem = shoppingCartItem.replace("Service + Zubehör", "");
        shoppingCartItem = shoppingCartItem.replaceAll("(?m)^[ \t]*\r?\n", "");
        return shoppingCartItem;
    }

    class MyJavaScriptInterface {

        private Context ctx;

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

        @JavascriptInterface
        public void boundMethod(String decodedShoppingCart, int i, int size) {
            if (i == 0) {
                shoppingCartItems = new String[size];
            }
            shoppingCartItems[i] = decodedShoppingCart;
            if (i == size - 1) {
                displayItems();
            }
        }
    }
}
Cédric Portmann
  • 1,014
  • 1
  • 9
  • 22
0

You can refer to this to learn how to get HTML content of webview. As for parsing the HTML content, XmlPullParser to do it.

Community
  • 1
  • 1
M. Erfan Mowlaei
  • 1,376
  • 1
  • 14
  • 25
  • @Efran Mowleai, thanks Erfan, I thought about this, but wasn't sure if it was going to work out. Do you have any experience about how to detect a press on a button inside this webview on a website which I dont own (i.e. Nike Webstore) and afterwards fire some method inside android? So the app recognizes when somebody buys a product? (Maybe something else will do the trick..) – Cédric Portmann Nov 16 '16 at 12:28
  • @CédricPortmann you can refer to this: http://stackoverflow.com/a/4075955/4260559 – M. Erfan Mowlaei Nov 16 '16 at 12:31
  • I checked your link out before, however @Sephy is the owner of the html page he is referring to, and I am not. How would I have to call the methods etc? – Cédric Portmann Nov 16 '16 at 12:35
  • @CédricPortmann that button probably has an id, special class or something which makes it unique, try finding it by that attribute. – M. Erfan Mowlaei Nov 16 '16 at 12:38
  • I have the id of the button (by inspection of the html code). However nothing happens when I implement the whole thing and this is the error I get: I/chromium: [INFO:CONSOLE(1)] "Uncaught TypeError: Cannot read property 'addEventListener' of null". Btw this now starts to be the same topic as I asked before at: http://stackoverflow.com/questions/40620431/detect-if-a-specific-button-has-been-clicked-in-android-webview/40620708#40620708 , maybe you can answer there. Thanks – Cédric Portmann Nov 16 '16 at 12:41
  • @CédricPortmann to be honest I'm not expert in JS, however the answer on your other question seems to tell you the reason: injection of your JS to that web page causes malfunction of web page's own JS, so you need to know the exact function of that button to implement it in your own code. As far as I'm concerned The answer I gave here to your question is the right one. – M. Erfan Mowlaei Nov 16 '16 at 12:48
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/128272/discussion-between-cedric-portmann-and-erfan-mowlaei). – Cédric Portmann Nov 16 '16 at 15:09