跨端原生交互设计深度解析
跨端原生交互:Bridge、JSI、Native Module 的设计与通信封装。 讲清如何安全桥接原生能力,掌握后能答出「跨端怎么调起相机/定位等原生模块」。
一句话概括
RN 从 Bridge 到 JSI 的演进,本质是把 JS 和 Native 之间那条”翻译走廊”拆掉,让双方直接握手——JSON 序列化消失,调用延迟从毫秒级降到微秒级。
核心知识点
1. Bridge 的代价:四次序列化
1
2
3
4
5
6
// 老 RN 一个简单的 NativeModules.Device.getBatteryLevel() 要走:
// JS → JSON 序列化 → Bridge 队列 → Native 线程 → JSON 反序列化
// → 执行 → JSON 序列化 → Bridge 队列 → JS 线程 → JSON 反序列化
// 四次序列化 + 两次跨线程通信,合计 5-15ms
// 单次看不出来,但在 FlatList 快速滚动时 => 掉帧
2. JSI 的革命:零序列化
1
2
3
4
5
6
7
// JSI 允许 C++ 直接持有 JS 对象的引用,反之亦然
// 没有 JSON,没有消息队列,就是函数指针调用
// 老 Bridge:
NativeModules.Device.getBattery() // 6.2ms
// 新 JSI:
global.batteryHost.getBatteryInfoSync() // 0.08ms (77倍提升)
3. Flutter Platform Channel:二进制 Codec
1
2
3
4
5
6
7
8
9
// Flutter 走的是另一条路:二进制编码而非 JSON
// StandardMessageCodec 比 JSON 快 30%-50%
// 但仍然是异步的,跨 Isolate 传输
class BatteryChannel {
static const channel = MethodChannel('com.app/battery');
static Future<int> getLevel() =>
channel.invokeMethod('getBatteryLevel');
}
4. 三种通信模式
1
2
3
// ① JS → Native 单次调用:NativeModules.X.method(args) → Promise
// ② Native → JS 事件推送:sendEvent('eventName', data)
// ③ JS → Native 带回调:method(args, callback) — JSI 下回调是同步的
5. 线程模型
1
2
3
4
5
6
UI 线程 (主线程) ← 渲染、手势、动画
JS 线程 ← 业务逻辑、React diff
Native Module 线程 ← Bridge 调用的执行线程
关键:JS 线程 ≠ UI 线程,所以 JSI 同步调用不卡 UI
但如果 Native 侧在主线程干重活,UI 照样卡
其实你每天都在用
- Animated API:RN 的动画之所以不掉帧,是因为 Animated 的值计算跑在 Native 线程,完全绕过 Bridge
- CameraRoll.getPhotos():返回的不是 base64 的图片数据,而是文件 URI——巨大的性能差异
- Platform.OS === ‘ios’:这行代码的背后就是 JSI 读取的编译期常量,不是 Bridge 调用
- FlatList 的 onEndReached:每一次回调都是 Native → JS 的 Bridge 消息,这就是为什么你总感觉”加载更多”有点延迟
- react-native-permissions:每个权限检查都是一次 Bridge 调用,所以推荐一次性请求所有权限而非逐个请求
常见误解(FAQ)
❌ 误区一:”Bridge 太慢了,老项目没救了”
慢的是大 JSON 和高频调用,不是 Bridge 本身。优化手段包括:传 URI 而非 base64、批量合并调用、用 TurboModule 渐进迁移高频模块。老 Bridge 在绝大多数业务场景(按钮点击、页面跳转、数据请求)是够用的。
❌ 误区二:”JSI 能解决所有性能问题”
JSI 消除了 Bridge 的序列化开销,但 Map、Filter、Diff 等纯 JS 计算并没有变快——这些需要 Hermes 引擎 + 代码优化来解决。JSI 解决的只是通信瓶颈,不是业务逻辑瓶颈。
❌ 误区三:”Swift 写的 Native Module 和 ObjC 一样用”
Swift 类必须继承 NSObject 并标记 @objc 才能被 RN 的 Bridge 发现。Swift 的 struct、enum、protocol 默认对 Bridge 不可见。如果你用了 Swift Concurrency(async/await),Bridge 的 RCTPromiseResolveBlock 模式需要手动桥接。
❌ 误区四:”Flutter 的 Platform Channel 没有 RN 的 Bridge 好”
Flutter 的二进制 Codec + 无 JSON 方案实际上比老 RN Bridge 更快。Flutter 的缺点是 Channel 只能异步(所有 invokeMethod 返回 Future),而 JSI 可以同步。这是设计哲学差异,不是性能差距。
一句话总结
Bridge 让你能跨语言调用,JSI 让你忘了在跨语言调用——这就是 RN 新架构最大的进步,也是面试官最想听到的洞察。