Search code examples
androidandroid-fragmentsandroid-webviewandroid-websettingsjavascript-injection

How do i inject a complicated javascript self running function into a webview in android?


I am trying to inject a javascript function into my webview running a server url "www.myserver.com". However, I am unable to do so. I tried several ways but didn't succeed. I tried setting up js alerts, which do not pop up upon reading the js file. I am not sure what I am doing wrong. Here's my code so far: my js file "page.js":

(function() {
    **alert("this is a test alert");**
    if (window.page) {
        return; // page has been loaded from somewhere, not to redefine it again
    }

    function Response(xhr) {
        this.xhr = xhr;
        this.status = xhr.status;
    }
    Response.prototype.getHeader = function(header) {
        return this.xhr.getResponseHeader(header);
    };
    Response.prototype.getBody = function() {
        return this.xhr.responseText;
    };

    function ajax(url, callback) {
        //TODO support PUT method
        var xhr = new XMLHttpRequest();
        xhr.open("GET", url, true);
        xhr.onerror = function(e) {
            callback.onerror(e);
        };
        xhr.onreadystatechange = function(event) {
            if (this.readyState != this.DONE || this.status == 0) { 
                return;
            }
            if (this.status != 200) {
                var response = new Response(xhr);
                callback.onfail(response);
                return;
            }
            callback.onsuccess(this.responseText);
        };
        xhr.send();
    };


    var rpc = {
        type: ["SMALL", "LARGE"],
        exec: function(call, type) {// "call" conform to JSON-RPC 2.0 
            //TODO differentiate POST/GET based on rpc.type.SMALL/LARGE
            var param = encodeURIComponent(JSON.stringify(call));
            ajax("?_$b=" + param, {
                onerror: function(e) {
                    //TODO use logging
                    alert("Error:"+e.toString());
                },
                onfail: function(response) {
                    //TODO use logging
                    alert("Failed:"+response.getBoby());
                },
                onsuccess: function(text) {
                    //TODO use logging
                    alert("page success:"+text);
                },
            });
        }
    };

    var _$b = window.page = {
            version: "0.1"
        };

    _$b.has =  function(feature) {
            // TODO support nested objects, e.g.: "cache.get"
            return _$b[feature];
        };

    _$b.notify = function(id, data) {
            // TODO invoke the function from native and send web event
            // var event = document.createEvent('Event');
            // event.initEvent(id, true, true);
            // document.dispatchEvent(event);
            alert("id:" + id + ";data:" + data);
        };

    _$b.navigate = function(url, title) {
            rpc.exec(// JSON-RPC 2.0
                {method: "navigate", params: {
                    "url": url, 
                    "title": title
                }}, rpc.type.SMALL);
        };

    _$b.cache = {};

    _$b.cache.get = function(id) {
            rpc.exec(
                {method: "cache.get", params: {
                    "id": id, 
                }}, rpc.type.SMALL);
        };

    _$b.cache.put = function(id, obj, ts, ttl) {
            rpc.exec(
                {method: "cache.put", params: {
                    "id": id, 
                    "obj": obj,
                    "ts": ts,
                    "ttl": ttl,
                }}, rpc.type.LARGE);
        };

    _$b.cache.has = function(id) {
            rpc.exec(
                {method: "cache.has", params: {
                    "id": id, 
                }}, rpc.type.SMALL);
        };

})();

Here's my webview code:

@Override
                    public void onPageFinished(WebView view, String url) {

                        String javascript = "";
                        try{
                            AssetManager manager = view.getContext().getAssets();
                            InputStream is = manager.open("page.js"); 
                            InputStreamReader isr = new InputStreamReader(is);
                            BufferedReader br = new BufferedReader(isr);

                            String line;
                            while (( line = br.readLine()) != null) {
                                javascript += line;

                            }
                            is.close();
                        }

                        catch(Exception e){}

                        view.loadUrl("javascript:" + javascript);


                    }

                webview.setWebChromeClient(new WebChromeClient() {});
                webview.loadUrl(url);

Any ideas how to get the alerts to popup? Note: When I remove all the functions in js and just keep the alerts, the alert works,but after I re-add the necessary js functions the alert doesnt work anymore. Any idea what might be stopping it from injecting into the js as expected?


Solution

  • Consider this code. This is simple html & javascript code that models after your page.js

     <html>
       <script type="text/javascript">
    
           (function() { alert('inside function'); })
           alert('ok');
    
       </script> 
     </html>
    

    Executing this, you can derive that the alert inside the function is not execute at the start unless you specifically invoke it.

    To run your function with a click: (Try this)

    <html>
       <input type="button" onclick="run()" value="Start" />
    
       <script type="text/javascript">
           var run = (function() { alert('inside function'); })
           alert('ok');
    
        </script>
    </html>
    

    To run your function [Self Run] (Try this)

    <html>
       <script type="text/javascript">
           var run = (function() { alert('inside function'); })
           alert('ok');
    
           //you need to execute your function that you have named
           run();
    
        </script>
    </html>