OTA split bundle — React Native runtime is not ready
Date: 2026-07-08
Problem
In OTA mode, remote pages failed to load with:
React Native runtime is not ready
Native rejected with NO_RUNTIME before the split bundle could execute.
Root cause
Two issues in SplitBundleLoader.mm (RN 0.86 bridgeless / RCTBridgeProxy):
-
Runtime detection —
isKindOfClass:[RCTBridgeProxy class]fails becauseRCTBridgeProxysubclassesNSProxy.NSProxyreports+classasNSProxy, so the kind check never matches andRuntimeForBridgereturnednullptr. -
Promise timing —
resolve(nil)was called immediately after schedulinginvokeAsync, beforeevaluateJavaScriptfinished. JS then calledgetFeatureComponentbeforeregisterFeatureran in the split bundle.
Solution
- Native (
SplitBundleLoader.mm): Stop usingCallInvoker::invokeAsync+CurrentBridge()(runtime was null in that callback). UseRCTBridgeProxy'sdispatchBlock:queue:RCTJSThread(dispatchToJSThread) to run on the JS runtime thread, capture the runtime pointer from the bridge at load time, and callevaluateJavaScriptsynchronously before resolving the promise. - JS (
bundleLoader.ts): When OTA toggle is on, load cached file via nativeSplitBundleLoaderbefore any Metro fallback.
Files changed
rn_app/ios/BrownfieldLib/SplitBundleLoader.mmrn_app/src/features/bundleLoader.ts
Verification
- Rebuild brownfield package:
npm run brownfield:package:ios:debug:sim→ BUILD SUCCEEDED - Run app from Xcode (or reinstall
ios_nativeif it embeds the framework). - Toggle OTA on a Remote page → check for updates → open Order/Promo.
- Page should load server bundle content without
NO_RUNTIMEerror.
Notes
RCTBridgeProxy.runtimelogs a migration warning; this is expected for split-bundle loading until RN exposes a public RuntimeExecutor API for third-party loaders.