fix(android): actually download remote http(s) jsBundleSource#43
Merged
Conversation
Loading a sandbox from a remote URL never worked on Android: - `createBundleLoader` mapped an http(s) source to `JSBundleLoader.createFileLoader(url)`, but that loader calls `loadScriptFromFile`, which treats its argument as a local path — a remote URL is never downloaded. - Even with a working loader, the sandbox ReactHost was created with developer support enabled, so in dev builds the runtime ignored the loader and fetched the bundle from Metro using `jsMainModulePath`, turning `http://host/x.bundle` into `http://localhost:8081/http://host/x.bundle.bundle` (a 404). Fix: - Prefetch the remote bundle to a cache file off the main thread (avoids NetworkOnMainThreadException) and load it via `createCachedBundleFromNetworkLoader`, preserving the source URL for stack traces. Returns null (existing failure path) on download error. - Disable developer support for remote (http/https) sources only, so the runtime uses our loader instead of Metro. Local asset/name sources keep dev support and Fast Refresh. Verified on a device: host loads the sandbox bundle from a remote HTTP URL in a debug build, renders, and exchanges messages both ways. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The remote (http/https) loader downloaded the bundle on every sandbox VM creation, so each cold start re-fetched the full bundle and failed when offline. Treat a remote URL as immutable: if the cached file for that exact URL already exists, reuse it and skip the network. Repeated loads (cold starts) become instant and work offline; a partial/failed download is deleted so a later load retries cleanly. To publish an update, change the URL (version segment or `?v=` query) — a new URL misses the cache and is fetched once. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
createCachedBundleFromNetworkLoader loads the cached file with
loadSynchronously=false. On RN 0.85 bridgeless this executes the bundle
before the TurboModule JSI bindings are installed on the runtime, so the
bundle's InitializeCore hits TurboModuleRegistry.getEnforcing('PlatformConstants')
with no proxy registered and the sandbox VM aborts. Because this happens
before the sandbox error handler is installed, it escalates to a native
fatal and takes the host process down with it.
Load the already-downloaded cache file synchronously via
JSBundleLoader.createFileLoader(path, sourceURL, true) — mirroring how the
built-in asset loader runs the main bundle — so the runtime is ready before
the bundle runs. The original URL is kept as sourceURL for stack traces.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Extract remote bundle download logic into a private downloadRemoteBundle() function for clarity - Shorten the two inline comments in createBundleLoader to 2 lines each Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Supersedes #37 — incorporates all of @akelmanson's work with review feedback applied.
Summary
Loading a sandbox from a remote URL (
jsBundleSource="https://…/x.bundle") did not work on Android. Two issues compounded:createBundleLoadermapped anhttp(s)source toJSBundleLoader.createFileLoader(url), which treats its argument as a local file path — a remote URL never resolves.ReactHostImplwith dev support enabled ignoresjsBundleLoaderand fetches through Metro, mangling the URL intohttp://localhost:8081/http://host/x.bundle.bundle→ 404.Fix
NetworkOnMainThreadException), then load it viaJSBundleLoader.createFileLoader(cacheFile, sourceUrl, true)— synchronous load required on RN 0.85 bridgeless to sequence after TurboModule JSI bindingshttp(s)sources so Metro doesn't intercept the loaddownloadRemoteBundle()private functionChanges from #37
downloadRemoteBundle()(requested by @CAMOBAP)Co-authored-by: akelmanson akelmanson@users.noreply.github.com
🤖 Generated with Claude Code