Mastering JSBridge: Two‑Way Communication Between WebView and Native
JSBridge (JSB) enables bidirectional communication between a WebView’s JavaScript environment and native mobile code, covering WebView basics, platform-specific APIs, interception and injection methods, callback handling, and practical demos for both Android and iOS, helping developers implement robust cross‑platform bridges.
What Is JSB
When an H5 page runs inside a mobile WebView, it often needs information or capabilities provided by the native side. JSB (JavaScript Bridge) serves as the bridge that allows two‑way communication between the Web and Native environments.
WebView Overview
WebView is a mobile component that provides a sandbox for JavaScript execution. It can load URLs, intercept requests, and expose various interfaces that JSB relies on. Historically, Android and iOS have two sets of WebView kernels:
iOS 8+ – WKWebView
iOS 2‑8 – UIWebView
Android 4.4+ – Chrome
Android 4.4‑ – WebKit
In the following text, “high version” refers to iOS 8+ or Android 4.4+, while “low version” refers to the older kernels.
JSB Principles
Two‑way communication requires implementing both Native‑to‑Web and Web‑to‑Native messaging.
Native → Web Messaging
Native sends a message by dynamically executing JavaScript in the WebView, usually by calling a globally exposed method. Android and iOS provide different APIs for this.
Methods
Android
Low version: WebView.loadUrl (no callback)
High version: WebView.evaluateJavascript (returns JS result)
iOS
Low version: UIWebView.stringByEvaluatingJavaScriptFromString (no callback)
High version: WKWebView.evaluateJavaScript (returns JS result)
Demo: Native calls a JS function that creates a <p> element and returns a string.
document.querySelector('#test').innerHTML = 'I am from native';Another demo adds a global function evaluateByNative and calls it from the native button.
function evaluateByNative(params) {
const p = document.createElement('p');
p.innerText = params;
document.body.appendChild(p);
return 'Hello Bridge!';
}Web → Native Messaging
Web‑to‑Native can be implemented via two main patterns: interception and injection.
Interception
Native intercepts URL requests from the WebView. A custom URL scheme (e.g., bytedance://) is defined for JSB calls. Native hooks:
Android – shouldOverrideUrlLoading iOS 8+ – decidePolicyForNavigationAction iOS 8‑ – shouldStartLoadWithRequest The typical flow creates an invisible iframe whose src is the custom scheme plus parameters.
// Web creates an iframe to trigger a native request
const CUSTOM_PROTOCOL_SCHEME = 'prek';
function web2Native(event) {
const messagingIframe = document.createElement('iframe');
messagingIframe.style.display = 'none';
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + event;
document.documentElement.appendChild(messagingIframe);
setTimeout(() => {
document.documentElement.removeChild(messagingIframe);
}, 200);
}Interception is widely compatible but suffers from message loss, URL length limits, and higher latency on Android.
Injection
Native injects objects or methods into the JavaScript global context, allowing JS to call native code directly.
Android – addJavascriptInterface (security risk before API 17)
iOS 8+ – WKScriptMessageHandler iOS 7+ – JavaScriptCore Example (iOS):
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
context[@"getAppInfo"] = ^(msg) {
return @"ggl_2693";
};
window.getAppInfo(); // returns 'ggl_2693'Comparison
Interception – No compatibility issues, poorer performance, URL length limit.
Injection – Works on Android 4.2+ and iOS 7+, better performance, no length limit.
Handling Callbacks
To receive a response from native, the Web can attach a unique callback identifier to the request (similar to JSONP) and expose a global function. Native executes that function with the result after processing.
// Web side
const uniqueID = 1;
function webCallNative(event, params, callback) {
if (typeof callback === 'Function') {
const callbackID = 'jsb_cb_' + (uniqueID++) + '_' + Date.now();
window[callbackID] = callback;
}
const src = 'bytedance://getAppInfo?' + JSON.stringify({callback: callbackID});
// send request via chosen method
}
// Native side parses URL, obtains result, then:
window[callbackID](result);Unified Event‑Emitter Model
Ideally, JSB behaves like a cross‑platform EventEmitter: Web can web.call(event, params, cb) and web.on(event, handler), while Native can native.call(event, params, cb) and native.on(event, handler). This model abstracts away the underlying interception or injection details.
Final Thoughts
The bridge used by the author’s team is the latest internal SDK, offering a smooth experience without the pitfalls of older implementations. Understanding JSB fundamentals—WebView basics, platform APIs, interception vs. injection, and callback mechanisms—helps developers build reliable cross‑platform bridges.
References
1. JSONP: https://en.wikipedia.org/wiki/JSONP
2. WebViewJavascriptBridge: https://github.com/marcuswestin/WebViewJavascriptBridge
3. JSB_Demo: https://code.byted.org/caocheng.viccc/JSB_Demo
4. 深入浅出 JSBridge: https://juejin.cn/post/6936814903021797389#heading-8
5. JSB 实战: https://juejin.cn/post/6844903702721986568
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
