Problem
When two sandboxes share the same origin on Android, they correctly share a Hermes VM — but the messaging bridge only works for the first one.
If you mount Weather A and Weather B both with origin="weather", and the sandbox JS calls globalThis.postMessage({type: 'rendered'}), only Weather A’s onMessage handler fires. Weather B never receives the event. The same applies to onError.
This happens because the JSI globals (postMessage, setOnMessage, error handler) are installed once per VM during host creation. They capture a reference to the first view’s native delegate. When the second view creates a surface on the same host, it doesn’t get its own bindings — it inherits the first view’s.
In practice, this means the second same-origin card in a feed can render content (the Fabric surface works independently), but it can’t communicate back to its host view. Ping/pong messaging, error reporting, and render-complete signals all route to the wrong card.
Expected behavior
Each sandbox view should independently receive messages from its own surface, even when sharing a VM. globalThis.postMessage() without a target origin should route to the calling surface’s parent view, not always to the first view that created the host.
Additional context
This is an architectural limitation of the current BindingsInstaller approach — JSI globals are per-runtime, not per-surface. iOS will have the same issue once origin-based sharing is implemented (see #28).
Environment
| Field |
Value |
| react-native-sandbox |
0.6.0 |
| React Native |
0.80.1 |
| Platform |
Android (SharedReactHost path) |
Problem
When two sandboxes share the same origin on Android, they correctly share a Hermes VM — but the messaging bridge only works for the first one.
If you mount Weather A and Weather B both with
origin="weather", and the sandbox JS callsglobalThis.postMessage({type: 'rendered'}), only Weather A’sonMessagehandler fires. Weather B never receives the event. The same applies toonError.This happens because the JSI globals (
postMessage,setOnMessage, error handler) are installed once per VM during host creation. They capture a reference to the first view’s native delegate. When the second view creates a surface on the same host, it doesn’t get its own bindings — it inherits the first view’s.In practice, this means the second same-origin card in a feed can render content (the Fabric surface works independently), but it can’t communicate back to its host view. Ping/pong messaging, error reporting, and render-complete signals all route to the wrong card.
Expected behavior
Each sandbox view should independently receive messages from its own surface, even when sharing a VM.
globalThis.postMessage()without a target origin should route to the calling surface’s parent view, not always to the first view that created the host.Additional context
This is an architectural limitation of the current
BindingsInstallerapproach — JSI globals are per-runtime, not per-surface. iOS will have the same issue once origin-based sharing is implemented (see #28).Environment