Skip to content

Instantly share code, notes, and snippets.

@pathnirvana
Last active January 31, 2024 18:15
Show Gist options
  • Star 25 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pathnirvana/5f4c2ce100100dbc7f1cca58e877bbc0 to your computer and use it in GitHub Desktop.
Save pathnirvana/5f4c2ce100100dbc7f1cca58e877bbc0 to your computer and use it in GitHub Desktop.
Async Await call to JavascriptInterface Android Java WebView
// Allows to call a Android java function asynchronously
// spawn long running computations/io on the Java/Android without blocking the JS/Website running inside the WebView
// Eg. const result = await callAndroidAsync('javaFunction', { param1: 'value1', param2: 'value2' })
// Please give a star if you find this useful
export async function callAndroidAsync(javaFuncName, params) {
const rand = 'asyncJava_' + Math.floor(Math.random() * 1000000)
window[rand] = {}
// func called from android
window[rand].callback = (isSuccess) => {
const dataOrErr = Android.runAsyncResult(rand)
if (isSuccess) window[rand].resolve(dataOrErr)
else window[rand].reject(dataOrErr)
delete window[rand] // clean up
}
// call some android function that returns immediately - should run in a new thread
// setTimeout(() => window[rand].callback(false, params.val * 2), 4000) // see testCallJavaAsync
Android.runAsync(rand, javaFuncName, JSON.stringify(params))
return new Promise((resolve, reject) => {
window[rand].resolve = (data) => resolve(data)
window[rand].reject = (err) => reject(err)
})
}
// async function testCallJavaAsync() {
// const res = await callJavaAsync('testFunc', { val: 100 })
// console.log(`received res = ${res}`)
// }
// testCallJavaAsync()
public class WebAppInterface {
WebView webView;
Map<String, String> runAsyncResults = new ConcurrentHashMap<>();
WebAppInterface(WebView wv) {
webView = wv;
}
@JavascriptInterface
public void runAsync(final String rand, final String funcName, final String jsonParams) {
final WebAppInterface wai = this;
new Thread() {
// runs the java function in a new thread
@Override public void run() {
try {
final JSONObject params = new JSONObject(jsonParams);
String result = (String) wai.getClass().getMethod(funcName, JSONObject.class).invoke(wai, params);
wai.jsResolve(rand, true, result);
} catch (InvocationTargetException ite) { // exceptions inside the funcName function
wai.jsResolve(rand, false, ite.getCause().toString());
} catch (Exception e) {
wai.jsResolve(rand, false, e.toString());
}
}
}.start();
}
private void jsResolve(String rand, boolean isSuccess, String result) { // notify that result is ready
runAsyncResults.put(rand, result);
final String url = "javascript:" + rand + ".callback(" + isSuccess + ")";
Log.i("LOG_TAG", "calling js method with url " + url);
webView.post(new Runnable() {
@Override
public void run() {
webView.loadUrl(url);
}
});
}
@JavascriptInterface
public String runAsyncResult(String rand) { // returns the result from runAsync to JS
String result = runAsyncResults.get(rand);
runAsyncResults.remove(rand);
return result;
}
// Java functions that you need to be called from Javascript needs to be declared here as Public functions
// e.g. public String javaFunction(JSONObject params) { ... }
}
@pathnirvana
Copy link
Author

Allows to call a Android java function asynchronously
spawn long running computations/io on the Java/Android without blocking the JS/Website running inside the WebView
E.g. call from JS inside Webview
const result = await callAndroidAsync('javaFunction', { param1: 'value1', param2: 'value2' })
definition of the function in Java/Android
public String javaFunction(JSONObject params) { ... }
Please give a star if you find this useful

@EaseTheWorld
Copy link

Thanks for sharing your codes.
I simplified your logic to work with androidx WorkManager.
https://gist.github.com/EaseTheWorld/12f73e1d1466d8d570f36b3e49e79a39

Basically idea is same except

  • Use own namespace instead of window['xxx']
  • requestId(='rand') will be created in Android side.
  • pass callback directly to android so js part can have control of the callback function name.
  • result is not saved in map because WorkManager handles it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment