Skip to main content

故事 4:Native Split Loader — RN 0.86 Bridgeless 从零打通

这是 OTA split bundle 的基础设施层。没有这一层,后面所有 JS 侧 registry / cache 修复都无从谈起。


用户看到什么

阶段现象
编译期brownfield package:ios 失败:executeApplicationScript selector 不存在
运行期React Native runtime is not ready / NO_RUNTIME
运行期Split bundle loading is unavailable / NO_LOADER
运行期-[SplitBundleLoader bridge]: unrecognized selector(TurboModule crash)
运行期segment 加载后 JS 仍报组件未注册(promise 过早 resolve)

演进时间线

1. RN 0.86 编译适配

RN 0.86 + RCT_REMOVE_LEGACY_ARCH=1 移除 Legacy Bridge 的 executeApplicationScript

修复:改走 Bridgeless — RCTBridgeProxy + jsi::Runtime::evaluateJavaScript

2026-07-08-split-bundle-loader-rn086-build.md

2. Segment 契约(registerSegmentWithId + segmentId)

错误做法executeApplicationScript 当主入口跑 — 不是 incremental segment。
错误做法:native 用 [path hash] 当 segment id — 与 Metro requireAsync(id) 不一致。

修复

  • Native 统一 registerSegmentWithId:path:
  • JS 传入 segmentId;单一来源 feature-segments.json(order=1, promo=2, shared=0)
  • Manifest / build-manifest 同步 segmentId

2026-07-08-split-bundle-segment-contract.md

3. Runtime 检测与 Promise 时序

根因 ARCTBridgeProxy 继承 NSProxyisKindOfClass 失败 → runtime null。
根因 Bresolve(nil)evaluateJavaScript 完成前调用 → JS 侧 registerFeature 尚未执行。

修复

  • 从 bridge 捕获 runtime;dispatchToJSThread 同步 eval 后再 resolve
  • JS:OTA 模式优先 native SplitBundleLoader.load,再 Metro fallback

2026-07-08-ota-runtime-not-ready.md

4. TurboModule + NSProxy 踩坑

问题原因修复
bridge unrecognized selector移除 @synthesize bridge恢复 __weak RCTBridge *_bridge
NO_LOADERrespondsToSelector: 对 NSProxy 返回 NO直接调用 proxy 上的 registerSegmentWithId:
Legacy 路径仍用错误 APILegacy 也用 registerSegmentWithId

最终:Codegen NativeSplitBundleLoader.ts + TurboModule JSI。

→ 详见 2026-07-08-split-bundle-segment-contract.md Follow-up 章节


架构图(面试白板)

JS bundleLoader.load(path, segmentId)


NativeSplitBundleLoader (TurboModule)

├─ Bridgeless: RCTBridgeProxy.registerSegmentWithId(id, path)
│ └─ ReactInstance::registerSegment → full eval segment

└─ Legacy (#ifndef RCT_REMOVE_LEGACY_ARCH):
RCTCxxBridge.registerSegmentWithId(id, path)

segmentId ← feature-segments.json ← build-bundles.js ← manifest

与 JS 层问题的边界

现象先看 Native(本故事)再看 JS(故事 1/2)
NO_RUNTIME / NO_LOADER
compile 失败
segment eval 日志有,但 not registeredpromise 时序 / segmentIdregistry / executeSplitBundleEntry
unknown modulesegmentId 错可能module graph / re-entry

STAR 口述(30 秒)

  • S:RN 0.86 New Architecture 下 OTA split bundle 编译不过,跑起来报 runtime not ready。
  • T:Brownfield 宿主能动态加载 Metro 构建的 segment bundle。
  • A:Legacy API 不可用 → Bridgeless eval;修正 segmentId 契约;修 NSProxy / TurboModule 调用链;promise 等 eval 完成再 resolve。
  • Rbrownfield:package:ios:debug 通过;OTA toggle 后 Order/Promo 可加载服务端 bundle。

细粒度记录