How do we call javascript from Android? I have this javascript library which I would like to use, I want to call the javascript function and pass the result value to the android java code. Haven't found the answer from now. i managed to call android code from javascript, but I want the other way around.
-
Just check an issue [WebView has no way to call JavaScript from Java](http://code.google.com/p/android/issues/detail?id=742) at code.google.com – Paresh Mayani Sep 25 '11 at 09:37
-
1The solution for now is to load a JavaScript URL, e.g.: webview.loadUrl("javascript:(function() { " + "document.getElementsByTagName('body')[0].style.color = 'red'; " + "})()"); In some ways it seems blindingly elegant and obvious once you see it, but then it's still not quite as elegant as a method to execute JavaScript directly. This does demonstrate, however, that implementing such a method would be easy. – A.Quiroga Sep 25 '11 at 09:41
4 Answers
There is a hack:
Bind some Java object so that it can be called from Javascript with WebView:
addJavascriptInterface(javaObjectCallback, "JavaCallback")
Force execute javascript within an existing page by
WebView.loadUrl("javascript: var result = window.YourJSLibrary.callSomeFunction(); window.JavaCallback.returnResult(result)");
(in this case your java class JavaObjectCallback
should have a method returnResult(..)
)
Note: this is a security risk - any JS code in this web page could access/call your binded Java object. Best to pass some one-time cookies to loadUrl() and pass them back your Java object to check that it's your code making the call.

- 79,991
- 11
- 123
- 154
-
2The Android developer's page also speaks about this security risk. -- I suppose there is no risk if the `JavascriptInterface` contains only methods that are meant to be reachable from JavaScript, and that is why the @JavascriptInterface annotation was introduced in JellyBean (api 17)? – Maarten Dec 24 '12 at 20:38
-
1@peter-knego What type should I use for the parameter in `returnResult(..)`? For example, I want to return `document.getElementsByClassName('someclass')` which is of type HTMLCollection, but there is no such type in Java? If I just use String or Object as parameter type, it will return null and "undefined".. – Kapé Jun 07 '14 at 19:57
-
I wonder if this might be overkill for me. All I want to do is parse an HTML table on my web site. I'm still searching for ways to do this. I have a javascript function that turns the table into json, I just need a way to get it inside java. – James Oct 12 '16 at 18:15
In order to match the method calls of the iOS WebviewJavascriptBridge ( https://github.com/marcuswestin/WebViewJavascriptBridge ), I made some proxy for the calls of register_handle
and call_handle
. Please note I am not a Javascript-guru therefore there is probably a better solution.
javascriptBridge = (function() {
var handlers = {};
return {
init: function () {
},
getHandlers : function() {
return handlers;
},
callHandler : function(name, param) {
if(param !== null && param !== undefined) {
JSInterface[name](param);
} else {
JSInterface[name]();
}
},
registerHandler : function(name, method) {
if(handlers === undefined) {
handlers = {};
}
if(handlers[name] === undefined) {
handlers[name] = method;
}
}
};
}());
This way you can send from Javascript to Java calls that can have a String parameter
javascriptBridge.callHandler("login", JSON.stringify(jsonObj));
calls down to
@JavascriptInterface
public void login(String credentialsJSON)
{
Log.d(getClass().getName(), "Login: " + credentialsJSON);
new Thread(new Runnable() {
public void run() {
Gson gson = new Gson();
LoginObject credentials = gson.fromJson(credentialsJSON, LoginObject.class);
SingletonBus.INSTANCE.getBus().post(new Events.Login.LoginEvent(credentials));
}
}).start();
}
and you can call back to Javascript with
javascriptBridge.registerHandler('successfullAuthentication', function () {
alert('hello');
})
and
private Handler webViewHandler = new Handler(Looper.myLooper());
webViewHandler.post(
new Runnable()
{
public void run()
{
webView.loadUrl("javascript: javascriptBridge.getHandlers().successfullAuthentication();"
}
}
);
If you need to pass a parameter, serialize to JSON string then call StringEscapeUtils.escapeEcmaScript(json)
, otherwise you get unexpected identifier: source (1)
error.
A bit tacky and hacky, but it works. You just have to remove the following.
connectWebViewJavascriptBridge(function(bridge) {
}
EDIT:
in order to change the global variable to an actual property, I changed the above code to the following:
(function(root) {
root.bridge = (function() {
var handlers = {};
return {
init: function () {
},
getHandlers : function() {
return handlers;
},
callHandler : function(name, param) {
if(param !== null && param !== undefined) {
Android[name](param);
} else {
Android[name]();
}
},
registerHandler : function(name, method) {
if(handlers === undefined) {
handlers = {};
}
if(handlers[name] === undefined) {
handlers[name] = method;
}
}
};
}());
})(this);
I got the idea from Javascript global module or global variable .

- 1
- 1

- 79,669
- 27
- 256
- 428
You can use Rhino
library to execute JavaScript without WebView.
Download Rhino first, unzip it, put the js.jar file under libs folder. It is very small, so you don't need to worry your apk file will be ridiculously large because of this one external jar.
Here is some simple code to execute JavaScript code.
Object[] params = new Object[] { "javaScriptParam" };
// Every Rhino VM begins with the enter()
// This Context is not Android's Context
Context rhino = Context.enter();
// Turn off optimization to make Rhino Android compatible
rhino.setOptimizationLevel(-1);
try {
Scriptable scope = rhino.initStandardObjects();
// Note the forth argument is 1, which means the JavaScript source has
// been compressed to only one line using something like YUI
rhino.evaluateString(scope, javaScriptCode, "JavaScript", 1, null);
// Get the functionName defined in JavaScriptCode
Object obj = scope.get(functionNameInJavaScriptCode, scope);
if (obj instanceof Function) {
Function jsFunction = (Function) obj;
// Call the function with params
Object jsResult = jsFunction.call(rhino, scope, scope, params);
// Parse the jsResult object to a String
String result = Context.toString(jsResult);
}
} finally {
Context.exit();
}
You can see more details at my post.

- 4,084
- 6
- 37
- 60
For a full implementation of JavaScript that doesn't require using a slow WebView, please see AndroidJSCore, which is a full port of Webkit's JavaScriptCore for Android.
UPDATE 2018: AndroidJSCore is deprecated. However, its successor, LiquidCore has all of the same functionality and more.
Calling functions from Android is very simple:
JSContext context = new JSContext();
String script =
"function factorial(x) { var f = 1; for(; x > 1; x--) f *= x; return f; }\n" +
"var fact_a = factorial(a);\n";
context.evaluateScript("var a = 10;");
context.evaluateScript(script);
JSValue fact_a = context.property("fact_a");
System.out.println(df.format(fact_a.toNumber())); // 3628800.0

- 1,755
- 2
- 19
- 25
-
1Hi Eric. You also forgot to mention it's now deprecated in favor of LiquidCore. – TheRealChx101 Jul 26 '18 at 02:30