mcpField
S
simdeck

simdeck

github.com/nativescript测试与质量158110 次安装7 周前更新
代码仓库

关于 simdeck

simdeck 通过命令行和浏览器界面自动化 iOS 模拟器与 Android 模拟器,面向 Agent 驱动的移动应用检查和测试。它将设备控制、界面交互及测试 API 集中在本地服务中。

主要功能

  1. 01控制 iOS 与 Android 模拟器
  2. 02检查界面层级并按选择器操作
  3. 03批量命令与 simdeck/test API
  4. 04截图、录屏、日志和统计信息
  5. 05为 iOS 应用模拟摄像头画面

适用场景

  1. 01自动运行移动应用界面测试流程
  2. 02检查屏幕并验证界面状态
  3. 03采集模拟器证据与诊断信息

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/nativescript/simdeck --skill simdeck

安装后在 Claude Code 中输入/simdeck确认已加载。

详细介绍

SimDeck Agent 指南

SimDeck 可自动操作 iOS 模拟器和 Android 模拟器。使用 CLI 进行自动化,并通过浏览器 UI 实时查看。iOS 支持 NativeScript、UIKit、SwiftUI、React Native、Expo 和 Flutter 应用;Android 实时查看使用模拟器的 -share-vid 共享显示界面,以及 SimDeck 原生主机 H.264 编码器;生命周期管理、屏幕截图、日志和 UIAutomator 层级结构转储也通过 ADB 处理。

SimDeck 使用一个长期运行的本地服务。运行 simdeck;它会启动或复用后台服务,并打印浏览器 URL 和配对码。只有在需要 SimDeck 自行打开默认浏览器时,才传入 --open。如果服务需要使用非默认端口,请传入 -p <port> 或 --port <port>。如果还需要将服务注册为 macOS LaunchAgent,请传入 -a 或 --autostart。

simdeck 的响应示例:

{
  "ok": true,
  "pairingCode": "401974",
  "pid": 91285,
  "projectRoot": "-",
  "started": true,
  "url": "http://127.0.0.1:4310"
}
simdeck
simdeck --open
simdeck -p 4311
simdeck -a
simdeck pair # prints LAN/Tailscale pairing URLs, code, and iOS QR
simdeck service stop
simdeck service kill # stops all SimDeck services from any binary
simdeck service restart

通常为 http://127.0.0.1:4310。如果希望浏览器 URL 打开时带上 ?device=<UDID>,请向 simdeck 传入模拟器名称或 UDID。默认端口不合适时,请使用 simdeck -p 4311。 需要与原生 iOS 客户端配对时,请使用 simdeck pair。此命令会启动或刷新由 LaunchAgent 管理的服务,检测 LAN 和 Tailscale IPv4 地址,并打印包含 simdeck://pair URL 的二维码。常规服务重启会保留令牌和配对码;只有需要轮换它们时,才使用 simdeck service reset。 需要清理已安装二进制文件和源码检出版本中的所有残留时,请使用 simdeck service kill 或 simdeck service killall。

可选:如果用户可能想通过手机控制当前模拟器,请运行 simdeck link [sim],打印一个 https://app.simdeck.sh/open 通用链接,在 iOS 上打开 SimDeck Studio(或在浏览器中打开启动页),并预先定位到已解析的模拟器。

始终先运行 simdeck,然后在有 Browser 工具时使用该工具在应用内浏览器中打开显示的 URL。

如果无法使用 Browser Use,只有此时才使用 simdeck --open;它会打开默认浏览器,并可能使焦点从应用切换出去。

设备和应用

首先选择项目的默认设备。simdeck use <UDID> 会为当前工作区/CWD 保存设备选择,因此后续命令可以省略 UDID。显式 UDID、--device、SIMDECK_DEVICE 和 SIMDECK_UDID 仍可用于临时覆盖。Agent 循环中优先使用简短形式,例如 simdeck tap "Continue" 和 simdeck snapshot --format agent --max-depth 2 -i。

simdeck list
simdeck list --format json
simdeck use <UDID>
simdeck boot <UDID>
simdeck boot android:<AVD_NAME> --android-emulator-arg=-no-snapshot
simdeck shutdown
simdeck erase
simdeck core-simulator restart
simdeck install /path/to/App.app
simdeck install /path/to/App.ipa
simdeck install android:<AVD_NAME> /path/to/app.apk
simdeck launch com.example.App
simdeck uninstall com.example.App
simdeck open-url myapp://route
simdeck open-url https://example.com
simdeck toggle-appearance
simdeck camera sources
simdeck camera start com.example.App --file /absolute/path/to/camera.mov
simdeck camera start com.example.App --webcam
simdeck camera switch --placeholder
simdeck camera status
simdeck camera stop

simdeck list 默认输出精简 JSON,以便 Agent 高效选择并节省令牌。只有需要完整路径和显示元数据时,才使用 simdeck list --format json。

使用项目工具构建应用。

Android 设备使用类似 android:Pixel_8_API_36 的 ID。simdeck list 会从 Android SDK 中发现 AVD。 SimDeck 管理的 Android 启动默认使用模拟器 gRPC 屏幕截图流进行实时视频传输,以模拟器共享视频界面作为备用,并使用 --android-gpu host。Android 浏览器视频流默认使用 60 fps 的软件 H.264 编码,并将长边限制为 960px,以确保模拟器 gRPC 帧生成保持流畅。在 macOS 上,受管理的启动会使用 -qt-hide-window,让 Qt 渲染循环保持运行,同时不显示原生模拟器窗口。 只有在主机 GPU 渲染不稳定时,才使用 simdeck service restart --android-gpu auto 或 --android-gpu swiftshader_indirect。可选的用户默认设置位于 ~/.simdeck/config.json。支持的键包括 service.port、android.emulatorArgs 和 android.disableAudio;临时运行时,显式 CLI/API 启动参数仍优先。

快速检查 Agent

针对测试循环使用定向检查。describe 是整个层级结构的诊断快照。验证时,优先使用 simdeck/test 暴露的服务 API:action、query、waitFor、assert、选择器 tap 和 batch。

simdeck describe
simdeck describe --format agent --max-depth 4
simdeck describe --format agent --max-depth 4 --interactive
simdeck snapshot --format agent --max-depth 4 -i
simdeck describe --format compact-json
simdeck describe --point 120,240
simdeck describe --source auto
simdeck describe --source nativescript|react-native|flutter|swiftui|uikit
simdeck describe --source native-ax
simdeck describe --source android-uiautomator
simdeck describe --direct
simdeck wait-for --label "Welcome" --timeout-ms 5000
simdeck wait --label "Welcome" --timeout-ms 5000
simdeck assert --id login.button --source auto --max-depth 8

默认来源是 native-ax,这是对 Agent 来说最快、适用范围最广的路径。若希望在回退到原生无障碍功能之前,先获取更丰富的 NativeScript、React Native、Flutter、SwiftUI 或 UIKit 检查器数据,请使用 --source auto。使用 --direct 或 --source native-ax 可访问私有的 CoreSimulator 无障碍桥接接口。使用 --source android-uiautomator 获取 Android 模拟器的 UIAutomator 层级结构。 对于 Android ID,describe 使用 uiautomator dump;与 iOS 一样,使用 --format agent 或 --format compact-json。 当 Agent 只需要控件和可操作的框架节点时,使用 --interactive 或 -i;SimDeck 会保留祖先上下文,因此输出仍可导航。Agent 输出会为节点标注 @e3 之类的引用;可通过 simdeck press @e3 重用这些引用。snapshot、press 和 wait 分别是 describe、tap 和 wait-for 的别名。

优先使用选择器,只在必要时使用坐标。选择器点击会通过服务执行,并在服务端等待元素出现。如果点击后还应等待下一屏再返回,请使用 --expect-id、--expect-label 或其他 --expect-* 选择器。

simdeck tap --id LoginButton --wait-timeout-ms 5000
simdeck tap --id com.apple.settings.screenTime --expect-id BackButton
simdeck tap --label "Continue" --element-type Button
simdeck tap 120 240
simdeck tap "Continue"
simdeck press @e3

对于持久化的应用集成测试,请使用 simdeck/test,而不要反复调用 Shell 命令:

import { connect } from "simdeck/test";

const udid = "your-device-udid";
const simdeck = await connect({ udid });

try {
  await simdeck.launch("com.example.App");
  await simdeck.waitFor({ id: "login.button" }, { maxDepth: 8 });
  await simdeck.tap(0.5, 0.5);
  await simdeck.assert({ label: "Welcome" }, { maxDepth: 8 });
  const matches = await simdeck.query({ id: "account.name" });
  console.log(matches);
} finally {
  simdeck.close();
}

simdeck/test 的状态查询辅助函数默认使用 source: "native-ax",以便快速控制 Agent。 只有在你明确希望先获取更丰富的框架检查器树、再回退到原生无障碍功能时,才传入 source: "auto"。

只有在测试需要输出整个 UI 以进行调试时,才使用 tree()/describe。在常规 Agent 循环中,不要在每次操作后都获取完整树;应验证能够证明步骤成功的特定元素或文本。

交互

simdeck tap 120 240
simdeck touch 0.5 0.5 --phase began --normalized
simdeck touch 0.5 0.5 --phase ended --normalized
simdeck touch 120 240 --down --up --delay-ms 800
simdeck swipe 200 700 200 200
simdeck swipe 200 700 200 200 --duration-ms 500 --pre-delay-ms 100 --post-delay-ms 250
simdeck gesture scroll-up
simdeck gesture scroll-down
simdeck gesture swipe-from-left-edge
simdeck gesture swipe-from-right-edge
simdeck pinch --start-distance 160 --end-distance 80
simdeck pinch --start-distance 0.20 --end-distance 0.35 --normalized --duration-ms 250 --steps 8
simdeck rotate-gesture --radius 100 --degrees 90
simdeck rotate-gesture --radius 0.12 --degrees 45 --normalized --duration-ms 250 --steps 8
simdeck type 'hello'
simdeck type --stdin
simdeck type --file message.txt
simdeck key enter
simdeck key 42 --duration-ms 500
simdeck key-sequence --keycodes h,e,l,l,o --delay-ms 75
simdeck key-combo --modifiers cmd,shift --key z
simdeck dismiss-keyboard
simdeck button software-keyboard
simdeck button home
simdeck back
simdeck button lock --duration-ms 1000
simdeck button side-button
simdeck button volume-up
simdeck button volume-down
simdeck button action --duration-ms 1000
simdeck button mute
simdeck button digital-crown
simdeck crown --delta 50
simdeck button left-side-button
simdeck button siri
simdeck button apple-pay
simdeck home
simdeck app-switcher
simdeck rotate-left
simdeck rotate-right
simdeck pasteboard set 'text'
simdeck pasteboard get

对于包含引号、换行符、Shell 变量或 Shell 敏感字符的文本,请使用 --stdin 或 --file。

计时与批处理

simdeck tap --label "Continue" --wait-timeout-ms 5000
simdeck tap --label "Continue" --expect-label "Done"
simdeck back
simdeck swipe 200 700 200 200 --pre-delay-ms 100 --post-delay-ms 250
simdeck button lock --duration-ms 1000

优先在批处理中使用 wait-for 或 assert 等待 UI 状态,而不是固定延迟。在批处理中,sleep 500 会等待 500 ms。若要明确使用秒数,请使用 sleep 0.5s 或 sleep --seconds 0.5。

步骤已确定时使用 batch;如果后续步骤依赖于解析前一步的输出,则使用单独的命令。

simdeck batch \
  --step "tap --label Continue --wait-timeout-ms 5000 --expect-label Done" \
  --step "type 'hello world'" \
  --step "back" \
  --step "pinch --start-distance 0.20 --end-distance 0.35 --normalized"

批处理规则:只能使用一个来源(--step、--file 或 --stdin);使用 simdeck use <UDID> 设置默认设备,或在批处理级别保留 <UDID>;步骤按顺序执行;默认遇错即停;使用 --continue-on-error 尽力继续。步骤命令:tap、back、wait-for、assert、swipe、gesture、pinch、rotate-gesture、touch、type、button、key、key-sequence、key-combo、sleep。

对于 JS 测试,批处理可以组合操作和验证,无需额外启动 CLI 进程:

await simdeck.batch([
  { action: "tap", selector: { label: "Continue" }, waitTimeoutMs: 5000 },
  {
    action: "waitFor",
    selector: { label: "Continue Tapped" },
    timeoutMs: 5000,
  },
  { action: "assert", selector: { id: "fixture.status" } },
]);

对于应用风格的流程,SimDeck 可以运行实用的 Maestro YAML 子集:

simdeck maestro test flow.yaml --artifacts-dir artifacts/maestro

证据

simdeck screenshot --output screen.png
simdeck screenshot --with-bezel --output screen-bezel.png
simdeck screenshot --stdout > screen.png
simdeck record --seconds 5 --output screen-recording.mp4
simdeck record --seconds 5 --stdout > screen-recording.mp4
simdeck logs --seconds 30 --limit 200
simdeck chrome-profile
simdeck processes
simdeck stats
simdeck stats --watch
simdeck sample --seconds 3

静态证据请使用屏幕截图;设备边框很重要时使用 --with-bezel;短 MP4 屏幕录制请使用 record。使用 stats 查看模拟器应用的 CPU、内存、磁盘写入、网络接收/发送速率、连接、卡顿以及崩溃/终止信号。只有在短时间 CPU 堆栈采集值得付出额外暂停时,才使用 sample。如果上下文足够,请优先使用 describe 获取节省 token 的状态转储。

摄像头模拟

当已启动的 iOS 模拟器应用需要确定性的摄像头画面时,使用 camera start。CLI 会与 SimDeck 守护进程通信,由它管理摄像头源和共享内存写入器,然后通过 simctl launch 将摄像头 shim 注入应用并重新启动应用包。只要守护进程的画面仍在运行,就可以使用 camera switch 在占位画面、媒体和网络摄像头源之间切换,而无需重新启动应用。

simdeck camera sources
simdeck camera start com.example.App --file /absolute/path/to/feed.mov --mirror off
simdeck camera switch --placeholder
simdeck camera start com.example.App --webcam "FaceTime HD Camera"
simdeck camera stop

媒体路径必须是绝对路径。URL 会被视为视频流。网络摄像头支持取决于 macOS 摄像头是否可用,以及 SimDeck 是否获得相应权限。

默认流程

  1. 启动 UI,列出设备,运行 simdeck use <UDID>,启动/选择设备;如果应用内浏览器可用,则打开查看器
  2. 使用项目工具进行构建;使用 SimDeck 安装并启动应用。
  3. 使用一次 describe --format agent --max-depth 4 来了解不熟悉的屏幕。
  4. 优先使用选择器进行交互;仅在需要时使用坐标。
  5. 使用 waitFor/assert/query 进行验证,而不是反复输出完整的 describe 结果。
  6. 批量执行已知流程;将 describe 作为失败/调试记录。
可选检查器插件

如果用户想选择启用,可获得更丰富的层级结构

NativeScript 检查器

NativeScript 应用可以通过 JS 直接连接到运行中的服务端,并公开其视图层级结构以及原始 UIKit 后备视图

import { startSimDeckInspector } from "@nativescript/simdeck-inspector";

if (__DEV__) {
  startSimDeckInspector({ port: 4310 });
}

运行时会通过 WebSocket 连接到 GET /api/inspector/connect

React Native 检查器

React Native 应用可以通过检查器包公开其组件树和 Metro 开发模式下的源代码位置:

import "react-native-simdeck/auto";
import "expo-router/entry";

在 expo-router/entry 或 AppRegistry.registerComponent(...) 之前导入它。开发环境之外,自动入口点不会执行任何操作;如果存在 EXPO_PUBLIC_SIMDECK_PORT,则会读取该变量,否则会扫描常见的 SimDeck 服务端口。需要自定义主机/路径/安全选项时,请使用手动的 startSimDeckReactNativeInspector(...) API。

评论

支持 Markdown