Summary
On iOS, agent-device's Metro/dev-server runtime hint (open --metro-host/--metro-port, metro reload, metro prepare) does not point an expo-dev-client app at the chosen Metro server. It writes bare-React-Native's RCT_jsLocation preference, which an expo-dev-client ignores — so the app keeps loading from its own dev-server URL (or embedded bundle) instead of the requested port.
This is the iOS analogue of the Android debug_http_host-wrong-file bug fixed in #1242: the intent is right, but the mechanism targets bare-RN while the app framework (expo-dev-client) reads a different source.
Root cause
applyIosSimulatorRuntimeHints in src/daemon/runtime-hints.ts sets RCT_jsLocation (+ RCT_packager_scheme) in the app's NSUserDefaults via simctl. Bare RN's RCTBundleURLProvider reads RCT_jsLocation, so this works for bare-RN debug apps. But an expo-dev-client resolves its dev-server from its own launcher state / the exp+<scheme>://expo-development-client/?url=<metro-url> deep-link, not RCT_jsLocation — so the hint is silently a no-op.
Evidence (verified live, iPhone 17 Pro simulator)
- After
open com.callstack.agentdevicelab --metro-host 127.0.0.1 --metro-port 8085, defaults read com.callstack.agentdevicelab RCT_jsLocation returned 127.0.0.1:8085 — the hint was written correctly.
- The app nonetheless did not request a bundle from Metro on 8085 (Metro logged only "Waiting on http://localhost:8085"); it kept running its own bundle.
- The dev build does register the
exp+agent-device-test-app URL scheme (the expo-dev-client launcher handler), confirming it is an expo-dev-client and that the exp+…://expo-development-client/?url= path is the intended mechanism.
Suggested fix direction
Detect an expo-dev-client target (it registers an exp+<scheme> CFBundleURLScheme in Info.plist) and, for those, point Metro via the expo mechanism instead of RCT_jsLocation:
- Launch/redirect via
xcrun simctl openurl <udid> "exp+<scheme>://expo-development-client/?url=<url-encoded-metro-url>".
- agent-device already computes the correct expo bundle URL via
metro prepare --kind expo (.expo/.virtual-metro-entry.bundle), so the pointing side is the gap.
Important caveat (separate limitation)
An embed-first dev build — one shipped with a baked main.jsbundle and configured to launch straight into the embedded bundle rather than the dev-launcher — runs the embedded bundle regardless of any metro hint or deep-link. That case genuinely requires a native rebuild (expo run:ios) and is not solvable by the fix above; only launcher-style expo-dev-clients benefit.
Context
Surfaced while capturing live over-filtering evidence for the replay-divergence chrome filter (PR #1233). Related: #1242 (the Android debug_http_host counterpart).
Summary
On iOS, agent-device's Metro/dev-server runtime hint (
open --metro-host/--metro-port,metro reload,metro prepare) does not point an expo-dev-client app at the chosen Metro server. It writes bare-React-Native'sRCT_jsLocationpreference, which an expo-dev-client ignores — so the app keeps loading from its own dev-server URL (or embedded bundle) instead of the requested port.This is the iOS analogue of the Android
debug_http_host-wrong-file bug fixed in #1242: the intent is right, but the mechanism targets bare-RN while the app framework (expo-dev-client) reads a different source.Root cause
applyIosSimulatorRuntimeHintsinsrc/daemon/runtime-hints.tssetsRCT_jsLocation(+RCT_packager_scheme) in the app's NSUserDefaults viasimctl. Bare RN'sRCTBundleURLProviderreadsRCT_jsLocation, so this works for bare-RN debug apps. But an expo-dev-client resolves its dev-server from its own launcher state / theexp+<scheme>://expo-development-client/?url=<metro-url>deep-link, notRCT_jsLocation— so the hint is silently a no-op.Evidence (verified live, iPhone 17 Pro simulator)
open com.callstack.agentdevicelab --metro-host 127.0.0.1 --metro-port 8085,defaults read com.callstack.agentdevicelab RCT_jsLocationreturned127.0.0.1:8085— the hint was written correctly.exp+agent-device-test-appURL scheme (the expo-dev-client launcher handler), confirming it is an expo-dev-client and that theexp+…://expo-development-client/?url=path is the intended mechanism.Suggested fix direction
Detect an expo-dev-client target (it registers an
exp+<scheme>CFBundleURLSchemeinInfo.plist) and, for those, point Metro via the expo mechanism instead ofRCT_jsLocation:xcrun simctl openurl <udid> "exp+<scheme>://expo-development-client/?url=<url-encoded-metro-url>".metro prepare --kind expo(.expo/.virtual-metro-entry.bundle), so the pointing side is the gap.Important caveat (separate limitation)
An embed-first dev build — one shipped with a baked
main.jsbundleand configured to launch straight into the embedded bundle rather than the dev-launcher — runs the embedded bundle regardless of any metro hint or deep-link. That case genuinely requires a native rebuild (expo run:ios) and is not solvable by the fix above; only launcher-style expo-dev-clients benefit.Context
Surfaced while capturing live over-filtering evidence for the replay-divergence chrome filter (PR #1233). Related: #1242 (the Android
debug_http_hostcounterpart).