mcpField
I
ios-simulator-skill

ios-simulator-skill

github.com/conorluddy测试与质量1.3k2.4k 次安装1 周前更新
代码仓库

关于 ios-simulator-skill

ios-simulator-skill 提供一组脚本,用于在模拟器中构建、测试和自动化 iOS 应用。它面向开发者和测试 Agent,以无障碍数据进行导航和交互,而非依赖屏幕坐标。

主要功能

  1. 01执行 Xcode 构建与测试
  2. 02基于无障碍信息映射和操作界面
  3. 03控制模拟器外观、位置和媒体
  4. 04无障碍审计与截图差异比较
  5. 05记录测试并生成调试快照

适用场景

  1. 01运行 iOS 项目的构建和测试
  2. 02按标签或无障碍 ID 导航应用界面
  3. 03测试定位及照片选择器行为
  4. 04结合日志和状态快照排查界面问题

安装

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

$npx skills add https://github.com/conorluddy/ios-simulator-skill --skill ios-simulator-skill

安装后在 Claude Code 中输入/ios-simulator-skill确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

agents/
openai.yaml
scripts/
accessibility_audit.py
app_launcher.py
app_state_capture.py
appearance.py
build_and_test.py
clipboard.py
container.py
gesture.py
hang_watcher.py
keyboard.py
localization_audit.py
location.py
log_monitor.py
media.py
model_inspector.py
navigator.py
privacy_manager.py
push_notification.py
screen_mapper.py
sim_health_check.sh
sim_list.py
scripts/common/
__init__.py
cache_utils.py
device_utils.py
env_config.py
hang_pipeline.py
hang_sessions.py
idb_utils.py
screenshot_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 输出机器可读结果。

导航策略

导航时始终优先使用无障碍树,而非截图。 无障碍树会提供元素类型、标签、框架和点击目标——这些结构化数据比图像分析成本更低,也更可靠。

请按以下优先级使用:

  1. screen_mapper.py → 结构化元素列表(5-7 行,约 10 个词元)
  2. navigator.py --find-text/--find-type/--find-id → 语义化交互
  3. 截图 → 仅用于视觉验证、错误报告或视觉差异对比

根据尺寸不同,截图消耗 1,600–6,300 个词元。默认模式下,无障碍树仅消耗 10–50 个词元。

30 个生产级脚本

构建与开发(2 个脚本)
  1. build_and_test.py - 构建 Xcode 项目、运行测试,并通过渐进式披露解析结果

    • 实时流式显示构建结果
    • 从 xcresult 包中解析错误和警告
    • 按需获取详细构建日志
    • 选项:--project、--scheme、--clean、--test、--verbose、--json
  2. log_monitor.py - 实时监控日志并进行智能过滤

    • 流式输出日志或按时长捕获日志
    • 按严重性(error/warning/info/debug)过滤
    • 对重复消息去重
    • 选项:--app、--severity、--follow、--duration、--output、--json
设备状态(3 个脚本)
  1. 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
  2. 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
  3. 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 个脚本)
  1. screen_mapper.py - 分析当前屏幕并列出可交互元素

    • 按元素类型分类
    • 可交互按钮列表
    • 文本字段状态
    • 如果带标签的元素覆盖屏幕的比例低于 10%,则添加一行 Coverage:,建议使用 --deep
    • --deep 通过 idb 的 axbridge 后端读取(idb 1.7+):还能看到 Safari/WKWebView 内容和默认读取会遗漏的应用内提醒,以及许多未标记的容器视图。它会开启设备的辅助功能自动化模式(之后不会恢复)。网页内容框架的位置相对于 Web 视图,因此使用 --deep 查找元素,而不要用它获取点击坐标
    • 选项:--verbose、--hints、--deep、--json
  2. 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
  3. 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
  4. 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
  5. 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 个脚本)
  1. accessibility_audit.py - 检查当前屏幕是否符合 WCAG

    • 严重问题(缺少标签、空按钮、没有替代文本)
    • 警告(缺少提示、小型触控目标)
    • 信息(缺少 ID、嵌套层级过深)
    • 选项:--verbose、--output、--json
  2. visual_diff.py - 比较两张屏幕截图的视觉变化

    • 逐像素比较
    • 基于阈值判定通过/失败
    • 生成差异图像
    • 选项:--threshold、--output、--details、--json
  3. test_recorder.py - 自动记录测试执行过程

    • 为每个步骤捕获屏幕截图和无障碍树
    • 生成包含计时数据的 Markdown 报告
    • 选项:--test-name、--output、--verbose、--json
  4. app_state_capture.py - 创建全面的调试快照

    • 屏幕截图、UI 层级结构、应用日志、设备信息
    • 用于 Bug 报告的 Markdown 摘要
    • 选项:--app-bundle-id、--output、--log-lines、--json
  5. sim_health_check.sh - 验证环境配置是否正确

    • 检查 macOS、Xcode、simctl、IDB、Python
    • 列出可用和已启动的模拟器
    • 验证 Python 软件包(Pillow)
  6. model_inspector.py - 检查项目文件中的 Core Data 和 SwiftData 模型

    • 解析 .xcdatamodeld 软件包(实体、属性、关系)
    • 检测模型版本和当前活动版本
    • 尽力提取 SwiftData @Model 类
    • 按需转储任意模型的原始源代码(--raw ModelName)
    • 选项:--project-path、--core-data-only、--swiftdata-only、--show-versions、--raw、--verbose、--json
  7. 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
  8. 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.ndjson gzip 压缩为 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
    
  9. 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 个脚本)
  1. clipboard.py - 管理模拟器剪贴板,以便测试粘贴

    • 将文本复制到剪贴板
    • 无需手动输入即可测试粘贴流程
    • 选项:--copy、--test-name、--expected、--json
  2. status_bar.py - 覆盖模拟器状态栏外观

    • 预设:clean(9:41、电量 100%)、testing(11:11、电量 50%)、low-battery(电量 20%)、airplane(离线)
    • 自定义时间、网络、电量和 WiFi 设置
    • 选项:--preset、--time、--data-network、--battery-level、--clear、--json
  3. push_notification.py - 发送模拟推送通知

    • 简单模式(标题 + 正文 + 徽标)
    • 自定义 JSON 负载
    • 测试通知处理和深层链接
    • --list 显示已送达的通知;--clear 撤回所有通知(两者均需 idb 1.7+;发送仍使用 simctl)
    • 如果应用处于前台时收到推送,该通知不会送达通知中心,因此 --list 不会显示该通知
    • 选项:--bundle-id、--title、--body、--badge、--payload、--list、--clear、--json
  4. privacy_manager.py - 授予、撤销和重置应用权限

    • 支持 13 项服务(相机、麦克风、位置、联系人、照片、日历、健康等)
    • 批量操作(以逗号分隔服务)
    • 提供带测试场景跟踪的审计记录
    • 选项:--bundle-id、--grant、--revoke、--reset、--list、--json
模拟器发现(2 个脚本)
  1. sim_list.py - 以渐进披露方式列出模拟器

    • 默认显示简洁摘要(总数 / 可用 / 已启动)
    • 可按需通过缓存 ID 查看完整详情
    • 按设备类型筛选
    • 使用 --suggest 推荐模拟器
    • 与原始 simctl list 相比,Token 用量减少 96%(57k → 2k 个 Token)
    • 选项:--get-details、--suggest、--device-type、--json
  2. simulator_selector.py - 为任务推荐最合适的模拟器

    • 根据最近使用情况(来自 config.json)、最新 iOS 版本、常见测试机型和启动状态对候选项排序
    • 使用 --list 列出所有可用模拟器
    • 使用 --boot 直接启动选定的模拟器
    • 提供适用于程序调用的 JSON 输出
    • 选项:--suggest、--list、--boot、--json
设备生命周期管理(5 个脚本)
  1. simctl_boot.py - 启动模拟器,可选择验证就绪状态

    • 按 UDID 或设备名称启动
    • 等待设备就绪,并设置超时时间
    • 批量启动操作(--all、--type)
    • 性能计时
    • 选项:--udid、--name、--wait-ready、--timeout、--all、--type、--json
  2. simctl_shutdown.py - 正常关闭模拟器

    • 按 UDID 或设备名称关闭
    • 可选择验证是否已完成关闭
    • 批量关闭操作
    • 选项:--udid、--name、--verify、--timeout、--all、--type、--json
  3. simctl_create.py - 动态创建模拟器

    • 按设备类型和 iOS 版本创建
    • 列出可用的设备类型和运行时
    • 自定义设备名称
    • 返回 UDID,供 CI/CD 集成使用
    • 选项:--device、--runtime、--name、--list-devices、--list-runtimes、--json
  4. simctl_delete.py - 永久删除模拟器

    • 按 UDID 或设备名称删除
    • 未指定 --yes 时会拒绝执行(不会提示确认;模拟器及其数据无法恢复):请先询问用户
    • 批量删除操作
    • 智能删除(使用 --old N 为每种设备类型保留 N 个)
    • 选项:--udid、--name、--yes、--all、--type、--old、--json
  5. 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。

典型工作流

  1. 验证环境:bash scripts/sim_health_check.sh
  2. 启动应用:python3 scripts/app_launcher.py --launch com.example.app
  3. 分析屏幕:python3 scripts/screen_mapper.py
  4. 交互:python3 scripts/navigator.py --find-text "Button" --tap
  5. 验证:python3 scripts/accessibility_audit.py
  6. 如有需要,进行调试:python3 scripts/app_state_capture.py --app-bundle-id com.example.app

配置

大多数运行限制都可以通过环境变量调整。默认值适用于典型的本地开发场景;对于运行缓慢的 CI 运行器、大型单体代码库构建,或复杂屏幕上的无障碍审查,可适当调高这些值。

变量默认值控制项
IOS_SIM_A11Y_LABEL_MAX80无障碍审查输出中保留的 AXLabel 最大字符数
IOS_SIM_A11Y_TOP_ISSUES10每次审查显示的无障碍问题数量上限
IOS_SIM_APPS_PREVIEW30app_launcher.py 在截断前列出的应用条目数
IOS_SIM_BOOT_SUBPROCESS_TIMEOUT60simctl boot 子进程本身的超时时间(秒)
IOS_SIM_BOOT_TIMEOUT300启动后等待就绪的超时时间(秒)
IOS_SIM_BUILD_JSON_CAP50JSON 输出中的构建错误/测试失败数量上限
IOS_SIM_BUILD_LOG_PREVIEW4000默认输出中的构建日志预览字符数
IOS_SIM_BUILD_TIMEOUT1800xcodebuild build 调用被终止前的最长秒数
IOS_SIM_INTROSPECT_TIMEOUT60xcodebuild -list 和 simctl list 查询的超时时间(秒)
IOS_SIM_TEST_TIMEOUT2700xcodebuild test 调用被终止前的最长秒数
IOS_SIM_BUILD_SUMMARY_CAP15默认构建摘要中的错误/失败数量
IOS_SIM_BUILD_VERBOSE_CAP100详细构建输出中的错误/警告数量
IOS_SIM_CACHE_MAX_ENTRIES500渐进式披露缓存中的条目上限(LRU 淘汰)
IOS_SIM_CACHE_TTL_HOURS1缓存条目的过期时间
IOS_SIM_ERASE_TIMEOUT90等待擦除完成的超时时间(秒)
IOS_SIM_HANG_PREDICATE(默认值)覆盖 hang_watcher.py 使用的 os_log 谓词(默认捕获 RunningBoard 终止和 “Hang detected” 事件,以及主线程卡顿)。卡顿事件源自系统守护进程(RunningBoard、SpringBoard),因此谓词作用范围保持为整个模拟器;--bundle-id 在解析后应用,不会通过 AND 运算加入谓词。
IOS_SIM_HANG_MIN_MS250HangBuster 阈值——持续时间低于此值的事件不会写入磁盘(值越小越灵敏,摘要越长)
IOS_SIM_HANG_SESSION_TTL_HOURS24HangBuster 会话清理时限;每次 --start 时都会运行清理
IOS_SIM_HANG_DEFAULT_TOP_N3--stop L1 输出中默认显示的前 N 个集群
IOS_SIM_HANG_BUDGET_TOKENS(未设置)--stop 的默认令牌预算(选择适合预算的 L0/L1/L2)
IOS_SIM_HANG_MAX_RESTARTS3HangBuster 工作进程:在会话标记为 crashed 前,因 EOF/子进程退出而重启 log stream 的最大尝试次数
IOS_SIM_HANG_TOTAL_CAP_MB100HangBuster 磁盘总容量上限。--start 时,如果会话状态总量超过此值,会优先删除最早的会话。设为 0 可禁用。
IOS_SIM_LOG_JSON_CAP100log_monitor.py JSON 输出中的错误/警告数量上限
IOS_SIM_LOG_LINE_MAX300日志摘要中每行的截断长度
IOS_SIM_LOG_TAIL200详细/示例输出中的日志尾部行数
IOS_SIM_LOG_TEXT_SUMMARY15文本模式日志摘要中显示的错误/警告数量
IOS_SIM_MAX_ELEMENTS25navigator.py --list 和 push_notification.py --list 列出的项目数
IOS_SIM_POLL_INTERVAL0.5启动/擦除状态轮询间隔(秒)
IOS_SIM_RELAUNCH_DELAY_MS1000app_launcher.py 中终止与重新启动之间的延迟
IOS_SIM_SCREEN_BUTTONS_PREVIEW15screen_mapper.py 列出的按钮名称数
IOS_SIM_SCREEN_SECTION_ITEMS10screen_mapper.py 每个分区显示的项目数
IOS_SIM_STATE_SUBPROCESS_TIMEOUT15app_state_capture.py 中子进程的超时时间(秒)
IOS_SIM_TAP_SETTLE_MS500navigator.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+
  • idb 1.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。

文档

  • SKILL.md(本文件)——脚本参考、要求和故障排除
  • README.md ——安装、更新 idb、Xcode 27 注意事项
  • AGENTS.md ——架构和实现细节

关键设计原则

语义化导航:按含义(文本、类型、ID)而非像素坐标查找元素,适应 UI 变化。

令牌效率:默认输出简洁(3–5 行),并提供可选的详细模式和 JSON 模式,以获取详细结果。

辅助功能优先:基于标准辅助功能 API 构建,确保可靠性和兼容性。

零配置:在安装了 Xcode 的任何 macOS 上都可立即使用,无需设置。

结构化数据:脚本输出 JSON 或格式化文本,而非原始日志,便于解析和集成。

自动学习:构建系统会记住你的设备偏好。配置按项目存储。


直接使用这些脚本,或者在你的请求符合技能描述时,让 Claude Code 自动调用它们。

评论

支持 Markdown