1. Overview

In hybrid app development, combining native applications with WebView is an efficient technical solution. This approach allows complex business logic to be implemented using web technologies while enabling efficient bidirectional communication between H5 and Native. JSBridge plays a key role in this interaction, serving as the bridge between the web and native environments.

1.1 Hybrid Development

Hybrid development is a method that combines multiple development models, mainly involving two types of technologies: Native Development and Web Development (H5).

  • Native Development: Focused on iOS and Android, offering high performance and comprehensive features, but with longer development cycles and requiring users to update the app for each release.
  • Web Development (H5): Provides strong cross-platform compatibility and is easy to publish and update, but has limitations in performance and access to device capabilities.

The advantage of hybrid development lies in combining the strengths of both. With hardware advancements and better Web support in modern OS versions (e.g., Android 5.0+ and iOS 9.0+), the shortcomings of H5 are becoming less significant.

2. What is JSBridge and What Does It Do?

JSBridge acts as the “bridge” between web and native applications, enabling bidirectional communication. It allows developers to:

  • Invoke native functions: Access native capabilities such as opening the camera, sending notifications, etc., through JavaScript.
  • Transfer data: Easily exchange complex data structures (e.g., objects, arrays) between web and native code.
  • Implement callbacks: Native code can send responses or results back to JavaScript after operations are executed.

3. Why JSBridge Matters

  • Cross-platform development: Enables consistent code across platforms, improving development efficiency.
  • Native feature integration: Leverages the full power of native platforms to enhance functionality and user experience.
  • Flexibility and scalability: Developers can quickly add new features and upgrade without releasing full app updates.

4. How JSBridge Works

JSBridge enables two-way communication between H5 and Native in a hybrid environment. Here’s how it works:

Native → Web

Native code can call JavaScript by injecting code into the WebView using methods like evaluateJavascript.

Android Example (Java):

1
2
3
4
5
6
7
String jsCode = String.format("window.showWebDialog('%s')", text);
webView.evaluateJavascript(jsCode, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
// Handle returned value
}
});

iOS Example (Objective-C):

1
2
3
[webView evaluateJavaScript:@"JS code to execute" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
// Handle response
}];

Web → Native

There are two main approaches:

  1. Custom URL Schemes: Use specially formatted URLs that are intercepted by the Native layer.
1
2
// JavaScript Example
window.location.href = "hellobike://showToast?text=hello";
  1. Injected JS APIs: Inject native objects/functions into the JS context.

Android Example (Java):

1
webView.addJavascriptInterface(new NativeBridge(this), "NativeBridge");

iOS Example (Objective-C):

1
webView.configuration.userContentController.addScriptMessageHandler(self, name: "callbackHandler");

5. H5 Implementation

To implement JSBridge on the H5 side, you can create an AppBridge class to encapsulate the logic for native calls and callbacks.

Calling Native Methods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
callNative(classMap, method, params) {
return new Promise((resolve, reject) => {
const id = generateUniqueId(); // Unique callback ID
this.__callbacks[id] = { resolve, reject, method: `${classMap} - ${method}` };
const data = { classMap, method, params: params ? JSON.stringify(params) : '', callbackId: id };
const dataStr = JSON.stringify(data);

if (isIOS()) {
window.webkit.messageHandlers.callNative.postMessage(dataStr);
} else if (isAndroid()) {
window.AppFunctions.callNative(dataStr);
}
});
}

Handling Callbacks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private initBridgeCallback() {
const oldCallback = window.callBack;
window.callBack = (data) => {
if (isFunction(oldCallback)) {
oldCallback(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);
error.response = data;
callback.reject(error);
}
delete this.__callbacks[callbackId];
}
};
}

6. Common Use Cases and Examples

In addition to the functions mentioned earlier, JSBridge can be used for the following:

Example 1: Open Native Camera

1
2
3
4
5
6
7
8
9
function openCamera() {
callNative('CameraModule', 'openCamera', {})
.then((imageData) => {
console.log('Image captured:', imageData);
})
.catch((error) => {
console.error('Error opening camera:', error);
});
}

Example 2: Get User Location

1
2
3
4
5
6
7
8
9
function getUserLocation() {
callNative('LocationModule', 'getUserLocation', {})
.then((location) => {
console.log('User location:', location);
})
.catch((error) => {
console.error('Error getting location:', error);
});
}

Example 3: Send Notification

1
2
3
4
5
6
7
8
9
function sendNotification(title, message) {
callNative('NotificationModule', 'sendNotification', { title, message })
.then(() => {
console.log('Notification sent successfully');
})
.catch((error) => {
console.error('Error sending notification:', error);
});
}

Example 4: Get User Login Info

1
2
3
4
5
6
7
8
9
function getUserInfo() {
callNative('UserModule', 'getUserInfo', {})
.then((userInfo) => {
console.log('User Info:', userInfo);
})
.catch((error) => {
console.error('Error fetching user info:', error);
});
}

7. Conclusion

JSBridge plays a vital role in hybrid app development, enabling efficient communication between web and native layers.
By understanding its principles and implementation, developers can harness its full potential to improve both development efficiency and user experience.

With proper use of JSBridge’s versatile features, you can significantly enrich the interactivity and capabilities of your application.