关于 ios-simulator-skill
ios-simulator-skill 提供一组脚本,用于在模拟器中构建、测试和自动化 iOS 应用。它面向开发者和测试 Agent,以无障碍数据进行导航和交互,而非依赖屏幕坐标。
主要功能
- 01执行 Xcode 构建与测试
- 02基于无障碍信息映射和操作界面
- 03控制模拟器外观、位置和媒体
- 04无障碍审计与截图差异比较
- 05记录测试并生成调试快照
适用场景
- 01运行 iOS 项目的构建和测试
- 02按标签或无障碍 ID 导航应用界面
- 03测试定位及照片选择器行为
- 04结合日志和状态快照排查界面问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ conorluddy/ ios-simulator-skill --skill ios-simulator-skill安装后在 Claude Code 中输入/ios-simulator-skill确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlscripts/accessibility_audit.pyapp_launcher.pyapp_state_capture.pyappearance.pybuild_and_test.pyclipboard.pycontainer.pygesture.pyhang_watcher.pykeyboard.pylocalization_audit.pylocation.pylog_monitor.pymedia.pymodel_inspector.pynavigator.pyprivacy_manager.pypush_notification.pyscreen_mapper.pysim_health_check.shsim_list.pyscripts/common/__init__.pycache_utils.pydevice_utils.pyenv_config.pyhang_pipeline.pyhang_sessions.pyidb_utils.pyscreenshot_utils.py详细介绍
iOS Simulator 技能
使用无障碍功能驱动的导航和结构化数据,而非像素坐标,来构建、测试和自动化 iOS 应用。
快速入门
# 1. Check environment
bash scripts/sim_health_check.sh
# 2. Launch app
python3 scripts/app_launcher.py --launch com.example.app
# 3. Map screen to see elements
python3 scripts/screen_mapper.py
# 4. Tap button
python3 scripts/navigator.py --find-text "Login" --tap
# 5. Enter text
python3 scripts/navigator.py --find-type TextField --enter-text "[email protected]"
路径: scripts/ 相对于包含此 SKILL.md 的目录,而非用户的项目目录。
为简洁起见,示例中使用 scripts/...;从用户的项目目录运行时,请使用绝对路径
(例如 python3 <skill-dir>/scripts/navigator.py ...),这样相对的 Xcode 项目路径仍可正确解析。
所有脚本都支持使用 --help 查看详细选项;大多数脚本支持使用 --json 输出机器可读结果。
导航策略
导航时始终优先使用无障碍树,而非截图。 无障碍树会提供元素类型、标签、框架和点击目标——这些结构化数据比图像分析成本更低,也更可靠。
请按以下优先级使用:
screen_mapper.py→ 结构化元素列表(5-7 行,约 10 个词元)navigator.py --find-text/--find-type/--find-id→ 语义化交互- 截图 → 仅用于视觉验证、错误报告或视觉差异对比
根据尺寸不同,截图消耗 1,600–6,300 个词元。默认模式下,无障碍树仅消耗 10–50 个词元。
30 个生产级脚本
构建与开发(2 个脚本)
-
build_and_test.py - 构建 Xcode 项目、运行测试,并通过渐进式披露解析结果
- 实时流式显示构建结果
- 从 xcresult 包中解析错误和警告
- 按需获取详细构建日志
- 选项:
--project、--scheme、--clean、--test、--verbose、--json
-
log_monitor.py - 实时监控日志并进行智能过滤
- 流式输出日志或按时长捕获日志
- 按严重性(error/warning/info/debug)过滤
- 对重复消息去重
- 选项:
--app、--severity、--follow、--duration、--output、--json
设备状态(3 个脚本)
-
appearance.py - 控制模拟器外观:深色模式、动态文字大小、对比度和语言区域
- 通过
xcrun simctl ui切换浅色/深色主题 - 使用易记别名设置动态文字大小(XS 到 AX5)
--contrast high|normal切换增强对比度,并读取设置以确认结果;--reset也会恢复正常对比度- 写入语言区域和地区默认值;可通过
--bundle-id选择重启应用 - 对 ar/he/fa/ur/yi 语言区域自动标记 RTL
- 选项:
--theme、--text-size、--contrast、--locale、--region、--reset、--bundle-id、--udid、--json、--verbose
- 通过
-
location.py - 模拟 GPS 坐标、预设城市位置和 GPX 场景播放
- 使用
--lat/--lng固定坐标,或使用--city选择城市 - 使用
--gpx <scenario>播放内置场景(City Run、Freeway Drive 等) - 使用
--waypoints和--speed,以可配置速度动态播放多途经点路线 - 使用
--clear清除模拟位置;使用--list-scenarios列出可用场景 - 选项:
--lat、--lng、--city、--gpx、--waypoints、--speed、--clear、--list-scenarios、--udid、--json、--verbose
- 使用
-
media.py - 为照片选择器测试填充或清空照片图库
- 通过
xcrun simctl addmedia使用--add a.jpg b.png添加照片 - 使用
--clear --yes通过idb photos clear清空图库(idb 1.7+);--clear --yes --add会清空图库,并仅保留新添加的文件 - 如果图库中有照片,未指定
--yes时,--clear会拒绝执行(照片无法恢复):请先询问用户 - 文件缺失时立即失败
- 选项:
--add、--clear、--yes、--udid、--json
- 通过
导航与交互(5 个脚本)
-
screen_mapper.py - 分析当前屏幕并列出可交互元素
- 按元素类型分类
- 可交互按钮列表
- 文本字段状态
- 如果带标签的元素覆盖屏幕的比例低于 10%,则添加一行
Coverage:,建议使用--deep --deep通过 idb 的 axbridge 后端读取(idb 1.7+):还能看到 Safari/WKWebView 内容和默认读取会遗漏的应用内提醒,以及许多未标记的容器视图。它会开启设备的辅助功能自动化模式(之后不会恢复)。网页内容框架的位置相对于 Web 视图,因此使用--deep查找元素,而不要用它获取点击坐标- 选项:
--verbose、--hints、--deep、--json
-
navigator.py - 按语义查找并与元素交互
- 按文本查找(模糊匹配,或使用
--find-exact精确匹配);交互式叶子元素的排序优先级高于标签相同的容器 - 按元素类型查找
- 按辅助功能 ID 查找
- 输入文本或点击元素
- 对具有唯一辅助功能 ID 或标签的 Button/Link/Switch/CheckBox/Tab 使用
--tap时,会通过辅助功能按下操作(idb 1.7+),因此悬浮搜索栏等叠加层无法拦截该操作;输出会显示(accessibility press)。否则会点击框架中心 --set-value TEXT无需键盘即可替换字段的值(支持任意字符,idb 1.7+)。焦点不会移动,因此如果之后需要按 Return 键提交,请使用--enter-text在确认成功之前会回读该值(安全字段除外);如果值不匹配,则退出码为 1- 仅当元素的值为 VALUE 时,
--tap --expect VALUE才会点击(开关:1表示开启,0表示关闭);否则不点击并以退出码 1 退出,因此重复执行“关闭 X”是安全的 - iOS 27 会将开关报告为
CheckBox。只有按下操作才能切换开关(即使在开关本身上执行 HID 触摸也不行);如果 ID 和标签都不唯一,输出会提示检查值 - 应用冻结时,在主线程响应之前,每次读取和点击都会停滞
- 失败信息中包含 idb 的标准错误输出(例如,配套进程已退出)
- 选项:
--find-text、--find-exact、--find-type、--find-id、--index、--tap、--expect、--tap-at、--enter-text、--set-value、--list
- 按文本查找(模糊匹配,或使用
-
gesture.py - 执行滑动、滚动、捏合和复杂手势
- 定向滑动(上/下/左/右)——
--swipe表示手指移动的方向 - 多次滑动滚动——
--scroll表示内容移动的方向(down会显示下方的内容) - 通过
idb ui pinch捏合缩放(--pinch out放大;--scale设置明确的缩放比例) - 通过
idb ui tap --duration长按 - 下拉刷新
--double-tap X,Y [--tap-count N]- 在某个点多次点击(idb 1.7+)--drag SOURCE DEST- 按住、拖动并松开;两端均可使用x,y或辅助功能标签,例如--drag "Row 1" "Row 4"(idb 1.7+)--rotate portrait|portrait-upside-down|landscape-left|landscape-right- 旋转设备(idb 1.7+)--shake- 摇动设备,用于调出调试菜单和撤销操作(idb 1.7+)- 选项:
--swipe、--swipe-from/--swipe-to、--scroll、--scroll-amount、--pinch、--scale、--long-press、--duration、--refresh、--double-tap、--tap-count、--drag、--rotate、--shake
- 定向滑动(上/下/左/右)——
-
keyboard.py - 文本输入和硬件按钮控制
- 输入文本(快速或慢速;仅支持 ASCII)
- 特殊按键(return、delete、tab、space、escape、方向键)、单个字母或原始 HID 代码
- 按键序列(
--key-sequence h,i,return) - 组合键:
--key z --command --shift(重做);--shift/--control/--option需要 idb 1.7+ - 清除当前聚焦字段(Cmd+A,然后 delete)
- 硬件按钮:home、lock/power、side、siri、apple-pay、volume-up/down(音量控制需要 idb 1.6.3+)
- 选项:
--type、--slow、--key、--shift、--control、--option、--command、--count、--key-sequence、--button、--clear、--dismiss
-
app_launcher.py - 应用生命周期管理
- 按 bundle ID 启动应用
- 终止应用
- 从 .app 包安装/卸载(
--uninstall需要--yes:应用数据会被删除) - 深度链接导航
- 列出已安装的应用
- 检查应用状态
- 在启动/重启应用时传递启动参数(
--args)和环境变量(--env KEY=VALUE,注入为SIMCTL_CHILD_*) - 选项:
--launch、--terminate、--restart、--install、--uninstall、--yes、--open-url、--list、--state、--args、--env、--wait-for-debugger
测试与分析(9 个脚本)
-
accessibility_audit.py - 检查当前屏幕是否符合 WCAG
- 严重问题(缺少标签、空按钮、没有替代文本)
- 警告(缺少提示、小型触控目标)
- 信息(缺少 ID、嵌套层级过深)
- 选项:
--verbose、--output、--json
-
visual_diff.py - 比较两张屏幕截图的视觉变化
- 逐像素比较
- 基于阈值判定通过/失败
- 生成差异图像
- 选项:
--threshold、--output、--details、--json
-
test_recorder.py - 自动记录测试执行过程
- 为每个步骤捕获屏幕截图和无障碍树
- 生成包含计时数据的 Markdown 报告
- 选项:
--test-name、--output、--verbose、--json
-
app_state_capture.py - 创建全面的调试快照
- 屏幕截图、UI 层级结构、应用日志、设备信息
- 用于 Bug 报告的 Markdown 摘要
- 选项:
--app-bundle-id、--output、--log-lines、--json
-
sim_health_check.sh - 验证环境配置是否正确
- 检查 macOS、Xcode、simctl、IDB、Python
- 列出可用和已启动的模拟器
- 验证 Python 软件包(Pillow)
-
model_inspector.py - 检查项目文件中的 Core Data 和 SwiftData 模型
- 解析 .xcdatamodeld 软件包(实体、属性、关系)
- 检测模型版本和当前活动版本
- 尽力提取 SwiftData @Model 类
- 按需转储任意模型的原始源代码(
--raw ModelName) - 选项:
--project-path、--core-data-only、--swiftdata-only、--show-versions、--raw、--verbose、--json
-
container.py - 检查应用沙盒:文件、UserDefaults 和 Core Data 存储路径
- 通过
--ls按可配置的深度列出数据容器中的文件 - 通过
--cat读取文件,并自动检测 plist 解码方式(大型文件会缓存) - 通过
--userdefaults将 UserDefaults 转储为键值对或 JSON - 通过
--core-data-path定位.sqlite/.sqlite-wal/.sqlite-shm存储文件 - 通过
--export导出完整的容器快照 - 选项:
--ls、--cat、--userdefaults、--core-data-path、--export、--udid、--json、--verbose
- 通过
-
hang_watcher.py (HangBuster) - 记录并汇总 os_log 卡顿事件,支持渐进式披露
- 会话模式(HangBuster,原生支持 Agent): 启动独立录制器,与模拟器交互,然后停止录制并获取精简摘要
--start→ 返回会话 ID;独立工作进程实时规范化事件并应用阈值--stop SESSION_ID→ 输出约 80–120 个 token 的 L1 摘要(标题 + 前 N 个聚类 + 深入查看提示)--get-details SESSION_ID [--cluster N | --raw]→ L2 完整聚类或 L3 单事件详情--list-sessions/--clear-sessions [--older-than 24h]/--diff A B(跨会话回归报告)- 过滤管线:解析 → 规范化 → 应用阈值 → 分桶 → 聚类 → 汇总 → 排序 → 格式化(位于
common/hang_pipeline.py) --budget-tokens N选择可容纳的最精简级别(L0/L1/L2);--terse强制使用 L0--auto-sample在每个聚类的首个事件发生时捕获主线程堆栈(软依赖:main_thread_sampler.py#62;若缺失则安全地不执行)
- 原始捕获模式(完整保真,便于使用
jq探索): 跳过聚类管线,将每一条匹配的日志原样写入raw.ndjson--start --raw-capture [--max-size-mb 10] [--no-gzip]— 启动log stream --style ndjson- 单会话大小上限(
--max-size-mb,默认值为 10)——工作进程达到上限后会正常停止;extras.truncated=true --stop将raw.ndjsongzip 压缩为raw.ndjson.gz(约 15–19 倍压缩;使用--no-gzip可跳过)- 对原始会话使用
--get-details SESSION_ID时,会显示文件路径及zcat | jq ...提示
- 弹性恢复(流中断时自动重启): EOF 或子进程退出会触发
stream_died事件,随后在 2 秒退避后进行有限次数的重启。达到IOS_SIM_HANG_MAX_RESTARTS(默认值为 3)后,会话将标记为crashed,不会停留在过时的running状态。--list-sessions会显示capture=Xs和restarts=N。 - 自动清理: TTL 清理(
IOS_SIM_HANG_SESSION_TTL_HOURS,默认值为 24h)和总量上限(IOS_SIM_HANG_TOTAL_CAP_MB,默认值为 100 MB,优先淘汰最早的会话)都会在每次运行--start时执行。 - 旧版模式(为向后兼容而保持不变):
--watch [--duration N](实时流)和--since 5m(历史记录) - 过滤器:
--bundle-id(解析后过滤——卡顿捕获仍以整个模拟器为范围,以保留 RunningBoard/SpringBoard 事件)、--predicate(也可通过IOS_SIM_HANG_PREDICATE指定) - 所有输出均支持
--json;会话存储于~/.ios-simulator-skill/sessions/<id>/{meta.json,events.jsonl,summary.json,raw.ndjson.gz}
快速开始(摘要模式):
SID=$(python3 scripts/hang_watcher.py --start --min-hang-ms 200) # ... 与模拟器交互(打开弹窗、滚动、导航)... python3 scripts/hang_watcher.py --stop $SID # 精简的 L1 摘要 python3 scripts/hang_watcher.py --get-details $SID --cluster 1 # 深入查看聚类 1 python3 scripts/hang_watcher.py --diff $SID_BASELINE $SID # 跨会话回归快速开始(原始捕获 +
jq探索):SID=$(python3 scripts/hang_watcher.py --start --raw-capture --max-size-mb 5) # ... 与模拟器交互... python3 scripts/hang_watcher.py --stop $SID # → "Session ...: raw mode, 737 lines, 0.96 MB → 0.05 MB gzipped" # 按事件数量排列的进程: zcat ~/.ios-simulator-skill/sessions/$SID/raw.ndjson.gz \ | jq -s 'group_by(.processImagePath) | map({proc: (.[0].processImagePath | split("/") | last), n: length}) | sort_by(-.n) | .[:5]' # 所有 RunningBoard 断言失效事件: zcat .../raw.ndjson.gz | jq -c 'select(.subsystem == "com.apple.runningboard" and (.eventMessage | startswith("Invalidating")))' # 每分钟的卡顿次数: zcat .../raw.ndjson.gz | jq -r '.timestamp[:16]' | sort | uniq -c - 会话模式(HangBuster,原生支持 Agent): 启动独立录制器,与模拟器交互,然后停止录制并获取精简摘要
-
localization_audit.py - 检测字符串目录中的缺漏、缺失键和占位符不匹配
- 报告
.xcstrings目录中每种语言环境下缺失和状态为needs_review/new的键 - 使用
--source将目录键与 Swift 源码(String(localized:)/NSLocalizedString)交叉比对 - 标记不同语言环境之间的占位符数量不匹配(
%d、%@、%s、%lld) - 通过
plistlib支持旧版.strings和.stringsdict - 适用于 CI 的
--strict会在发现任何问题时以状态码 2 退出 - 选项:
--catalog、--source、--locale、--strict、--json、--verbose
- 报告
高级测试与权限(4 个脚本)
-
clipboard.py - 管理模拟器剪贴板,以便测试粘贴
- 将文本复制到剪贴板
- 无需手动输入即可测试粘贴流程
- 选项:
--copy、--test-name、--expected、--json
-
status_bar.py - 覆盖模拟器状态栏外观
- 预设:clean(9:41、电量 100%)、testing(11:11、电量 50%)、low-battery(电量 20%)、airplane(离线)
- 自定义时间、网络、电量和 WiFi 设置
- 选项:
--preset、--time、--data-network、--battery-level、--clear、--json
-
push_notification.py - 发送模拟推送通知
- 简单模式(标题 + 正文 + 徽标)
- 自定义 JSON 负载
- 测试通知处理和深层链接
--list显示已送达的通知;--clear撤回所有通知(两者均需 idb 1.7+;发送仍使用 simctl)- 如果应用处于前台时收到推送,该通知不会送达通知中心,因此
--list不会显示该通知 - 选项:
--bundle-id、--title、--body、--badge、--payload、--list、--clear、--json
-
privacy_manager.py - 授予、撤销和重置应用权限
- 支持 13 项服务(相机、麦克风、位置、联系人、照片、日历、健康等)
- 批量操作(以逗号分隔服务)
- 提供带测试场景跟踪的审计记录
- 选项:
--bundle-id、--grant、--revoke、--reset、--list、--json
模拟器发现(2 个脚本)
-
sim_list.py - 以渐进披露方式列出模拟器
- 默认显示简洁摘要(总数 / 可用 / 已启动)
- 可按需通过缓存 ID 查看完整详情
- 按设备类型筛选
- 使用
--suggest推荐模拟器 - 与原始
simctl list相比,Token 用量减少 96%(57k → 2k 个 Token) - 选项:
--get-details、--suggest、--device-type、--json
-
simulator_selector.py - 为任务推荐最合适的模拟器
- 根据最近使用情况(来自
config.json)、最新 iOS 版本、常见测试机型和启动状态对候选项排序 - 使用
--list列出所有可用模拟器 - 使用
--boot直接启动选定的模拟器 - 提供适用于程序调用的 JSON 输出
- 选项:
--suggest、--list、--boot、--json
- 根据最近使用情况(来自
设备生命周期管理(5 个脚本)
-
simctl_boot.py - 启动模拟器,可选择验证就绪状态
- 按 UDID 或设备名称启动
- 等待设备就绪,并设置超时时间
- 批量启动操作(--all、--type)
- 性能计时
- 选项:
--udid、--name、--wait-ready、--timeout、--all、--type、--json
-
simctl_shutdown.py - 正常关闭模拟器
- 按 UDID 或设备名称关闭
- 可选择验证是否已完成关闭
- 批量关闭操作
- 选项:
--udid、--name、--verify、--timeout、--all、--type、--json
-
simctl_create.py - 动态创建模拟器
- 按设备类型和 iOS 版本创建
- 列出可用的设备类型和运行时
- 自定义设备名称
- 返回 UDID,供 CI/CD 集成使用
- 选项:
--device、--runtime、--name、--list-devices、--list-runtimes、--json
-
simctl_delete.py - 永久删除模拟器
- 按 UDID 或设备名称删除
- 未指定
--yes时会拒绝执行(不会提示确认;模拟器及其数据无法恢复):请先询问用户 - 批量删除操作
- 智能删除(使用 --old N 为每种设备类型保留 N 个)
- 选项:
--udid、--name、--yes、--all、--type、--old、--json
-
simctl_erase.py - 将模拟器恢复出厂设置,但不删除
- 保留设备 UUID(比删除后重新创建更快)
- 擦除所有模拟器、指定类型的模拟器或已启动的模拟器
- 可选择验证
- 未指定
--yes时会拒绝执行(应用、数据和设置无法恢复):请先询问用户 - 选项:
--udid、--name、--yes、--verify、--timeout、--all、--type、--booted、--json
常见模式
自动检测 UDID:大多数脚本在未提供 --udid 时,会自动检测已启动的模拟器。
设备名称解析:可使用设备名称(例如“iPhone 16 Pro”)代替 UDID,脚本会自动解析。
批量操作:许多脚本支持 --all 以操作所有模拟器,或使用 --type iPhone 按设备类型筛选。
输出格式:默认输出简洁易读的信息。使用 --json 可在 CI/CD 中生成机器可读的输出。
帮助:所有脚本都支持使用 --help 查看详细选项和示例。
屏幕截图尺寸:屏幕截图会调整大小以节省令牌。预设:full(3-4 个切片,约 5K 个令牌)、half(1 个切片,约 1.6K 个令牌,默认)、quarter(1 个切片,约 800 个令牌,细节较少)。快速检查画面时使用 quarter,需要清晰查看 UI 时使用 half,只有在需要像素级细节时才使用 full。会截取屏幕截图的脚本(app_state_capture.py、test_recorder.py)默认使用 half。
典型工作流
- 验证环境:
bash scripts/sim_health_check.sh - 启动应用:
python3 scripts/app_launcher.py --launch com.example.app - 分析屏幕:
python3 scripts/screen_mapper.py - 交互:
python3 scripts/navigator.py --find-text "Button" --tap - 验证:
python3 scripts/accessibility_audit.py - 如有需要,进行调试:
python3 scripts/app_state_capture.py --app-bundle-id com.example.app
配置
大多数运行限制都可以通过环境变量调整。默认值适用于典型的本地开发场景;对于运行缓慢的 CI 运行器、大型单体代码库构建,或复杂屏幕上的无障碍审查,可适当调高这些值。
| 变量 | 默认值 | 控制项 |
|---|---|---|
IOS_SIM_A11Y_LABEL_MAX | 80 | 无障碍审查输出中保留的 AXLabel 最大字符数 |
IOS_SIM_A11Y_TOP_ISSUES | 10 | 每次审查显示的无障碍问题数量上限 |
IOS_SIM_APPS_PREVIEW | 30 | app_launcher.py 在截断前列出的应用条目数 |
IOS_SIM_BOOT_SUBPROCESS_TIMEOUT | 60 | simctl boot 子进程本身的超时时间(秒) |
IOS_SIM_BOOT_TIMEOUT | 300 | 启动后等待就绪的超时时间(秒) |
IOS_SIM_BUILD_JSON_CAP | 50 | JSON 输出中的构建错误/测试失败数量上限 |
IOS_SIM_BUILD_LOG_PREVIEW | 4000 | 默认输出中的构建日志预览字符数 |
IOS_SIM_BUILD_TIMEOUT | 1800 | xcodebuild build 调用被终止前的最长秒数 |
IOS_SIM_INTROSPECT_TIMEOUT | 60 | xcodebuild -list 和 simctl list 查询的超时时间(秒) |
IOS_SIM_TEST_TIMEOUT | 2700 | xcodebuild test 调用被终止前的最长秒数 |
IOS_SIM_BUILD_SUMMARY_CAP | 15 | 默认构建摘要中的错误/失败数量 |
IOS_SIM_BUILD_VERBOSE_CAP | 100 | 详细构建输出中的错误/警告数量 |
IOS_SIM_CACHE_MAX_ENTRIES | 500 | 渐进式披露缓存中的条目上限(LRU 淘汰) |
IOS_SIM_CACHE_TTL_HOURS | 1 | 缓存条目的过期时间 |
IOS_SIM_ERASE_TIMEOUT | 90 | 等待擦除完成的超时时间(秒) |
IOS_SIM_HANG_PREDICATE | (默认值) | 覆盖 hang_watcher.py 使用的 os_log 谓词(默认捕获 RunningBoard 终止和 “Hang detected” 事件,以及主线程卡顿)。卡顿事件源自系统守护进程(RunningBoard、SpringBoard),因此谓词作用范围保持为整个模拟器;--bundle-id 在解析后应用,不会通过 AND 运算加入谓词。 |
IOS_SIM_HANG_MIN_MS | 250 | HangBuster 阈值——持续时间低于此值的事件不会写入磁盘(值越小越灵敏,摘要越长) |
IOS_SIM_HANG_SESSION_TTL_HOURS | 24 | HangBuster 会话清理时限;每次 --start 时都会运行清理 |
IOS_SIM_HANG_DEFAULT_TOP_N | 3 | --stop L1 输出中默认显示的前 N 个集群 |
IOS_SIM_HANG_BUDGET_TOKENS | (未设置) | --stop 的默认令牌预算(选择适合预算的 L0/L1/L2) |
IOS_SIM_HANG_MAX_RESTARTS | 3 | HangBuster 工作进程:在会话标记为 crashed 前,因 EOF/子进程退出而重启 log stream 的最大尝试次数 |
IOS_SIM_HANG_TOTAL_CAP_MB | 100 | HangBuster 磁盘总容量上限。--start 时,如果会话状态总量超过此值,会优先删除最早的会话。设为 0 可禁用。 |
IOS_SIM_LOG_JSON_CAP | 100 | log_monitor.py JSON 输出中的错误/警告数量上限 |
IOS_SIM_LOG_LINE_MAX | 300 | 日志摘要中每行的截断长度 |
IOS_SIM_LOG_TAIL | 200 | 详细/示例输出中的日志尾部行数 |
IOS_SIM_LOG_TEXT_SUMMARY | 15 | 文本模式日志摘要中显示的错误/警告数量 |
IOS_SIM_MAX_ELEMENTS | 25 | navigator.py --list 和 push_notification.py --list 列出的项目数 |
IOS_SIM_POLL_INTERVAL | 0.5 | 启动/擦除状态轮询间隔(秒) |
IOS_SIM_RELAUNCH_DELAY_MS | 1000 | app_launcher.py 中终止与重新启动之间的延迟 |
IOS_SIM_SCREEN_BUTTONS_PREVIEW | 15 | screen_mapper.py 列出的按钮名称数 |
IOS_SIM_SCREEN_SECTION_ITEMS | 10 | screen_mapper.py 每个分区显示的项目数 |
IOS_SIM_STATE_SUBPROCESS_TIMEOUT | 15 | app_state_capture.py 中子进程的超时时间(秒) |
IOS_SIM_TAP_SETTLE_MS | 500 | navigator.py 中点击后的稳定等待时间 |
示例:
# Slow GitHub Actions runner: give boot 10 minutes
IOS_SIM_BOOT_TIMEOUT=600 python3 scripts/simctl_boot.py --wait-ready
要求
- macOS 15 (Sequoia)+
- Xcode 26+(完整应用;仅安装 Command Line Tools 不足以运行 idb)
- Apple silicon Mac(Homebrew 提供的 idb 版本仅支持 arm64)
- Python 3.12+
idb1.5.1+(推荐 1.6.3+)——所有交互式脚本(轻点、滑动、输入)都需要:brew install facebook/fb/idb(同时安装 idb-cli 和 idb-companion)- Pillow,仅用于视觉差异比较:
pip3 install pillow
运行 bash scripts/sim_health_check.sh 进行验证(添加 --json 可获取结构化输出)。
故障排除
轻点、滑动和输入都不起作用,但读取正常。 idb 显示成功,屏幕却没有变化。在 Xcode 27 上,这意味着 idb-companion 版本低于 1.5.1:它会在 Xcode 26 使用的路径查找 SimulatorKit.framework。同时升级这两个软件包,然后重启正在运行的 companion:brew upgrade facebook/fb/idb-cli facebook/fb/idb-companion && idb kill。
SimulatorKit is required for HID interactions。 原因和解决方法相同。
健康检查提示“idb companions started before idb-companion was last installed”。 这些 companion 仍在运行升级前的二进制文件。运行 idb kill;下次调用 idb 时会启动新的 companion。
每次调用 idb 都返回 Connection refused 或 No such file。 idb 注册表 /tmp/idb/state 中仍有已失效的 companion,因此 idb 会连接到无人监听的套接字,而不是启动新的 companion。解决方法:idb disconnect <udid>。
open -a Simulator 失败。 Xcode 27 没有 Simulator.app;它已被 Xcode.app/Contents/Applications/ 中的 DeviceHub.app 取代。请改为无界面启动:xcrun simctl boot <udid>。请注意,退出 DeviceHub 会关闭它所承载的模拟器。
idb: command not found。 companion 和 CLI 是单独的软件包;brew install facebook/fb/idb 会同时安装两者。如果 which -a idb 显示多个结果,则会使用 PATH 中排在第一位的版本。如果其中有旧版 pip fb-idb,需要运行 pip uninstall fb-idb 将其卸载。
已知的上游 idb 问题(截至 idb 1.7.6 仍未解决):
- facebook/idb#964:在某些 iOS 26+ 屏幕上,
describe-all只返回应用节点,并且无法轻点 SpringBoard 提醒框。默认的ax后端无法跨进程边界查看内容;可尝试idb ui describe-all --json --api axbridge。轻点坐标的单位是点,而不是屏幕截图像素。重新启动应用后,默认读取也可能卡在一个大小为零的 Application 节点上;读取一次screen_mapper.py --deep(本身可能会超时一次)即可恢复。 - facebook/idb#978:
describe-all会列出辅助功能自定义操作,但无法执行。 - facebook/idb#954:Homebrew 版本仅支持 arm64,因此不支持 Intel Mac。
文档
关键设计原则
语义化导航:按含义(文本、类型、ID)而非像素坐标查找元素,适应 UI 变化。
令牌效率:默认输出简洁(3–5 行),并提供可选的详细模式和 JSON 模式,以获取详细结果。
辅助功能优先:基于标准辅助功能 API 构建,确保可靠性和兼容性。
零配置:在安装了 Xcode 的任何 macOS 上都可立即使用,无需设置。
结构化数据:脚本输出 JSON 或格式化文本,而非原始日志,便于解析和集成。
自动学习:构建系统会记住你的设备偏好。配置按项目存储。
直接使用这些脚本,或者在你的请求符合技能描述时,让 Claude Code 自动调用它们。