充分利用 Device Hub
Get the most out of Device Hub
2026年6月10日
一句话判断
✅ Device Hub 把 Xcode 臃肿的设备管理剥离成了独立 App,并用全新的 devicectl 命令行工具彻底拯救了 CI/CD 里的设备控制脚本。
这场 Session 讲了什么
以前我们要管真机得开 Xcode 的 Devices and Simulators 窗口,管模拟器得开 Simulator.app,写 CI 脚本还得在 xcrun simctl 和各种第三方真机工具(比如 ios-deploy)之间反复横跳。现在 Apple 把这些全扔进了一个叫 Device Hub 的独立 App 里,随 Xcode 27 附赠,不打开 Xcode 也能直接用。
它把真机和模拟器的管理体验彻底拉平了。在 Device Hub 的 Canvas(画布)里,你既能用鼠标直接操作真机屏幕、捕获 Mac 键盘输入,也能一键调整模拟器的 Resize mode(调整大小模式)。侧边栏把几十台设备统一管理,Inspector(检查器)面板直接搞定 Provisioning profiles(描述文件)和 Location simulation(位置模拟)。
对日常开发来说,这也就是个更漂亮的 UI;但对 QA 团队和搞 CI/CD 的人来说,底层配套的 devicectl 命令行工具才是真香。它统一了真机和模拟器的 CLI 操作,抓日志、装 App、改配置一气呵成,终于不用在脚本里写一堆 if [ "$is_simulator" = true ] 的判断了。
值得深挖的点
真机与模拟器的“大一统”体验
Apple 这次把 Simulator.app 的功能直接融进了 Device Hub,这不仅仅是 UI 上的缝合。以前 Simulator 和真机的底层通信协议完全隔离,导致很多自动化工具必须维护两套逻辑。Device Hub 在架构上抽象出了一层统一的 Device Provider。你在 Canvas 里看到的实时投屏、触摸映射,无论是走 USB 的真机还是走 XPC 的模拟器,上层 API 表现完全一致。
这种设计的 trade-off 在于,对于只需要跑个简单 iPhone 15 模拟器的轻量级开发者,Device Hub 显得有点“重”。但 Apple 显然更看重多设备矩阵测试(比如同时开 5 个不同尺寸的 Compact window 测 UIKit 适配)和跨设备联动(比如右键一键配对 iPhone 和 Apple Watch 模拟器)。把设备管理从 Xcode 主进程剥离,也变相减轻了 Xcode 本体的内存压力,毕竟 Xcode 已经够吃内存了。
devicectl 终结 CI/CD 脚本的“缝合怪”时代
搞过 iOS CI 的人都知道,写设备管理脚本有多痛苦。模拟器用 xcrun simctl,真机要么用不稳定的 instruments,要么依赖第三方开源库。devicectl 的出现直接统一了 CLI 层面的设备控制。它不仅能 install 和 launch,还能直接 capture sysdiagnose(抓取系统诊断日志)和管理 logging profiles(日志描述文件)。
最狠的是它支持 JSON 输出(--json-output),这意味着你的 Python 或 Bash 脚本可以直接解析结构化的设备状态,而不用去正则匹配那些随时会变的终端纯文本输出。Apple 终于意识到,开发者在终端里需要的不是一个“能跑就行”的工具,而是一个能无缝接入现代 DevOps 流水线的标准化接口。坑在于,devicectl 目前对旧版 iOS 设备的兼容性可能不如老工具,升级 CI 节点时得留足回归测试的时间。
代码片段
1. 统一安装并启动 App
场景:在 CI 脚本中,不区分真机还是模拟器,直接安装并拉起 App。
# 获取当前连接的设备 ID (假设只连了一台)
DEVICE_ID=$(xcrun devicectl list devices --json-output | jq -r '.result.devices[0].identifier')
# 安装 App,真机和模拟器使用完全相同的命令
xcrun devicectl device install app --device "$DEVICE_ID" ./Build/MyApp.app
# 启动 App 并传入环境变量
xcrun devicectl device process launch \
--device "$DEVICE_ID" \
--environment-variables '{"UI_TESTING": "1"}' \
com.mycompany.myapp
坑:devicectl 的 JSON 输出结构在 Xcode 小版本更新时可能会有微调,CI 脚本里最好用 jq 做一下容错处理,别直接硬编码数组索引。
2. 自动化抓取设备诊断日志
场景:UI 自动化测试失败时,自动抓取真机的 sysdiagnose 并上传到 artifacts。
# 触发并抓取 sysdiagnose,输出到指定目录
xcrun devicectl device info sysdiagnose \
--device "$DEVICE_ID" \
--output-directory ./diagnostics/
# 如果是模拟器,可以直接抓取特定的日志归档
xcrun devicectl device info logs \
--device "$DEVICE_ID" \
--predicate 'subsystem == "com.mycompany.myapp"' \
--output ./diagnostics/app_logs.logarchive
坑:真机的 sysdiagnose 抓取非常耗时(可能需要几分钟),且会短暂阻塞设备交互。在 CI 中一定要设置合理的超时时间,别让它把整个 Job 卡死。
最佳实践
- 已有项目的迁移策略:把 CI 仓库里的
xcrun simctl和ios-deploy逐步替换为xcrun devicectl。先在一个非核心的 nightly build 流水线跑一周,观察设备连接稳定性和 JSON 输出格式。 - 新项目的采用建议:QA 团队直接放弃独立的 Simulator.app,全面转向 Device Hub。利用它的多 Tab 和 Compact window 功能,把常用的测试机型(如 iPhone SE、iPad Pro、Apple Watch)固定在工作区,形成标准化的测试矩阵。
- 实战中容易踩的坑:Device Hub 的 Canvas 投屏在连接多台高刷真机时,会吃掉大量 Mac GPU 资源。如果你只是想把设备放在旁边跑测试,记得在 Device Hub 设置里关掉 “Live display”(实时显示),或者最小化窗口,否则你的 Mac 风扇会起飞。
还有什么值得关注
- Resize mode(调整大小模式):在 Canvas 里可以直接自由拖拽改变 App 窗口尺寸,这是配合 “Modernize your UIKit app” 里提到的 UIKit 窗口自适应特性的最佳调试工具。
- Keyboard capture(键盘捕获):Mac 键盘输入直接映射到真机,测快捷键和复杂文本输入时,终于不用在真机那块小玻璃上痛苦地戳了。
- Configuration profiles(配置描述文件)管理:Inspector 面板里可以直接安装和删除 .mobileconfig 文件,抓包配代理或者装测试证书再也不用绕圈子了。