I want to get a return value from Javascript in Android. I can do it with the iPhone, but I can't with Android. I used loadUrl, but it returned void instead of an object. Can anybody help me?
10 Answers
Same as Keith
but shorter answer
webView.addJavascriptInterface(this, "android");
webView.loadUrl("javascript:android.onData(functionThatReturnsSomething)");
And implement the function
@JavascriptInterface
public void onData(String value) {
//.. do something with the data
}
Don't forget to remove the onData
from proguard
list (if you have enabled proguard)

- 296
- 4
- 27

- 10,035
- 9
- 50
- 67
-
1
-
@eugene if you don't know what it is you probably don't use it. Anyway its something to enable which makes reverse engineering your app harder – Kirill Kulakov Jul 10 '14 at 14:08
-
1Thanks. I know I have proguard-project.txt in the project root but no more than that. I'm asking because your solution works but I get SIGSEGV. I am evaluating `document.getElementById("my-div").scrollTop` to get scroll position from `SwipeRefreshLayout::canChildScrollUp()`. I suspect it might be due to the call gets called too many times in short period. or `proguard` which I suspect because I just don't know what it is.. – eugene Jul 11 '14 at 01:31
-
Not necessary to use `loadUrl`. What is necessary is that you define `webView.addJavascriptInterface(this, "android");` before calling `webview.loadUrl()` method. Also, you can directly call `android.onData(result)` from anywhere inside JavaScript. Even inside an `async` function that doesn't return anything. – philoopher97 Feb 21 '23 at 17:29
Here's a hack on how you can accomplish it:
Add this Client to your WebView:
final class MyWebChromeClient extends WebChromeClient {
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Log.d("LogTag", message);
result.confirm();
return true;
}
}
Now in your javascript call do:
webView.loadUrl("javascript:alert(functionThatReturnsSomething)");
Now in the onJsAlert call "message" will contain the returned value.

- 1,479
- 2
- 10
- 16
-
17This is an extremely valuable hack; especially when you're building an app where you don't have control over the javascript and have to make do with existing functions. Note you can get the same result without intercepting the JS alerts using the `public boolean onConsoleMessage(ConsoleMessage consoleMessage)` instead of `onJsAlert` and then in the javascript call you do `webView.loadUrl("javascript:console.log(functionThatReturnsSomething)");` - that way you leave the JS alerts alone. – Mick Byrne Jul 09 '12 at 03:46
-
The solution with `WebChromeClient.onConsoleMessage` seems to be cleaner but be aware that it does not work with some HTC devices. See [this question](http://stackoverflow.com/questions/4860021/android-problem-with-debugging-javascript-in-webview) for more info. – Piotr Jul 13 '12 at 09:29
-
4
-
@Keith: You'd require an object into which javascript writes it results, but as you can't touch the existing javascript in this question and the existing js does not write into such object, the js interface method doesn't help here (that's how I understood it). – Ray Feb 04 '14 at 09:14
-
1@RayKoopa Not necessarily true. Although you may not be able to edit the existing javascript within the target webpage, you can still invoke methods onto the object passed into `mWebView.addJavascriptInterface(YourObject mYourObject,String yourNameForObject);` by calling the function `mWebView.loadUrl("javascript:yourNameForObject.yourSetterMethod(valueToSet)")` – Chris - Jr Nov 23 '16 at 15:26
Use addJavascriptInterface()
to add a Java object to the Javascript environment. Have your Javascript call a method on that Java object to supply its "return value".

- 986,068
- 189
- 2,389
- 2,491
-
how can i do that in situation like http://stackoverflow.com/questions/5521191/returning-a-value-from-javascript-function-in-android – vnshetty Apr 02 '11 at 04:59
-
This doesn't help if your js doesn't write into this object and you can't touch the js. – Ray Feb 04 '14 at 09:14
-
7@PacMani: Use `loadUrl("javascript:...")` (API Level 1-18) or `evaluateJavascript()` (API Level 19+) to evaluate your own JavaScript in the context of the currently-loaded Web page. – CommonsWare Feb 04 '14 at 12:34
-
@CommonsWare: Thanks, I got that ;) however, the manager decided that js can be modified over "abusing javascript alerts" (eyeroll), so I got it going with the interface method. – Ray Feb 04 '14 at 12:49
Here's what I came up with today. It's thread-safe, reasonably efficient, and allows for synchronous Javascript execution from Java for an Android WebView.
Works in Android 2.2 and up. (Requires commons-lang because I need my code snippets passed to eval() as a Javascript string. You could remove this dependency by wrapping the code not in quotation marks, but in function(){}
)
First, add this to your Javascript file:
function evalJsForAndroid(evalJs_index, jsString) {
var evalJs_result = "";
try {
evalJs_result = ""+eval(jsString);
} catch (e) {
console.log(e);
}
androidInterface.processReturnValue(evalJs_index, evalJs_result);
}
Then, add this to your Android activity:
private Handler handler = new Handler();
private final AtomicInteger evalJsIndex = new AtomicInteger(0);
private final Map<Integer, String> jsReturnValues = new HashMap<Integer, String>();
private final Object jsReturnValueLock = new Object();
private WebView webView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
webView = (WebView) findViewById(R.id.webView);
webView.addJavascriptInterface(new MyJavascriptInterface(this), "androidInterface");
}
public String evalJs(final String js) {
final int index = evalJsIndex.incrementAndGet();
handler.post(new Runnable() {
public void run() {
webView.loadUrl("javascript:evalJsForAndroid(" + index + ", " +
"\"" + StringEscapeUtils.escapeEcmaScript(js) + "\")");
}
});
return waitForJsReturnValue(index, 10000);
}
private String waitForJsReturnValue(int index, int waitMs) {
long start = System.currentTimeMillis();
while (true) {
long elapsed = System.currentTimeMillis() - start;
if (elapsed > waitMs)
break;
synchronized (jsReturnValueLock) {
String value = jsReturnValues.remove(index);
if (value != null)
return value;
long toWait = waitMs - (System.currentTimeMillis() - start);
if (toWait > 0)
try {
jsReturnValueLock.wait(toWait);
} catch (InterruptedException e) {
break;
}
else
break;
}
}
Log.e("MyActivity", "Giving up; waited " + (waitMs/1000) + "sec for return value " + index);
return "";
}
private void processJsReturnValue(int index, String value) {
synchronized (jsReturnValueLock) {
jsReturnValues.put(index, value);
jsReturnValueLock.notifyAll();
}
}
private static class MyJavascriptInterface {
private MyActivity activity;
public MyJavascriptInterface(MyActivity activity) {
this.activity = activity;
}
// this annotation is required in Jelly Bean and later:
@JavascriptInterface
public void processReturnValue(int index, String value) {
activity.processJsReturnValue(index, value);
}
}

- 1,123
- 9
- 22
-
1But if I run evalJS in button.click listener, etc,. waitForJsReturnValue may cause evalJs() to hang up. So webView.loadUrl() inside handler.post() may not have chance to execute because button.click listener didn't returned. – victorwoo Jul 11 '13 at 09:18
On API 19+, the best way to do this is to call evaluateJavascript on your WebView:
webView.evaluateJavascript("foo.bar()", new ValueCallback<String>() {
@Override public void onReceiveValue(String value) {
// value is the result returned by the Javascript as JSON
}
});
Related answer with more detail: https://stackoverflow.com/a/20377857

- 2,537
- 1
- 22
- 15
The solution that @Felix Khazin suggested works, but there is one key point missing.
The javascript call should be made after the web page in the WebView
is loaded. Add this WebViewClient
to the WebView
, along with the WebChromeClient
.
Full Example:
@Override
public void onCreate(Bundle savedInstanceState) {
...
WebView webView = (WebView) findViewById(R.id.web_view);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new MyWebViewClient());
webView.setWebChromeClient(new MyWebChromeClient());
webView.loadUrl("http://example.com");
}
private class MyWebViewClient extends WebViewClient {
@Override
public void onPageFinished (WebView view, String url){
view.loadUrl("javascript:alert(functionThatReturnsSomething())");
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}
}
private class MyWebChromeClient extends WebChromeClient {
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Log.d("LogTag", message);
result.confirm();
return true;
}
}

- 1,923
- 3
- 34
- 54

- 79
- 1
- 4
Android return value from javascript in Android WebView
As an alternative variant that uses a custom scheme to communicate Android native code <-> HTML/JS code
. for example MRAID uses this technic[About]
MainActivity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
final WebView webview = new CustomWebView(this);
setContentView(webview);
webview.loadUrl("file:///android_asset/customPage.html");
webview.postDelayed(new Runnable() {
@Override
public void run() {
//Android -> JS
webview.loadUrl("javascript:showToast()");
}
}, 1000);
}
}
CustomWebView
public class CustomWebView extends WebView {
public CustomWebView(Context context) {
super(context);
setup();
}
@SuppressLint("SetJavaScriptEnabled")
private void setup() {
setWebViewClient(new AdWebViewClient());
getSettings().setJavaScriptEnabled(true);
}
private class AdWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("customschema://")) {
//parse uri
Toast.makeText(CustomWebView.this.getContext(), "event was received", Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
}
}
customPage.html (located in the assets folded)
<!DOCTYPE html>
<html>
<head>
<title>JavaScript View</title>
<script type="text/javascript">
<!--JS -> Android-->
function showToast() {
window.location = "customschema://goto/";
}
</script>
</head>
<body>
</body>
</html>

- 29,217
- 8
- 193
- 205
You can do it like this:
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
public WebView web_view;
public static TextView textView;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
Window.AddFlags(WindowManagerFlags.Fullscreen);
Window.ClearFlags(WindowManagerFlags.ForceNotFullscreen);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.main);
web_view = FindViewById<WebView>(Resource.Id.webView);
textView = FindViewById<TextView>(Resource.Id.textView);
web_view.Settings.JavaScriptEnabled = true;
web_view.SetWebViewClient(new SMOSWebViewClient());
web_view.LoadUrl("https://stns.egyptair.com");
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
public class SMOSWebViewClient : WebViewClient
{
public override bool ShouldOverrideUrlLoading(WebView view, IWebResourceRequest request)
{
view.LoadUrl(request.Url.ToString());
return false;
}
public override void OnPageFinished(WebView view, string url)
{
view.EvaluateJavascript("document.getElementsByClassName('notf')[0].innerHTML;", new JavascriptResult());
}
}
public class JavascriptResult : Java.Lang.Object, IValueCallback
{
public string Result;
public void OnReceiveValue(Java.Lang.Object result)
{
string json = ((Java.Lang.String)result).ToString();
Result = json;
MainActivity.textView.Text = Result.Replace("\"", string.Empty);
}
}

- 157
- 12
If you want to get the value in a synchronous way, you have to know that the webView.evaluateJavascript() runs asynchronously but you can use a simple semaphore to wait for the execution.
Steps:
Create a javascript interface (basically a class with a method that is going to be called from the javascript we want to evaluate.
public class MyInterface { private String value; private Semaphore semaphore; public MyInterface(Semaphore semaphore) { this.semaphore = semaphore; } public String getValue() { return value; } @JavascriptInterface public void setValue(String value) { this.value = value; //important release the semaphore after the execution semaphore.release(); } }
Add the javascript interface to the Android web view
Semaphore mySemaphore = new Semaphore(0); MyInterface myJsInterface = new MyInterface(mySemaphore); webView.addJavascriptInterface(myJsInterface, "jsInterface");
Execute the javascript and await the execution
webView.evaluateJavascript("var myValue='this works';jsInterface.setValue(myValue);", null); //await the execution mySemaphore.acquire(); //the interface now have the value after the execution myJsInterface.getValue();

- 1
- 3
To get data from a WebView in Android, you can use the evaluateJavascript()
method to execute JavaScript code that retrieves the data from the web page. Here's an example:
WebView webView = findViewById(R.id.webview); webView.getSettings().setJavaScriptEnabled(true); webView.loadUrl("https://example.com");
String js = "(function() { " +
"return document.getElementById('my_element').innerHTML;" +
"})()";
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
view.evaluateJavascript(js, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
// 'value' contains the result of the JavaScript code
Log.d("WebView", "Data: " + value);
}
});
}
});
In this example, the JavaScript code retrieves the inner HTML of an element with the ID my_element. The evaluateJavascript()
method executes the code and passes the result to a ValueCallback
that logs the data to the console.
You can modify the JavaScript code to retrieve different types of data, such as form input values or attributes of HTML elements. Just make sure to return the data as a string, and parse it in the onReceiveValue()
method if necessary.

- 2,653
- 18
- 24