I'm building hybrid Android app with WebView that communicates with the device with JavaScriptInterface
annotation
From the WebView:
webView.addJavascriptInterface(someService, "someService");
The service implementation:
@JavascriptInterface
public void someMethod() {
//do some business logic..
}
Problem is that from the JavaScript I run it like this:
function callSomeMethod() {
someService.someMethod()
};
This call is synchronous, and would like something that will run asynchronously like:
function callSomeMethod(callback) {
someService.someMethod(function(result) {
if (result == 'success')
callback();
})
};
Preferably using promise:
function callSomeMethod() {
return someService.someMethod()
//someMethod returns promise
};
Does Android WebView has built in support for running JavaScript code asynchronously?
Enable JavaScript JavaScript is disabled in a WebView by default. You can enable it through the WebSettings attached to your WebView . You can retrieve WebSettings with getSettings() , then enable JavaScript with setJavaScriptEnabled() . WebView myWebView = (WebView) findViewById(R.
JavaScript provides three methods of handling asynchronous code: callbacks, which allow you to provide functions to call once the asynchronous method has finished running; promises, which allow you to chain methods together; and async/await keywords, which are just some syntactic sugar over promises.
WebView allows you to bind JavaScript code to Android code through an interface. To do this, we must use the addJavaScriptInterface() method, which is passed the class that provides the interface for JS, and the name that will be used to display the instance in JS (for example, “AndroidFunction“).
JavaScript is a single-threaded, non-blocking, asynchronous, concurrent programming language with lots of flexibility.
That solely depends on you. You just need to return immediately from the injected method, but be able to call JS code when the execution is complete. Something like this (note that it's only a rough sketch):
private WebView mWebView;
private final Object mLock = new Object();
private String mJsCallbackCode;
@JavascriptInterface
public void someMethod(String jsCallbackCode) {
synchronized (mLock) {
mJsCallbackCode = jsCallbackCode;
}
// Start some business logic asynchronously, and return back here immediately.
return;
}
public void onBusinessLogicCompleted(bool success) {
String jsCallbackCode;
synchronized (mLock) {
jsCallbackCode = mJsCallbackCode;
}
mWebView.loadUrl("javascript:" + jsCallbackCode + "(" + success + ");void(0);");
}
And in JavaScript you use it like this:
function callSomeMethod(callback) {
window._someMethodCallback = callback;
someService.someMethod(
'(function(success){' +
' if (success) window._someMethodCallback();' +
' delete window._someMethodCallback;' +
'})'
);
};
So the idea is that you pass the JS code you need to be called back as a string (because you can't pass a real JS object). This code will be called in the global context.
Locking in Java is needed because methods called from JS run on a dedicated thread, not on your app's UI thread.
Note that in M preview, an API for postMessage
has been added to WebView, enabling to post asynchronous messages between Java and JS code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With