awesome-ios-sim:把 iOS 模拟器状态变成可版本化的代码

前言

在 DeepSeek Harness(DSH)里给智能体接 iOS 模拟器,常见做法是开放一个 shell,让它直接调 xcrun simctl。这条路的问题很实际:环境配置散落在脚本和没写进文档的 defaults 命令里,测试环境难以复现;模型拿到的只是一个无类型、不安全的 shell 入口,改了什么、按什么顺序改的,事后无从审计。

qubyyang/awesome-ios-sim 解决的就是这个问题。它不新增模拟器能力,而是把「变更模拟器状态」收进一条固定流程:

profile + current snapshot -> diff -> deterministic plan -> explicit confirmation -> audited apply

先有目标 profile 和当前快照,做 diff,生成确定性的有序操作计划,显式确认后才带审计地执行。下面按功能、安装、用法依次介绍。

这是什么

awesome-ios-sim 的定位是 Simulator State as Code:通过确定性 Swift CLI 与 MCP stdio server,将 iOS 模拟器状态捕获、diff、规划并安全应用为可复现的版本化 profile。作者为 qubyyang,MIT 许可证,当前项目状态为 alpha,状态 schema 为 v1alpha1

它同时面向三类使用者:iOS 开发者、CI 流水线,以及 AI 智能体。

核心功能

一条固定流程:capture → diff → plan → 确认 → apply

模拟器设置被转成可版本化的 JSON profile,可以和测试代码一起提交到仓库。任何变更都先离线生成计划、审查后再应用,计划是确定性的有序操作列表。

CLI 与 MCP server 共用同一套引擎

仓库产出两个可执行文件:ios-sim-state(CLI)与 ios-sim-state-mcp(MCP stdio server)。两者共享同一 planner、校验与 apply 门控,不会出现命令行和智能体各走一套逻辑的情况。

面向智能体的安全默认值

MCP 工具使用 JSON Schema 描述入参;simulator_apply 默认 dry-run,必须显式确认才会产生实际变更。

可复用的 layers 与 presets

内置 bootedclean-status-barshutdown 三个 preset,运行 ios-sim-state presets 可查看各自的描述。layer 只含可复用的 spec 字段,没有 target--layer--preset 可以按需要叠加的顺序重复传入,应用到 composediffplan。合并规则是确定的:标量后值覆盖,application 按 bundleIdentifier 替换,preference 按 domain + key 替换,状态栏字段按键合并。v1alpha1 没有通用的 delete/tombstone 操作符,想卸载应用要用 presence: "absent"

严格校验与执行回执

profile 由 v1alpha1 JSON Schema 校验,严格解码,拒绝未知字段与空标识符。apply 之后,每条执行回执记录实际执行的参数数组、退出码、stdout、stderr 与时间戳;apply 在第一个失败操作处停止。

只走公开 API,本地优先

所有变更仅通过 Apple 公开的 xcrun simctl 完成,不使用私有 CoreSimulator 框架。无守护进程、云账号、遥测或 API key。

安装与启用

先确认环境,再安装。

系统要求

  • macOS 13 或更高版本;
  • Swift 6;
  • 完整 Xcode 及 iOS 模拟器 runtime(inventory、snapshot、apply 实际操作都需要);
  • xcode-select 指向目标 Xcode 安装。

仅装 Command Line Tools 可以构建,但不含 CoreSimulator/simctl,做不了实际操作。

Homebrew 安装

brew tap qubyyang/awesome-ios-sim https://github.com/qubyyang/awesome-ios-sim
brew install qubyyang/awesome-ios-sim/awesome-ios-sim

在 Homebrew 尚未识别的 prerelease macOS 上,可能遇到 packages.*_dunno API 错误,可用源码 tap 模式绕过:

HOMEBREW_NO_INSTALL_FROM_API=1 \
  brew install qubyyang/awesome-ios-sim/awesome-ios-sim

需要注意:初期 Release 归档(Apple Silicon/Intel)尚未代码签名或公证;下一个 tagged 发行版将进行 Developer ID 签名与 Apple 公证,并改用 universal 归档。

源码安装

git clone https://github.com/qubyyang/awesome-ios-sim.git
cd awesome-ios-sim
swift build -c release

构建产物在 .build/release/ios-sim-state.build/release/ios-sim-state-mcp

作为 dsh-plugin 安装

npm 包 @qubyyang/awesome-ios-sim(版本 0.2.0-dev,OS 限 darwin,engines 要求 Node ^22.19.0 || >=24.0.0)导出 ./dsh-plugin,可作为 dsh-plugin bundle 安装到 DeepSeek Harness。README 的安装一节没有给出专门的 DSH 安装命令,仓库顶栏链接了 docs/DEEPSEEK_HARNESS.mddocs/MCP.md,DSH 集成的具体步骤以这两份文档为准。

典型用法

以仓库自带示例为例,走一遍完整流程。第一步列出运行时与模拟器:

swift run ios-sim-state inventory

输出为稳定的 JSON。第二步捕获一台模拟器的受管状态:

swift run ios-sim-state snapshot --device <UDID> > simulator.snapshot.json

第三步把层与预设按顺序叠加,生成完整的目标 profile:

swift run ios-sim-state compose \
  --profile Examples/ui-tests.profile.json \
  --preset clean-status-bar \
  --layer Examples/ui-tests.layer.json > simulator.composed.json

第四步离线生成确定性的有序操作计划:

swift run ios-sim-state plan \
  --profile Examples/ui-tests.profile.json \
  --snapshot Examples/ui-tests.snapshot.json > simulator.plan.json

第五步预览 apply 的行为。不带 --confirm 时默认 dry-run,不做任何变更:

swift run ios-sim-state apply --plan simulator.plan.json

经过上面的步骤审查计划后,加上 --confirm 真正执行,并用 --journal 保留执行日志:

swift run ios-sim-state apply \
  --plan simulator.plan.json \
  --confirm \
  --journal simulator.report.json

profile 本身长这样(取自 README 示例):

{
  "apiVersion": "awesome-ios-sim/v1alpha1",
  "kind": "SimulatorState",
  "metadata": { "name": "ui-tests" },
  "target": {
    "name": "iPhone 17 Pro",
    "runtime": "com.apple.CoreSimulator.SimRuntime.iOS-27-0"
  },
  "spec": {
    "power": "shutdown",
    "applications": [
      {
        "bundleIdentifier": "com.example.app",
        "sourcePath": "/absolute/path/to/Example.app",
        "running": true,
        "launchArguments": ["--uitesting"]
      }
    ],
    "preferences": [
      {
        "domain": "com.example.app",
        "key": "hasSeenOnboarding",
        "value": false
      }
    ],
    "statusBar": { "time": "09:41", "batteryLevel": 100 }
  }
}

有安全默认值的字段可以省略。power: "unchanged" 会在临时工作后恢复原电源状态;计划包含 erase 时,已启动的设备会先关机;boot 操作会等待 simctl bootstatus -b 完成再执行后续步骤。statusBar 只接受公开的 simctl status_bar 覆盖项,枚举值与数值范围在规划前就会校验。

适用场景与注意事项

适合两类人:一是需要在 CI 或团队中复现 iOS 模拟器测试环境的开发者,把 profile 和测试代码一起提交即可;二是给智能体接模拟器能力的 DSH 插件作者,用带 JSON Schema、默认 dry-run 的 MCP 工具替代裸 shell。

使用前注意:

  1. 项目处于 alpha 状态,schema 为 v1alpha1,后续可能变动;
  2. 应用含 erase 或移除应用操作的计划前,务必人工审查;
  3. apply 在第一个失败操作处停止,靠 journal 排查后续;
  4. 初期 Release 归档未签名、未公证,对供应链有要求的团队可以先走源码构建。

另外提醒一点:这类插件会以当前 dsh 进程的权限运行,安装前建议检查源码与许可证(本项目为 MIT)。

结尾

awesome-ios-sim 做的事情不复杂:把模拟器状态变成和代码一样可以提交、diff、审查的 profile,让智能体和人在同一套流程里操作,默认安全、事后可审计。目录页见 https://www.skillhub.cn/plugins/qubyyang/awesome-ios-sim,源码见 https://github.com/qubyyang/awesome-ios-sim

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜