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. 错误处理:统一的错误捕获和上报机制
相关推荐
孟健1 小时前
我的网站被黑了:一天灌入 227 万条垃圾数据,AI 写的代码差点让我社死
前端
anOnion2 小时前
构建无障碍组件之Checkbox pattern
前端·html·交互设计
IT枫斗者3 小时前
IntelliJ IDEA 2025.3史诗级更新:统一发行版+Spring Boot 4支持,这更新太香了!
java·开发语言·前端·javascript·spring boot·后端·intellij-idea
N***p3653 小时前
Spring Boot项目接收前端参数的11种方式
前端·spring boot·后端
享誉霸王5 小时前
15、告别混乱!Vue3复杂项目的规范搭建与基础库封装实战
前端·javascript·vue.js·前端框架·json·firefox·html5
a1117765 小时前
飞机躲避炸弹 网页游戏
前端·开源·html·threejs
夏乌_Wx5 小时前
mybash:简易 Shell 实现的设计思路与核心模块解析
linux·服务器·前端
滕青山6 小时前
URL编码/解码 核心JS实现
前端·javascript·vue.js
菜鸟小芯7 小时前
【GLM-5 陪练式前端新手入门】第五篇:响应式适配 —— 让个人主页 “见机行事”
前端·人工智能