EAK TEAM
EAK TEAM

Reputation: 7552

Select element inside WebView and get details

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" +
                "            })");
    }
}

Upvotes: 4

Views: 7502

Answers (2)

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);
    }
});

Upvotes: 4

Elhoussine Zennati
Elhoussine Zennati

Reputation: 301

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.

Upvotes: 0

Related Questions