18

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.

2 Answers 2

18

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Does any synchronization option exist for that issue?
@soommmy12 Not that I know of, unfortunately. You could block the main thread and wait for evaluateJavascript to return, but I wouldn't recommend it since that could cause your app to drop frames.
2

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.

1 Comment

If you call getDataFromJsSync from @JavascriptInterface, all webview operation will be blocked indefinitely, and you won' t get any result from js.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.