JSBridge 原理详解

什么是 JSBridge

JSBridge 是 WebView 中 JavaScript 与 Native 代码之间的通信桥梁。核心问题是:两个不同运行环境的代码如何互相调用?


通信原理

1. Native 调用 JS(简单)

WebView 本身就提供了执行 JS 的能力,原理很直接:WebView 控制着 JS 引擎,可以直接向其注入并执行代码。

java 复制代码
// Android
webView.evaluateJavascript("window.appCallJS('data')", null);

// iOS
webView.evaluateJavaScript("window.appCallJS('data')")

// Flutter
webViewController.runJavaScript("window.appCallJS('data')");

2. JS 调用 Native(核心难点)

JS 运行在沙箱中,无法直接访问系统 API。有两种主流方案:

方案一:注入 API

Native 在 WebView 初始化时,向 JS 全局对象注入方法:

java 复制代码
// Android - 注入对象到 window
webView.addJavascriptInterface(new Object() {
    @JavascriptInterface
    public void showToast(String msg) {
        Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
    }
}, "NativeBridge");

JS 端直接调用:

javascript 复制代码
window.NativeBridge.showToast("Hello")

本质:Native 把自己的方法"挂"到了 JS 的全局作用域里。

方案二:URL Scheme 拦截

JS 发起一个特殊协议的请求,Native 拦截并解析:

javascript 复制代码
// JS 端
location.href = 'jsbridge://showToast?msg=Hello'

// 或使用 iframe(避免页面跳转)
const iframe = document.createElement('iframe')
iframe.src = 'jsbridge://showToast?msg=Hello'
document.body.appendChild(iframe)
java 复制代码
// Android 端拦截
webView.setWebViewClient(new WebViewClient() {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (url.startsWith("jsbridge://")) {
            // 解析 url,执行对应 Native 方法
            return true;
        }
        return false;
    }
});

本质:利用 WebView 的 URL 加载机制作为通信通道。


异步回调的实现

JS 调用 Native 后如何拿到返回值?通过回调 ID 机制:

javascript 复制代码
// JS 端
let callbackId = 0
const callbacks = {}

function callNative(method, params) {
    return new Promise((resolve) => {
        const id = callbackId++
        callbacks[id] = resolve
        // 告诉 Native:调用完成后,用这个 id 回调我
        window.NativeBridge.invoke(JSON.stringify({
            method,
            params,
            callbackId: id
        }))
    })
}

// Native 执行完后调用这个函数
window.handleCallback = (id, result) => {
    callbacks[id]?.(result)
    delete callbacks[id]
}

流程 :JS 调用 → Native 处理 → Native 调用 evaluateJavascript 执行回调函数 → JS 收到结果


各平台注入对象命名

平台/插件 全局对象名 是否可自定义
Android 原生 任意 ✅ 完全自定义
iOS WKWebView webkit.messageHandlers.xxx ✅ xxx 部分可自定义
flutter_inappwebview flutter_inappwebview ❌ 插件固定
webview_flutter 需要自己实现 ✅ 完全自定义

Android 示例

java 复制代码
// 第二个参数就是 JS 中的对象名,可以随便取
webView.addJavascriptInterface(bridgeObject, "MyBridge");
javascript 复制代码
// JS 端
window.MyBridge.method()

iOS 示例

swift 复制代码
// name 就是 JS 中的 handler 名
configuration.userContentController.add(self, name: "iOSBridge")
javascript 复制代码
// JS 端
window.webkit.messageHandlers.iOSBridge.postMessage(data)

Flutter (flutter_inappwebview) 示例

dart 复制代码
// Flutter 端注册 handler,handlerName 可自定义
webViewController.addJavaScriptHandler(
  handlerName: 'myCustomHandler',
  callback: (args) { ... }
);
javascript 复制代码
// JS 端,flutter_inappwebview 是固定的
window.flutter_inappwebview.callHandler('myCustomHandler', data)

通信方式总结

方向 原理 实现方式
Native → JS WebView 控制 JS 引擎 evaluateJavascript
JS → Native 注入或拦截 addJavascriptInterface / URL Scheme

常见通信方式对比

方式 优点 缺点 适用场景
JavaScript Bridge 双向通信、支持回调 需要约定协议 复杂交互
URL Scheme 简单、兼容性好 单向、数据量有限 简单跳转
postMessage 标准 API 需要 WebView 支持 iframe 通信
注入 JS 对象 调用方便 Android 4.2 以下有安全漏洞 频繁调用

最佳实践建议

  1. 统一封装:抽离成独立的 bridge 工具类,统一管理通信逻辑
  2. 消息队列:处理 Native 未就绪时的调用,避免丢失消息
  3. 超时处理:添加超时机制,防止回调永远不返回
  4. 类型安全:使用 TypeScript 定义消息类型
  5. 错误处理:统一的错误捕获和上报机制
相关推荐
mqcode11 小时前
Vue3 + Element Plus + Vite 企业级后台框架搭建全流程
前端
SL-staff11 小时前
Web 白板技术架构深度解析:从渲染到协作的选型哲学
前端·架构
微扬嘴角11 小时前
react篇4--setState、LazyLoad和Hooks
前端·javascript·react.js
杨梦馨11 小时前
万级数据表格卡死?Web Worker 一招搞定
前端·javascript·vue.js
阿明在折腾11 小时前
从Canvas到AI模型:我在线工具站里的图片处理实战
前端·后端
CainChen12 小时前
Chrome 远程调试 Android 卡在 Pending authentication 的解决办法
前端
杨运交12 小时前
[030][Web模块]Spring Boot 验证与 OpenAPI 集成实战:从校验规则到文档生成
前端·spring boot·python
天le12 小时前
基于cocos3.x复刻《猪了个猪》挪了个船:位置生成实现
前端
青木_JS12 小时前
qiankun 子应用重开后仍显示旧数据?问题出在模块顶层的 useStore()
前端
货拉拉技术12 小时前
面向 Agent Skill 的 CLI/SSO 鉴权体系:安全、无感、可追溯
前端·agent