Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return value from webView.evaluateJavascript callback?

So I have a class named JavascriptBridge that I use to communicate between Java and Javascript.

To send commands to javascript, I simply use this:

public void sendDataToJs(String command) {
    webView.loadUrl("javascript:(function() { " + command + "})()");
}

My problem is that I would also need a function that return a response from the Javascript. I try using webView.evaluateJavascript, but it skip the callback, as evaluateJavascript is done on another thread.

public String getDataFromJs(String command, WebView webView) {
    String data = null;

    webView.evaluateJavascript("(function() { return " + command + "; })();", new ValueCallback<String>() {
        @Override
        public void onReceiveValue(String s) {
            Log.d("LogName", s); // Print "test"
            // data = s; // The value that I would like to return
        }
    });

    return data; // Return null, not "test"
}

The call to the method:

String result = getDataFromJs("test", webView); // Should return "test" from the webView

I've also tried using a @JavascriptInterface, but it gives the same result.

like image 824
endlessCoffee Avatar asked Sep 05 '16 01:09

endlessCoffee


2 Answers

There isn't a way to evaluate Javascript synchronously on Android (i.e. on the current thread) so your best bet is to use evaluateJavascript then wait for the callback:

public void getDataFromJs(String command, WebView webView) {
    webView.evaluateJavascript("(function() { return " + command + "; })();", new ValueCallback<String>() {
        @Override
        public void onReceiveValue(String s) {
            returnDataFromJs(s);
        }
    });
}

public returnDataFromJs(String data) {
    // Do something with the result.
}

There isn't a method to evaluate Javascript on the current thread, as Javascript operations can take a while (the JS engine needs time to spin up) and this can block the current thread.

like image 176
Colin White Avatar answered Oct 15 '22 09:10

Colin White


I have written a small code snippet in Kotlin that could help you. I wrote this using RxKotlin but if you use Java you can use RxJava2 since they are the same.

fun getDataFromJsSync(command: String, webView: WebView): String {
    return getDataFromJs(command, webView).blockingGet()
}

fun getDataFromJs(command: String, webView: WebView): Single<String> {
    return Single.create { emitter: SingleEmitter<String> ->
        try {
            webView.evaluateJavascript(
                    "(function() { return $command; })();",
                    { result -> emitter.onSuccess(result) }
            )
        } catch (e: Exception) {
            emitter.onError(e)
        }
    }
}

P.S. I haven't tested the functions and cannot guarantee that they work but I don't have time and will test them and rewrite them in Java when I have time, probably in a 5 hours max.

like image 2
TheKarlo95 Avatar answered Oct 15 '22 07:10

TheKarlo95