做 iOS 开发时,有不少操作并不复杂,但每次都得在几个工具之间来回切换:在终端查模拟器、打开沙盒找文件、输入一条路由、抓日志、检查签名,再回到 Xcode。
我想把这些分散的操作放到一个桌面控制台里,围绕"当前项目、目标 App、当前设备"组织起来,于是做了 iCATBox。
现在它以 MIT 协议 开源,首个公开版本为 1.2.0 。核心是 SwiftUI + AppKit,模拟器使用 Xcode 的 simctl,真机使用 devicectl,没有第三方 Swift 依赖。
- 源码:LZQVicLi/iCATBox
- 安装包:GitHub Releases

截图来自隔离预览模式,全部为合成项目和设备数据;真实设备操作在该模式下被阻止。
从设备和 App 出发,把调试流程连起来
iCATBox 的主窗口分成设备列表、操作区、控制台和信息栏。先选项目和设备,后面的操作复用同一组上下文,减少重复输入 Bundle ID、路径和参数。
目前整理进来的能力包括:
| 调试场景 | 可以使用的入口 |
|---|---|
| 应用与设备 | 安装、启动、终止、截图、录屏、设备状态 |
| 文件与数据 | 打开沙盒、拉取或写入、备份与还原 |
| 路由 | 打开链接、环境映射、收藏、订阅、回归截图 |
| 日志与崩溃 | 日志流、真机 App 控制台、崩溃报告和符号化 |
| 工程维护 | 脚本、依赖、签名证书、描述文件、发布前检查 |
| 混合开发 | Hybrid 桥接目录、Flutter 工具、React Native 工作流 |
具体动作能不能使用,仍取决于设备类型、Xcode 和系统版本。例如,真机不能直接套用模拟器的整机抹除与开关机能力;真机实时日志也可能需要重启目标 App。界面应当把这些差别表达清楚。
命令执行之外,为什么还需要一个控制台
GUI 把入口集中起来之后,还需要让执行过程能够被检查。项目使用 Process 执行本机工具,将参数作为参数数组传入,并采集标准输出、标准错误和退出码;部分任务支持持续输出。
典型调用关系可以概括为:
text
用户选择动作
→ 读取当前项目、App 和设备
→ 检查当前状态和可用能力
→ 构造本机工具参数
→ 执行并回显输出
→ 根据结果刷新界面
例如,路由跳转最终仍然调用对应设备工具。控制台会显示执行信息;如果配置了环境域名映射或 Scheme 改写,也会显示文档链接与实际唤起地址,方便排查"为什么打开了另一套环境"。
工程里的自定义脚本和模块命令需要单独看待:它们属于用户选择执行的项目内容。导入一份项目配置不会自动运行这些脚本。
路由不再跟着源码一起更新
一个调试工具如果把实际项目的路由表编进 App,维护起来很快就会遇到问题:页面变了就要改源码,其他项目也没法直接复用。
现在 iCATBox 支持用户维护项目路由,也支持订阅 JSON、Markdown 或 HTML 文档。其中,明确结构的 routes.json 最容易控制:
json
{
"revision": "example-1",
"title": "Example routes",
"routes": [
{
"group": "Demo",
"title": "Home",
"url": "https://example.com/home"
}
]
}
把文档地址填进项目设置后,可以手动同步,也可以每 30 分钟检查新增条目。默认后台只提示,手动同步时预览确认;需要自动追加时,再主动开启后台合并。
合并按 URL 去重,已有条目的标题保留,不因为源文档少了一项就删除本地路由。每个项目还可以配置允许的域名和 URL Scheme。
这里有个值得单独处理的异步问题:请求发出去后,用户可能已经切换项目或修改了订阅地址。网络结果回来时,程序会重新核对项目 ID、订阅地址和导入规则,再读取最新项目配置进行合并,避免旧请求把内容写到另一套工程里。
HTML 和 Markdown 采用通用链接提取,复杂站点不保证都能正确解析;需要稳定同步时,建议提供明确的 JSON 文档。
通用工具开源,具体业务配置留在本机
这次整理开源版时,我做的一个主要调整,是把"工具能力"和"项目数据"拆开。
公开的部分包括路由跳转、目录展示、桥接调用代码生成、Flutter 工具、接口请求与字段映射等通用能力。具体项目的链接、桥接方法定义、页面名称、域名和接口参数,通过本地 JSON 导入。
text
公开仓库
├─ 通用调试界面与本机工具调用
├─ 配置模型、校验和导入导出
├─ 路由解析、合并与接口映射
└─ 虚构示例配置
仓库外的本机文件
└─ 用户自己的项目配置包
公开版本从空白项目开始,不根据固定 Bundle ID 套用某家公司的预设,不自动回填厂商接口,也不会自动扫描私有配置目录。
导入前会显示项目名称和路由、桥接、Flutter 页面等条目数量。导入生成新项目,不覆盖已有项目。

一个桥接目录条目,本质上只是方法名、方向、示例参数和说明等数据。公开代码保留展示、搜索和 JS 调试代码生成器,就可以让不同项目导入各自的目录,而无需把业务协议写死在工具中。
路由和 Flutter 页面也采用同样的思路。这里不会凭一个网页 URL 自动猜出任意 Flutter 页面的 pageName,需要项目自己提供配置。
埋点接口:地址可编辑,还不等于协议通用
埋点调试里还有一层更容易忽略的耦合:即便域名改成输入框,请求路径、参数和响应字段仍可能绑定某个特定后端。
因此,公开版把这些内容做成了声明式适配器。配置可以描述接口路径、表单参数、响应列表位置和字段映射。例如,下面是一个虚构的事件接口片段:
json
{
"path": "/v1/events",
"parameters": {
"device": "{udid}",
"after": "{since}"
},
"rowsPath": "items",
"fields": {
"id": "eventId",
"timestamp": "time",
"eventName": "name",
"trackingID": "definitionId",
"customize": "properties"
}
}
适配器把响应转换为标准事件或定义,再由通用逻辑对照事件名、页面和自定义字段。点路径支持嵌套对象与数组下标,也支持依次尝试多个候选路径。
这些映射是数据,不执行 JavaScript 或其他表达式。当前接口能力是表单 POST 与字段重映射;如果后端需要特殊加密、签名或完全不同的传输协议,还需要单独实现,不能只换个域名就承诺通用适配。
Token、Cookie 和密码也不应作为可导出项目配置的一部分。
发布一个能独立构建的公开版本
开源版需要验证:只拿公开仓库,是否也能完成构建,产物是否只包含公开输入。
目前仓库里有配置回归检查和 GitHub Actions,覆盖旧配置解码、JSON 往返、路由解析、域名边界、重复链接、字段映射、参数占位符以及 Cookie 的域名、路径和 Secure 范围。
发布流程会从公开源码构建 Apple Silicon + Intel 通用 App,检查源码与最终 App,生成独立版本的 ZIP、DMG 和 SHA-256 校验文件。历史版本按标签保留,后续发布不覆盖旧产物。
sh
git clone https://github.com/LZQVicLi/iCATBox.git
cd iCATBox
bash scripts/test.sh
bash scripts/build.sh
bash scripts/package.sh
源码自检和合成预览有明确的范围:它们不能替代真实设备上的录屏、日志、权限、安装和恢复验证。项目没有对所有 Xcode、iOS 版本和设备组合做端到端保证。
下载体验与反馈
最低要求为 macOS 13+ 和 Xcode ,真机功能还取决于本机 Xcode 是否提供相应的 devicectl 能力,以及设备信任和开发环境。Flutter、Node 等属于按需使用的外部工具,不随 App 一起捆绑。
当前公开安装包为 ad-hoc 签名,尚未 Apple Developer ID 公证。下载后先核实来源与 SHA-256 校验和,如遇 macOS 拦截,再按系统提供的"隐私与安全性 → 仍要打开"流程处理;具体步骤见仓库签名说明。
如果你也经常在终端、Xcode 和 Finder 之间反复切换,可以从截图、沙盒和路由这些日常操作试起。
欢迎 Star、Issue 和 PR。反馈时请注明 macOS、Xcode、App 版本,以及模拟器还是真机;尽量提供虚构项目的复现步骤,不要附带业务配置、设备标识或未经处理的日志。