Understanding JSBridge in Hybrid Mobile App Development
JSBridge is a bidirectional communication layer that lets hybrid mobile apps combine native performance with web flexibility by allowing JavaScript to invoke native functions and native code to call back into the WebView, using techniques such as URL schemes, injected APIs, and platform‑specific evaluateJavascript methods.
Hybrid (or mixed) application development combines native code with WebView to leverage both native performance and the flexibility of web technologies. A key challenge in this model is establishing two‑way communication between the H5 (HTML5) layer and the native layer. JSBridge is a widely used mechanism that provides this communication channel.
Hybrid Development Overview
Hybrid development involves two major technology stacks: native (iOS, Android) and web (HTML5). Native code offers high performance and full device capabilities, while web code enables rapid updates and cross‑platform reuse. By integrating the two, developers can enjoy the advantages of both.
JSBridge Concept and Role
Acts as a communication bridge between web and native code, allowing bidirectional calls and data exchange.
Enables JavaScript to invoke native functions such as camera access, notifications, or hardware interaction.
Supports callbacks so native code can notify JavaScript of operation results.
Why JSBridge Is Important in Hybrid Apps
Facilitates cross‑platform development by letting a single web codebase run on multiple platforms while still accessing native features when needed.
Extends native capabilities, improving user experience.
Provides a flexible, extensible way to add new native functions without rebuilding the entire app.
Native → Web Communication
On Android, evaluateJavascript can execute JavaScript and receive a result via a callback:
String jsCode = String.format("window.showWebDialog('%s')", text);
webView.evaluateJavascript(jsCode, new ValueCallback
() {
@Override
public void onReceiveValue(String value) {
// handle result
}
});On iOS, WKWebView provides evaluateJavaScript:completionHandler: :
[webView evaluateJavaScript:@"执行的JS代码"
completionHandler:^(id _Nullable response, NSError * _Nullable error) {
// handle response
}];Web → Native Communication
Two common approaches are used:
URL Schema : The web page navigates to a custom URL (e.g., hellobike://showToast?text=hello ). The native side intercepts the request, parses the scheme, and invokes the corresponding native method.
Injecting JS API : Native code injects a JavaScript object into the WebView’s global scope (e.g., window.NativeBridge ) so that JavaScript can call window.NativeBridge.showNativeDialog('hello') directly.
Android injection before API 4.2 used addJavascriptInterface (which had security issues); after 4.2, @JavascriptInterface is recommended. iOS uses UIWebView with JavaScriptCore (iOS 7+) or WKWebView with WKScriptMessageHandler (iOS 8+).
Example of Android injection:
// Inject global JS object
webView.addJavascriptInterface(new NativeBridge(this), "NativeBridge");
class NativeBridge {
private Context ctx;
NativeBridge(Context ctx) { this.ctx = ctx; }
@JavascriptInterface
public void showNativeDialog(String text) {
new AlertDialog.Builder(ctx).setMessage(text).create().show();
}
}Calling the injected method from JavaScript:
window.NativeBridge.showNativeDialog('hello');H5 Implementation Details
A typical implementation defines an AppBridge class that encapsulates two main responsibilities: sending requests to native code and handling native callbacks.
Key steps:
Define a JavaScript class/object that provides bridge methods.
Initialize a callback handler that receives data from native and resolves/rejects the corresponding Promise.
Expose a callNative method that packages the class map, method name, parameters, and a unique callback ID, then sends the JSON string to the native side (via URL schema, injected API, or platform‑specific bridge).
Handle the native response, match it with the stored callback ID, and resolve or reject the Promise accordingly.
Example of the callNative implementation (TypeScript‑style):
// Define a method to call native functions
callNative
(classMap: string, method: string, params: P): Promise
{
return new Promise((resolve, reject) => {
const id = v4(); // generate unique callback ID
this.__callbacks[id] = { resolve, reject, method: `${classMap} - ${method}` };
const data = {
classMap,
method,
params: params === null ? '' : JSON.stringify(params),
callbackId: id,
};
const dataStr = JSON.stringify(data);
if (this.env.isIOS && isFunction(window?.webkit?.messageHandlers?.callNative?.postMessage)) {
window.webkit.messageHandlers.callNative.postMessage(dataStr);
} else if (this.env.isAndroid && isFunction(window?.AppFunctions?.callNative)) {
window.AppFunctions.callNative(dataStr);
}
});
}Bridge callback initialization:
private initBridgeCallback() {
const oldCallback = window.callBack;
window.callBack = (data) => {
if (isFunction(oldCallback)) oldCallback(data);
console.info('native callback', data);
const { callbackId } = data;
const callback = this.__callbacks[callbackId];
if (callback) {
if (data.code === 0) {
callback.resolve(data.data);
} else {
const error = new Error(data.msg) as Error & { response: unknown };
error.response = data;
callback.reject(error);
}
delete this.__callbacks[callbackId];
}
};
}Usage examples include opening a WebView, invoking OCR services, etc., all through the unified callNative API.
Overall, JSBridge provides a standardized, platform‑agnostic way to achieve seamless interaction between web and native components in hybrid mobile applications.
HelloTech
Official Hello technology account, sharing tech insights and developments.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.