4

i have implemented a webview in my android app and trying to highlight or to mark element when user click in the layout.

The webview is initialized as following :

myWebView.getSettings().setJavaScriptEnabled(true);
//myWebView.getSettings().setGeolocationEnabled(true);
//myWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
myWebView.getSettings().setBuiltInZoomControls(true);
myWebView.getSettings().setDomStorageEnabled(true);
myWebView.setWebViewClient(new WebViewController());

Trying to mark the element which is clicked by user for example like in this screenshot :

selection_java

Selection with dot

I'm getting all the page divs via jsoup :

doc = Jsoup.connect(url).get();
final Elements alldivs = doc.select("div");
ArrayList<String> list = new ArrayList<String>();
for (org.jsoup.nodes.Element e : alldivs) {
if (!e.id().equals(""))
list.add(e.id());
}

But how to mark the selection as the photo above, and after that select marked content from div id.

How can make some thing like this ?

I'm using this javascript into webview to hightlight the selection but how to get the clicked element programmatically like : id of selected div or other values

public class MyWebViewClient extends WebViewClient {
    @Override
    public void onPageFinished(WebView view, String url) {
        view.loadUrl("javascript: "
                + "Object.prototype.each = function (fn, bind) {\n" +
                "                console.log(bind);\n" +
                "                for (var i = 0; i < this.length; i++) {\n" +
                "                    if (i in this) {\n" +
                "                        fn.call(bind, this[i], i, this);\n" +
                "                    }\n" +
                "                }\n" +
                "            };\n" +
                "\n" +
                "            var _addListener = document.addEventListener || document.attachEvent,\n" +
                "                _eventClick = window.addEventListener ? 'click' : 'onclick';\n" +
                "\n" +
                "            var elements = document.getElementsByTagName(\"div\");\n" +
                "\n" +
                "            elements.each(function (el) {\n" +
                "                _addListener.call(el, _eventClick, function () {\n" +
                                 // todo process the clicked div element
                "                    el.style.cssText = \"border-color:  black;border-style:  dashed;\"\n" +
                "                }, false);\n" +
                "            })");
    }
}
EAK TEAM
  • 5,726
  • 4
  • 30
  • 52

2 Answers2

4

If I understand correctly, you want to get some information from the HTML component into the native side.

According to this answer, it is not possible to pass arbitrary objects to Java, but at least you can pass the HTML code of the clicked node and then parse it natively.

This code based on yours does exactly that.

MainActivity.java: I guess this is pretty self-explanatory. The only thing I did different from you is to get the Javascript code from a separate file, so it's easier to maintain.

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final WebView myWebView = findViewById(R.id.webView);
        final WebSettings settings = myWebView.getSettings();

        settings.setJavaScriptEnabled(true);
        myWebView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                final String injectedJs = "javascript:(function(){" + injectedJs() + "})()";
                myWebView.loadUrl(injectedJs);
            }
        });

        myWebView.addJavascriptInterface(
                new Object() {
                    @JavascriptInterface
                    public void onClick(String param) {
                        Toast.makeText(MainActivity.this, param, Toast.LENGTH_LONG).show();
                    }
                },
                "appHost"
        );
        myWebView.loadUrl("https://google.com");
    }

    // Javascript code to inject on the Web page
    private String injectedJs() {
        BufferedReader stream = null;
        StringBuilder jsBuilder = new StringBuilder();
        try {
            stream = new BufferedReader(new InputStreamReader(getAssets().open("js.js")));
            String line;
            while ((line = stream.readLine()) != null) {
                jsBuilder.append(line.trim());
            }
            return jsBuilder.toString();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return "";
    }
}


js.js: The base of this part is your code. Keep in mind that since injectedJs() removes all line markers, every statement needs to finish, including comments, hence the /*...*/ instead of //

/* Keep track of the last clicked element so we can un-highlight it */
var lastSelectedItem = null;

var showHighlighted = function(/* HTML element */view, /*boolean */highlighted) {
    if (view) {
        view.style.cssText = highlighted? 'border-color: black;border-style: dashed;' : '';
    }
};

/* This new method, _addEventListener and _eventClick are the same as yours */
Object.prototype.each = function (fn, bind) {
                for (var i = 0; i < this.length; i++) {
                    if (i in this) {
                        fn.call(bind, this[i], i, this);
                    }
                }
            };

var _addListener = document.addEventListener || document.attachEvent,
    _eventClick = window.addEventListener ? 'click' : 'onclick';

/* I changed the element selection criteria, but you can change it back easily.
   I am adding event listeners all the leaf elements in the DOM. */
var elements = document.body.getElementsByTagName('*');
elements.each(function (el) {
    if (el.children.length == 0) {
        _addListener.call(el, _eventClick, function () {
            /* First, deal with the previously selected item*/
            showHighlighted(lastSelectedItem, false);
            if (lastSelectedItem !== null) {
                appHost.onClick(lastSelectedItem.outerHTML);                
            }

            /* Update the selected item reference */
            lastSelectedItem = el;


            /* Finally, deal with the previously selected item*/
            showHighlighted(lastSelectedItem, true);
            appHost.onClick(el.outerHTML);
        }, false);
    }
});
  • I understand, thanks for your time, i will reward you and will try later because the bounty is expiring, and your answer is the only one that have sense. :), Thanks – EAK TEAM May 23 '18 at 13:09
  • Thanks! Let me know if there's any problem when you test it :) – Leo supports Monica Cellio May 23 '18 at 13:25
  • Hello, i just tried it. :) :) , the only problem that i have is that maybe i want to select multiple elements, and in some hightliting is not working , for example some texts :). I mean the second selected div for example is in hierarchy of first selected. Hope to understand my English :D ? – EAK TEAM May 23 '18 at 13:30
  • I see, then I shouldn't have changed your element selection criteria. I just put it back like it was, have a look. And no problem with your English :) – Leo supports Monica Cellio May 23 '18 at 13:36
  • Hello, thanks again but it's not working. The problem is with javascript. It now selects all the divs, the first version by you was really ok, but i just wanted if i select another div it should highlight it too and call the event in @JavaScripInterface – EAK TEAM May 23 '18 at 13:50
  • I see, then please let me check it when I get to my machine, as I'm commuting now. – Leo supports Monica Cellio May 23 '18 at 13:55
  • Ok, I reverted the changes and removed lastSelectedItem. You should be good to go now! – Leo supports Monica Cellio May 23 '18 at 15:02
  • Hi @Leonardo , yes thanks it works, but one last thing. If you can help im not good at javascript :) , how can it be done if i select previously highlighted selected element it should un-highlight and fire the same method in native java too. Thank you – EAK TEAM May 23 '18 at 23:05
  • 1
    You can un-highlight any view by passing false as the second parameter of `showHighlighted ()` (in fact that's what my original answer did). – Leo supports Monica Cellio May 23 '18 at 23:19
  • I understand. if you can, please add at answer one javascript function for selected item as it is right now, and one with ability to select not element only but div container for that element, i will be really helpful for me and for other people who are noob in javascript :D :D :D , anyway , thanks for your time. Have a great day ! – EAK TEAM May 23 '18 at 23:28
  • I edited the answer for it to un-highlight the previously selected item, and to invoke the native method. I added a reference for the previously selected item, and code to update it and deal with it in the event handler. – Leo supports Monica Cellio May 23 '18 at 23:31
  • You helped me really a lot ! :) – EAK TEAM May 23 '18 at 23:40
  • Sorry, but the final edit is not working hahaha, this will make me crazy ! – EAK TEAM May 24 '18 at 00:09
  • 1
    D'oh! Semicolon missing. Fixed now – Leo supports Monica Cellio May 24 '18 at 01:47
  • i am really bad at javascript, but i read a little and finally found what i really need to do. Please accept my edit suggest – EAK TEAM May 24 '18 at 02:26
0

consider the web view as a view of a web page. You need to configure the element inside that web view to send a request that would fire an intent in your android application, which is possible, but it would not work for multiple users unless you know the user in that web view and authenticate the users... the point is , it is very complicated if you want to send that request from web to the logical part of your app. Even if you can do it, it is not optimal and i discourage it.

On the other hand, what you can do if you insist on using web views is to complete the rest of your logical operations on the web view. Don't go back from the web view to the app java logic.

Normally web views are used to show something rather than to make actions on the app. (the action might be used on the same web view)

I hope you do get , I've tried to explain as much as possible.

  • Yes , i understand you and thanks for your explanation. In fact i'm interacting with webview, with javascript. So my question is how to get some info from that javascript that i have used to make specific DIV marked after selected. – EAK TEAM May 22 '18 at 02:13
  • You can mark it like you would mark a normal div for a webpage , but it would not affect your main application – Elhoussine Zennati May 22 '18 at 07:47
  • Hello, i just tried it. :) :) , the only problem that i have is that maybe i want to select multiple elements, and in some hightliting is not working , for example some texts :)... – EAK TEAM May 23 '18 at 13:26
  • i'm not so good with javascript :( i would have helped you, but i think you can do whatever you want with javascript , it is powerful enough. good luck – Elhoussine Zennati May 23 '18 at 14:00
  • i'm worse with javascript too that's why i needed help :D :D , thank you anyway – EAK TEAM May 23 '18 at 14:01
  • maybe try to make a new question with [Javascript] tag , and be precise about what you need for that webview – Elhoussine Zennati May 23 '18 at 14:03