Umair Anwar
Umair Anwar

Reputation: 682

Understanding Android webview javascript interface

I have created an android WebView, and injected javascript interface using addJavascriptInterface(mObject, "jsinterface"). It works fine until I create an object with same name (jsinterface) in JavaScript using the new operator.

My Java Code:

WebView mWebView = findViewById(R.id.myWebView);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebChromeClient(new MyWebChromeClient((Activity)mContext));
mWebView.addJavascriptInterface(new testClass(), "jsinterface");
mWebView.loadUrl("UrlToLoad");

testClass.java

public class testClass{
    public testClass() {
    }

    @JavascriptInterface
    public String testNativeMethod() {
        return "Java method called!!";
    }
}

My Java Script Code

test.js

function test(msg){
    this.message = msg;

    this.testJSMethod = function(){
        return this.message;
    }
}

alert(jsinterface.testNativeMethod()); // prints Java method called!!
jsinterface= new test("JS method called...");
alert(jsinterface.testJSMethod()); // prints JS method called...
alert(jsinterface.testNativeMethod()); // errors "NPMethod called on non- NPObject"

Problem:

Is this possible for a javascript object to have access to both , i.e javascript methods and native JAVA methods(exposed to it via javascriptinterface) ? Is there any possibility of setting any property to webview OR executing any JS script to get this done?

Upvotes: 9

Views: 34084

Answers (2)

Aown Raza
Aown Raza

Reputation: 2023

TRY

You may try to make another object, which will retranslate calls to javascript interface.Implement onPageStarted method in WebViewClient , and inject javascript in onPageStarted method, in the following way.

 mWebView.setWebViewClient(new WebViewClient() {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
        @Override
        public void onPageStarted (WebView view, String url, Bitmap favicon){
            String jsScript= "javascript:var functions_array = ['testNativeMethod'];";
                   jsScript+="var jsinterface = {};"
                   jsScript+="functions_array.map(function(id){"
                   jsScript+="jsinterface[id]= function() {"
                   jsScript+="try{return temp_obj[id].apply(temp_obj, arguments);}"
                   jsScript+="catch(e) { console.log('ERROR: ' + e + ', method ' + id);"
                   jsScript+="return false;}}})"
            view.loadUrl(jsScript);
        }
    });

Hope this helps :-)

Upvotes: 5

kris larson
kris larson

Reputation: 30985

Think about document in javascript. When you are in a web browser, this is a global object that you have access to at any point. If you make your own new var called document, you are going to have problems accessing the global document.

When you execute this line:

    mWebView.addJavascriptInterface(new testClass(), "jsinterface");

you are adding a global object called jsinterface. This is the same situation as document. If you create a var with the same name, it will overwrite the existing global reference.

Once you add a javascript interface to the WebView, you don't need to create a new reference to the interface. addJavascriptInterface has already done that for you.

Upvotes: 14

Related Questions