eas-simulator

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

EAS Simulator

EAS Simulator

EAS Simulator runs a remote iOS simulator or Android emulator on EAS infrastructure that you drive from your machine — from the CLI, from an AI agent (via
agent-device
), and from a browser preview. It's the unlock for environments that can't run a simulator locally (Linux boxes, cloud/background agents like Cursor Cloud), and for letting an agent verify a change on a real device instead of only reasoning about code.
The
simulator:*
commands are experimental and hidden, and need a recent eas-cli (≥ 20.3.0 as of writing) — which is why this skill runs everything via
npx --yes eas-cli@latest
. Flags and verbs may change; if a command fails,
<cmd> --help
is authoritative.
EAS Simulator 在EAS基础设施上运行远程iOS模拟器或Android模拟器,你可以通过本地机器、CLI、AI Agent(通过
agent-device
)以及浏览器预览来操控它。它为无法在本地运行模拟器的环境(Linux设备、Cursor Cloud等云/后台Agent)提供了解决方案,还能让Agent在真实设备上验证变更,而不仅仅是对代码进行推理。
simulator:*
命令是实验性且未公开的,需要使用最新版本的eas-cli(撰写本文时要求≥20.3.0)——这也是本技能通过
npx --yes eas-cli@latest
运行所有命令的原因。命令参数和动词可能会发生变化;如果命令执行失败,
<cmd> --help
是权威参考

When to use

适用场景

The frontmatter
description
carries the trigger phrases. In short: use this to get a user's app onto a cloud simulator and interact with it — especially from a Mac-less or cloud/sandbox agent. Not for local sims (
expo run:ios
, Xcode, Android Studio), store builds/signing (that's EAS Build), or physical devices. For the macOS case, see Cloud vs local next.
前置的
description
部分包含了触发短语。简而言之:使用本工具将用户的应用部署到模拟器并与之交互——尤其适用于无Mac设备或云/沙箱Agent的场景。不适用于本地模拟器(
expo run:ios
、Xcode、Android Studio)、应用构建/签名(这属于EAS Build的范畴)或物理设备。对于macOS场景,请查看下文的「云模拟器 vs 本地模拟器」。

Cloud vs local: decide this first

云模拟器 vs 本地模拟器:先做判断

  • Non-macOS (Linux / CI / cloud sandbox like Cursor Cloud, detect via
    uname -s
    Darwin
    ): the only way to get a sim — just proceed.
  • macOS: local sims exist and a cloud session costs money + latency, so ask first ("a remote cloud sim — to share a live preview, offload, or test an iOS version you lack — or just run locally?") unless the user explicitly said cloud/remote/shareable.
  • Always honor an explicit choice; for "run it locally" hand off to
    expo run:ios
    / Xcode.
bash
undefined
  • 非macOS系统(Linux / CI / Cursor Cloud等云沙箱,通过
    uname -s
    Darwin
    检测):这是获取模拟器的唯一途径——直接执行即可
  • macOS系统:本地模拟器已存在,且云会话会产生费用并存在延迟,因此先询问用户(“是使用远程云模拟器——用于共享实时预览、卸载负载或测试你缺少的iOS版本——还是直接在本地运行?”),除非用户明确提到云/远程/可共享。
  • 始终尊重用户的明确选择;如果用户选择“在本地运行”,则转交至
    expo run:ios
    / Xcode处理。
bash
undefined

Programmatic detection — run this to decide before doing anything else:

程序化检测——在执行任何操作前先运行此命令判断:

if [ "$(uname -s)" != "Darwin" ] || ! xcrun --find simctl &>/dev/null 2>&1; then echo "no local sim — proceed with EAS Simulator" else echo "local sim available — ask the user (cloud or local?)" fi
undefined
if [ "$(uname -s)" != "Darwin" ] || ! xcrun --find simctl &>/dev/null 2>&1; then echo "no local sim — proceed with EAS Simulator" else echo "local sim available — ask the user (cloud or local?)" fi
undefined

Prerequisites

前置条件

  • Run every
    eas
    command via
    npx --yes eas-cli@latest …
    — guarantees a CLI new enough to have
    simulator:*
    (a global
    eas
    is often too old), and
    --yes
    skips npx's prompt. (Bare
    eas
    is fine if
    eas --version
    is current.)
  • Authenticated. Interactive machine →
    npx --yes eas-cli@latest login
    . Cloud sandbox / CI / headless agent has no browser login — set
    EXPO_TOKEN
    (expo.dev → Account → Access Tokens) in the env instead. Verify either way with
    npx --yes eas-cli@latest whoami
    .
  • Run from an Expo project directory. A fresh app needs one-time setup:
    npx --yes eas-cli@latest init
    to create/link the project (when there's no
    projectId
    ), and set
    ios.bundleIdentifier
    in app config if it's missing — a fresh
    create-expo-app
    often has none, and
    prebuild
    /
    eas build
    need it (they prompt or fail without it; e.g.
    dev.<owner>.<slug>
    ). Read current config with
    npx expo config --json
    (it may live in
    app.config.js
    ). The first Mode-C run is slow (native build); later runs reuse it.
  • A controller to drive the device. This skill uses agent-device (open source, MIT), run on demand via
    npx agent-device@latest
    — nothing globally installed. argent is an alternative (
    --type argent
    in
    simulator:start
    ); see references/controllers.md.
  • .env.eas-simulator
    is written/managed by eas-cli (not this skill): it holds the session id (
    EAS_SIMULATOR_SESSION_ID
    ) + the daemon URL/token, so
    get
    /
    stop
    /
    exec
    default to that session (usually omit
    --id
    ; pass
    --id <id>
    to target another). It carries a token → keep it gitignored (eas-cli marks it "do not commit" but may not add the ignore rule, and a fresh app's
    .gitignore
    won't cover it — add
    .env.eas-simulator
    if missing).
  • --max-duration-minutes
    is paid-plan only; otherwise a default applies.
  • 所有
    eas
    命令均通过
    npx --yes eas-cli@latest …
    运行
    ——确保CLI版本足够新,支持
    simulator:*
    命令(全局安装的
    eas
    通常版本过旧),
    --yes
    参数会跳过npx的确认提示。如果
    eas --version
    显示版本符合要求,直接使用
    eas
    命令也可。
  • 已完成身份验证。交互式机器环境→执行
    npx --yes eas-cli@latest login
    云沙箱 / CI / 无头Agent环境无法通过浏览器登录——需在环境变量中设置
    EXPO_TOKEN
    (登录expo.dev → 账户 → 访问令牌)。可通过
    npx --yes eas-cli@latest whoami
    验证身份验证状态。
  • 在Expo项目目录下运行。全新应用需要一次性设置:执行
    npx --yes eas-cli@latest init
    创建/关联项目(当没有
    projectId
    时),并且如果缺少**
    ios.bundleIdentifier
    **,需在应用配置中设置——使用
    create-expo-app
    创建的全新应用通常没有该配置,而
    prebuild
    /
    eas build
    需要它(如果缺少会提示或失败;例如设置为
    dev.<owner>.<slug>
    )。可通过
    npx expo config --json
    查看当前配置(配置文件可能是
    app.config.js
    )。首次运行Mode-C会较慢(需要构建原生代码);后续运行会复用构建结果。
  • 需要一个控制器来驱动设备。本技能使用agent-device(开源,MIT协议),通过
    npx agent-device@latest
    按需运行——无需全局安装。argent是替代方案(在
    simulator:start
    中使用
    --type argent
    );详情请参阅references/controllers.md
  • .env.eas-simulator
    由eas-cli管理(而非本技能):它存储会话ID(
    EAS_SIMULATOR_SESSION_ID
    )以及守护进程URL/令牌,因此
    get
    /
    stop
    /
    exec
    命令默认针对该会话(通常
    省略
    --id
    参数
    ;如需针对其他会话,传递
    --id <id>
    )。该文件包含令牌→需设置为git忽略(eas-cli会标记“请勿提交”但可能不会添加忽略规则,全新应用的
    .gitignore
    也不会覆盖它——如果缺少,需添加
    .env.eas-simulator
    .gitignore
    )。
  • --max-duration-minutes
    仅付费计划可用;否则使用默认时长。

The core loop (always the same)

核心流程(始终一致)

A session is: start → (install your app) → drive → stop.
eas-cli
owns the session; the device verbs (open/tap/screenshot) come from the controller, which
npx --yes eas-cli@latest simulator:exec
runs for you with the session's connection env loaded.
bash
undefined
一个会话流程为:启动 →(安装应用)→ 操控 → 停止
eas-cli
负责管理会话;设备操作动词(打开/点击/截图)来自控制器,通过
npx --yes eas-cli@latest simulator:exec
加载会话连接环境变量后运行。
bash
undefined

1. Start a session (boots the remote sim + agent-device daemon; writes .env.eas-simulator).

1. 启动会话(启动远程模拟器 + agent-device守护进程;写入.env.eas-simulator)。

printf '# managed by eas-cli\n' > .env.eas-simulator # clear any stale session first npx --yes eas-cli@latest simulator:start --platform ios --type agent-device --non-interactive
printf '# managed by eas-cli\n' > .env.eas-simulator # 先清除任何过期会话 npx --yes eas-cli@latest simulator:start --platform ios --type agent-device --non-interactive

Then confirm it's live: simulator:get --json → status IN_PROGRESS (bounded poll in run-your-app.md).

然后确认会话已激活:simulator:get --json → 状态为IN_PROGRESS(详情请参阅run-your-app.md中的轮询逻辑)。

2. Drive it through
exec
(loads the session env, then runs the command you give it).

2. 通过
exec
操控设备(加载会话环境变量,然后运行指定命令)。

agent-device runs on demand via npx — nothing installed globally.

agent-device通过npx按需运行——无需全局安装。

npx --yes eas-cli@latest simulator:exec npx agent-device@latest open <app-or-url> --platform ios npx --yes eas-cli@latest simulator:exec npx agent-device@latest snapshot -i # interactive UI tree → @e1, @e2 refs npx --yes eas-cli@latest simulator:exec npx agent-device@latest press @e2 # tap a ref (NOTE: 'press', not 'tap') npx --yes eas-cli@latest simulator:exec npx agent-device@latest screenshot ./shot.png
npx --yes eas-cli@latest simulator:exec npx agent-device@latest open <app-or-url> --platform ios npx --yes eas-cli@latest simulator:exec npx agent-device@latest snapshot -i # 交互式UI树 → @e1、@e2等引用 npx --yes eas-cli@latest simulator:exec npx agent-device@latest press @e2 # 点击引用(注意:使用'press',而非'tap') npx --yes eas-cli@latest simulator:exec npx agent-device@latest screenshot ./shot.png

3. Stop (ends billing; tears down the VM) and reset the dotenv. Omit --id to target the dotenv session.

3. 停止会话(结束计费;销毁虚拟机)并重置环境变量文件。省略--id参数会针对.env.eas-simulator中的会话。

npx --yes eas-cli@latest simulator:stop printf '# managed by eas-cli\n' > .env.eas-simulator

To **watch** it live, hand the user the `webPreviewUrl` that `start` prints (an `--type agent-device` iOS session runs serve-sim alongside the daemon, so it emits one — agent control *and* a browser preview in one session; Android has no preview, and `--type serve-sim` is preview-only). **This URL is for the *user's* browser — you cannot open it for them, and it must never touch the sim:**
- **"Open it here" (Cursor/VS Code)** → print the URL on its own line and tell the user to open Simple Browser (`Cmd/Ctrl+Shift+P` → "Simple Browser: Show") and paste it. Then **stop**: do not shell out to a system browser or a Cursor/VS Code URL handler, and do not ask "did a tab appear?" — you can't confirm it, the handoff is done.
- **Never `open` the `webPreviewUrl` on the sim.** It's a browser preview, not a deep link and not an `agent-device open` argument; routing it to the device renders a browser-in-a-browser (a real past failure).
- **Headless agent** (no display) → just return the URL as the deliverable.
- **Keeping it alive for the user to drive** → bound it: start with `--max-duration-minutes N` so it auto-stops; tell them it bills until stopped and when it auto-stops; offer to reopen/extend when it ends. (This is the one case where "stop right away" doesn't apply; one-shot `screenshot`/`get` runs still stop immediately.)

`start` also prints a job-run URL.
npx --yes eas-cli@latest simulator:stop printf '# managed by eas-cli\n' > .env.eas-simulator

如需**实时查看**模拟器画面,将`start`命令输出的`webPreviewUrl`提供给用户(`--type agent-device`的iOS会话会在守护进程旁运行serve-sim,因此会生成该URL——一个会话同时支持Agent操控和浏览器预览;Android没有预览功能,`--type serve-sim`仅提供预览)。**该URL仅用于用户的浏览器——你无法为用户打开它,且绝对不能将其发送到模拟器:**
- **“在此打开”(Cursor/VS Code)** → 单独一行打印URL,并告知用户打开Simple Browser(`Cmd/Ctrl+Shift+P` → “Simple Browser: Show”)并粘贴URL。然后**停止操作**:不要调用系统浏览器或Cursor/VS Code的URL处理器,也不要询问“标签页是否打开?”——你无法确认,交接完成即可。
- **绝对不要在模拟器上`open` `webPreviewUrl`**。这是浏览器预览链接,不是深度链接,也不是`agent-device open`的参数;如果发送到设备,会出现浏览器嵌套浏览器的情况(这是过往实际出现过的问题)。
- **无头Agent**(无显示设备)→ 直接返回该URL作为交付结果。
- **让用户持续操控会话** → 设置时长限制:启动时使用`--max-duration-minutes N`参数,使其自动停止;告知用户会话会持续计费直到停止,以及自动停止的时间;会话结束时可提供重新开启/延长的选项。(这是“立即停止”规则的唯一例外;单次截图/查询操作仍需立即停止会话。)

`start`命令还会输出一个作业运行URL。

Commands at a glance

命令概览

CommandPurpose
npx --yes eas-cli@latest simulator:start --platform ios|android [--type agent-device|argent|serve-sim] [--package-version X] [--max-duration-minutes N] [--non-interactive] [--json]
Create a session; boot the sim + controller; write
.env.eas-simulator
; print
webPreviewUrl
+ job-run URL
npx --yes eas-cli@latest simulator:exec <cmd> [args…]
Load
.env.eas-simulator
, then run
<cmd>
with that env. The bridge to the controller.
npx --yes eas-cli@latest simulator:get [--id] [--json]
Session status + connection details. Use this to confirm readiness (see Operating principles).
npx --yes eas-cli@latest simulator:list [--status …] [--type …] [--platform …]
List an app's sessions
npx --yes eas-cli@latest simulator:stop [--id]
Stop a session (idempotent)
命令用途
npx --yes eas-cli@latest simulator:start --platform ios|android [--type agent-device|argent|serve-sim] [--package-version X] [--max-duration-minutes N] [--non-interactive] [--json]
创建会话;启动模拟器 + 控制器;写入
.env.eas-simulator
;输出
webPreviewUrl
+ 作业运行URL
npx --yes eas-cli@latest simulator:exec <cmd> [args…]
加载
.env.eas-simulator
,然后在该环境下运行
<cmd>
。这是与控制器交互的桥梁。
npx --yes eas-cli@latest simulator:get [--id] [--json]
查询会话状态 + 连接详情。使用此命令确认会话已就绪(请参阅「操作原则」)。
npx --yes eas-cli@latest simulator:list [--status …] [--type …] [--platform …]
列出应用的所有会话
npx --yes eas-cli@latest simulator:stop [--id]
停止会话(幂等操作)

Running the user's app — pick a mode

运行用户应用——选择模式

The remote sim boots blank — no Expo Go, no apps. Install a build, then drive it — but match the build type to the goal first (the box below); that's where live-session runs derail. Full sequences: references/run-your-app.md — read before running a mode.
Match the build to the goal before installing anything — this is where live-session runs derail. Two traps, same root (grabbing a build that doesn't fit the request):
  1. Wrong type. Live edits (Mode C) require a dev build. A static build — a local Release (A), the default EAS sim build (B), or any build left on the sim from an earlier screenshot run — freezes its JS at build time and can never hot-reload. For a live request, ignore existing builds entirely and install a dev build (local Debug, or an EAS build with
    developmentClient: true
    ). Never reconnect Metro to a static build hoping it'll reload — it won't.
  2. Stale. A static look must match current source — reuse only a fingerprint-matched build, else build fresh; reuse is explicit-only.
So a leftover EAS/release build is not a shortcut for "iterate live" — it's the wrong binary. The fact that a build exists never makes it the right one.
ModeWhat it isChoose whenLive edits?
A — Local release buildBuild a Release
.app
locally,
agent-device install
it (uploads)
User has a Mac toolchain and wants a quick "run my current code on a cloud device"No (rebuild to see changes)
B — EAS build (rare, explicit-only)
eas build
a simulator build,
agent-device install-from-source <url>
(the VM downloads it)
Only when explicitly asked — the user names an existing/EAS build, or wants a static EAS artifact for CI/sharing. Not for "show me"/"iterate" (use C). Sim builds need no credentials.No
C — Local dev build + tunnelDev (Debug) build +
EXPO_UNSTABLE_TUNNEL_V2=1 expo start --tunnel
+ connect the dev client to Metro
The agentic edit-and-see loop — change code and see it live (Fast Refresh)Yes
Quick decision — default to C; A and B are explicit-only:
  • C (almost everything): iterate, interact, poke the app, live edits — and most "show me my app" (current code needs a build anyway, so live+current wins). Mac → dev client builds locally; no Mac → build it on EAS (
    developmentClient: true
    ). Unsure → C.
  • A: only an explicit one-shot static screenshot on a Mac.
  • B: only when the user names an existing/EAS build or wants a static EAS artifact (CI/sharing) — see the box above for why a static build is the wrong tool for "iterate."
远程模拟器启动时是空白状态——没有Expo Go,也没有任何应用。需要先安装构建包,然后操控——但首先要根据目标匹配构建包类型(如下方方框内容);这是实时会话运行失败的常见原因。完整流程请参阅:references/run-your-app.md——运行前务必阅读。
在安装任何内容前,先根据目标匹配构建包类型——这是实时会话运行失败的常见原因。 两个陷阱,根源相同(使用了不符合需求的构建包):
  1. 类型错误。实时编辑(Mode C)需要开发构建包。静态构建包——本地Release版本(A)、默认EAS模拟器构建包(B)或之前截图运行后留在模拟器上的任何构建包——会在构建时冻结JS代码,永远无法热重载。对于实时编辑请求,完全忽略现有构建包,安装开发构建包(本地Debug版本,或启用
    developmentClient: true
    的EAS构建包)。永远不要尝试重新连接Metro到静态构建包以实现重载——这行不通。
  2. 版本过期。静态预览必须匹配当前源代码——仅复用指纹匹配的构建包,否则重新构建;复用需明确操作。
因此,遗留的EAS/Release构建包不是“快速迭代”的捷径——它是错误的二进制文件。构建包的存在绝不意味着它是合适的选择。
模式说明适用场景支持实时编辑?
A — 本地Release构建包在本地构建Release版本的
.app
,通过
agent-device install
安装(上传到模拟器)
用户拥有Mac工具链,想要快速“在云设备上运行当前代码”否(需重新构建才能查看变更)
B — EAS构建包(罕见,仅明确指定时使用)通过
eas build
构建模拟器构建包,通过
agent-device install-from-source <url>
安装(虚拟机下载)
仅当用户明确要求时使用——用户指定了现有/EAS构建包,或需要用于CI/共享的静态EAS产物。不适用于“展示我的应用”/“迭代开发”(请使用C模式)。模拟器构建包无需凭据。
C — 本地开发构建包 + 隧道开发(Debug)构建包 +
EXPO_UNSTABLE_TUNNEL_V2=1 expo start --tunnel
+ 将开发客户端连接到Metro
Agent驱动的编辑-预览循环——修改代码后实时查看(Fast Refresh)
快速决策——默认选择C模式;A和B模式仅在明确指定时使用
  • C模式(几乎所有场景):迭代开发、交互操作、调试应用、实时编辑——以及大多数“展示我的应用”场景(当前代码仍需构建,因此实时+最新版本是最佳选择)。Mac设备→本地构建开发客户端;无Mac设备→在EAS上构建(启用
    developmentClient: true
    )。不确定时→选择C模式
  • A模式:仅适用于Mac设备上明确要求的单次静态截图场景。
  • B模式:仅当用户指定现有/EAS构建包或需要用于CI/共享的静态EAS产物时使用——请参阅上方方框了解为什么静态构建包不适合“迭代开发”。

Driving the device (agent-device)

操控设备(agent-device)

agent-device
is the controller. Common verbs (run each as
npx --yes eas-cli@latest simulator:exec npx agent-device@latest <verb>
):
VerbDoes
apps --platform ios
List installed apps (the blank sim shows none)
install <appId> <path> --platform ios
Install a local
.app
(uploads it)
install-from-source <url> --platform ios
Install from a URL — the VM downloads it (use for EAS artifacts)
open <appId|deep-link> --platform ios
Launch an app (bundle id) or follow an app deep link (
exp+slug://…
). Not for the
webPreviewUrl
— that's a browser preview for the user, never the device.
snapshot -i
Interactive accessibility tree →
@e1
-style refs
press <ref|selector>
Tap (e.g.
press @e2
or
press 'label="Open"'
) — the tap verb is
press
, not
tap
fill <ref> "text"
Type into a field
screenshot <path>
Capture the screen to a local PNG (downloaded from the daemon) — requires an app to be open (
open
first)
metro prepare
/
metro reload
Point a dev client at Metro / reload (Mode C)
For the full verb set and the
argent
controller alternative, see references/controllers.md.
agent-device
是控制器。常用操作动词(每个动词需通过
npx --yes eas-cli@latest simulator:exec npx agent-device@latest <verb>
运行):
动词功能
apps --platform ios
列出已安装的应用(空白模拟器显示为空)
install <appId> <path> --platform ios
安装本地
.app
文件(上传到模拟器)
install-from-source <url> --platform ios
从URL安装——虚拟机下载(用于EAS产物)
open <appId|deep-link> --platform ios
启动应用(bundle id)或打开应用深度链接
exp+slug://…
)。请勿用于
webPreviewUrl
——这是给用户的浏览器预览链接,绝不能发送到设备。
snapshot -i
生成交互式可访问性树 →
@e1
样式的引用
press <ref|selector>
点击(例如
press @e2
press 'label="Open"'
)——点击操作使用
press
动词,而非
tap
fill <ref> "text"
在输入框中输入文本
screenshot <path>
捕获屏幕并保存为本地PNG文件(从守护进程下载)——需要先打开应用(先执行
open
命令)
metro prepare
/
metro reload
将开发客户端指向Metro / 重载应用(C模式)
完整动词列表以及替代控制器
argent
的详情,请参阅references/controllers.md

Operating principles

操作原则

The non-obvious mental model worth internalizing. Specific error→fix lookups (hung verbs,
tap
press
,
--platform
,
--json
,
pod install
locale, orphaned sessions, boot variability) live in references/troubleshooting.md.
  1. Establish ground truth, then reset — don't patch-loop. Never assume an existing session or Metro is yours or healthy. Before driving, confirm:
    • cwd — you're in the intended Expo project dir (a misdirected
      start
      /
      exec
      sessions the wrong app + drops a stray
      .env.eas-simulator
      ;
      pwd
      / check
      app.json
      ).
    • session live
      IN_PROGRESS
      via
      simulator:get --json
      (a stopped session keeps its id +
      remoteConfig
      , so the dotenv alone isn't proof).
    • one Metro on
      :8081
      — reuse if it's yours, else free the port before starting (run-your-app.md).
    • build fits intent — a release build can't live-reload; if live edits are wanted and a release build is installed, install the dev build, don't reconnect.
    If current code isn't rendering after your first connect, stop poking live state: reset to baseline (stop session → clear dotenv → kill Metro) and redo the mode once; a second failure → stop and report. Never restart Metro in place, reconnect more than once, rebuild the native client to fix a JS/connection problem, or surface a preview URL while state is unknown. (A daemon drop —
    ERR_NGROK_3200
    /
    Remote daemon is unavailable
    — is the same: reset, don't retry.)
  2. exec
    is a wrapper, not a driver.
    simulator:exec
    loads
    .env.eas-simulator
    and spawns the command you pass; the device verbs come from the controller (
    npx agent-device@latest
    ). There is no
    simulator:tap
    .
  3. Act immediately; don't park an idle session. Sessions are short-lived — install and drive right after
    start
    . Leaving one idle drops the tunnel/daemon (→ reset, per #1).
  4. Stop on every exit path (billing) and reset the dotenv.
    --non-interactive
    doesn't auto-stop, and a forgotten session bills until stopped. Don't
    start
    again to "retry" a slow boot — that orphans a second billed session.
  5. Screenshot only the correct, fresh build. Mode C only after the dev client connects to Metro; A/B only from a build matching current source — reusing a pre-existing build is the #1 "my edits don't show" cause (see the build caveat above). (
    9:41
    in the status bar is the sim default, not staleness.)
需要理解一些非直观的核心逻辑。具体错误→修复方案(如操作卡住、
tap
press
--platform
参数、
--json
参数、
pod install
区域设置、孤立会话、启动差异)请参阅references/troubleshooting.md
  1. 先确认基准状态,再重置——不要循环修补。永远不要假设现有会话或Metro是可用且健康的。在操控前,确认:
    • 当前工作目录——你位于目标Expo项目目录中(错误的
      start
      /
      exec
      命令会为错误的应用创建会话,并留下孤立的
      .env.eas-simulator
      文件;可通过
      pwd
      / 检查
      app.json
      确认)。
    • 会话已激活——通过
      simulator:get --json
      查询状态为
      IN_PROGRESS
      (已停止的会话仍保留ID +
      remoteConfig
      ,因此仅环境变量文件不足以证明会话已激活)。
    • 仅一个Metro实例运行在
      :8081
      端口
      ——如果是你启动的则复用,否则在启动前释放端口(请参阅run-your-app.md)。
    • 构建包符合需求——Release构建包无法热重载;如果需要实时编辑但已安装Release构建包,安装开发构建包,不要重新连接Metro
    如果首次连接后当前代码未正常渲染,不要继续修改实时状态:重置到基准状态(停止会话 → 清除环境变量文件 → 终止Metro),然后重新执行一次对应模式;如果第二次仍失败→停止操作并报告问题。永远不要原地重启Metro、多次重新连接、重新构建原生客户端以修复JS/连接问题,或在状态未知时提供预览URL。(守护进程断开——
    ERR_NGROK_3200
    /
    Remote daemon is unavailable
    ——处理方式相同:重置,不要重试。)
  2. exec
    是包装器,而非驱动程序
    simulator:exec
    加载
    .env.eas-simulator
    并启动你传递的命令;设备操作动词来自控制器(
    npx agent-device@latest
    )。不存在
    simulator:tap
    命令。
  3. 立即操作;不要让会话闲置。会话是短期的——启动后立即安装并操控应用。闲置会话会导致隧道/守护进程断开(→ 按照第1点重置)。
  4. 在所有退出路径上停止会话(避免计费)并重置环境变量文件
    --non-interactive
    参数不会自动停止会话,遗忘的会话会持续计费。不要通过“重新启动”来重试缓慢的启动——这会产生第二个计费的孤立会话。
  5. 仅对正确的、最新的构建包截图。C模式仅在开发客户端连接到Metro后截图;A/B模式仅对匹配当前源代码的构建包截图——复用预构建包是“我的编辑未显示”的头号原因(请参阅上方构建包注意事项)。(状态栏显示
    9:41
    是模拟器默认时间,并非版本过期的标志。)

Stop and clean up

停止并清理

Stop the session (ends billing) and reset the dotenv so a later run doesn't try to reuse the dead session:
bash
npx --yes eas-cli@latest simulator:stop          # omit --id → stops the dotenv session (or pass --id <id>)
printf '# managed by eas-cli\n' > .env.eas-simulator   # clear the stale session id so it isn't reused
停止会话(结束计费)并重置环境变量文件,避免后续运行尝试复用已失效的会话:
bash
npx --yes eas-cli@latest simulator:stop          # 省略--id → 停止环境变量文件中的会话(或传递--id <id>指定会话)
printf '# managed by eas-cli\n' > .env.eas-simulator   # 清除过期会话ID,避免被复用

if you started Metro for Mode C, stop it too (Ctrl+C in its terminal, or kill the expo process)

如果为C模式启动了Metro,也需要停止它(在终端按Ctrl+C,或终止expo进程)

undefined
undefined

References

参考资料

  • references/run-your-app.md — full tested command sequences for modes A, B, and C (read before running a mode).
  • references/controllers.md — agent-device verb reference and the
    argent
    alternative.
  • references/troubleshooting.md — concrete errors and fixes.
Source of truth: Expo docs and the
eas
/
agent-device
CLIs (
npx --yes eas-cli@latest simulator:* --help
,
agent-device --help
). This skill teaches how to apply them; it doesn't replace them.
  • references/run-your-app.md——A、B、C模式的完整测试命令序列(运行前务必阅读)。
  • references/controllers.md——agent-device动词参考以及
    argent
    替代方案。
  • references/troubleshooting.md——具体错误及修复方案。
权威来源:Expo文档以及
eas
/
agent-device
CLI(
npx --yes eas-cli@latest simulator:* --help
agent-device --help
)。本技能仅教授如何应用这些工具;不能替代官方文档。