外观
工具箱签名标识、多选与应用列表共享:方案与实现
Owner 2026-11-03(内部包 250 试用后)七项需求,复述后 Owner 确认:
- 未连接设备时,设备信息下方“重新检查设备”按钮去掉;
- 应用管理给每个应用加签名类型标识(开发证书 / 发布证书 / App Store),不新增列;鼠标悬停显示签名 ID(签名证书的 application-identifier)、证书名称、可执行文件名;发布证书不细分标识,悬停中说明 Ad Hoc / 企业;
- 工具箱列表内 Control+左键改为多选(同 ⌘+左键),Shift+左键连续多选,右键 / 双指点按仍弹菜单;
- “全选”点击后变“取消”,再点变回“全选”,按钮宽度固定;
- 工具箱左侧菜单应用管理放首位、崩溃日志第二,“崩溃日志获取”改名“崩溃日志”;
- 主页面“选择测试应用”列表显示版本号,图标换成应用真实图标;
- 主页面选设备后已读过应用列表,打开工具箱不再重新读取。
一、实测依据(设备 A,内部包 250 自带 pymobiledevice3,只读)
| 操作 | 耗时 | 说明 |
|---|---|---|
apps list --type User --no-calculate-sizes(主页面所用) | 2.90 s / 2.97 s | 47 个应用,JSON 611 KB |
apps list --type User --calculate-sizes(工具箱所用) | 10.49 s | 多出的 7.5 s 是设备计算占用空间 |
springboard icon(单个应用) | 0.99 s | PNG 约 9.6 KB;本机缓存已有 45 个 |
应用列表每项已带签名相关字段,无需额外请求:
| 字段 | 47 个应用中的取值 |
|---|---|
SignerIdentity | Apple iPhone OS Application Signing 17;Apple Distribution: … 27;Apple Development: … 2;TestFlight Beta Distribution 1 |
Entitlements.application-identifier | 47 个均有 |
Entitlements.get-task-allow | 开发签名为 true,其余 false 或缺失 |
结论(E3):
- 签名类型按
SignerIdentity前缀判定:Apple iPhone OS Application Signing→ App Store;Apple Development:/iPhone Developer:→ 开发;Apple Distribution:/iPhone Distribution:→ 发布;TestFlight Beta Distribution→ TestFlight(Owner 列的三类之外,实测存在,单独标“TF”,不并入任何一类);其他或缺失 → 未知,不猜。 - 偏差:Ad Hoc 与企业签名都用发布证书,区别只在描述文件(
ProvisionsAllDevices),应用列表不带描述文件;逐个读取描述文件需打开应用容器(每个约 2 s,且非开发签名的应用常被系统拒绝)。因此悬停中写“发布证书(Ad Hoc / 企业无法从应用列表区分)”,不给出可能错误的细分。
二、方案
| 项 | 做法 | 关键文件 |
|---|---|---|
| 1 | 删除未连接时的“重新检查设备”按钮;USB 插拔由现有设备监听自动发现 | PerfowlWorkbenchView.swift |
| 2 | DeviceAppRecord、ToolboxApp 增加 signerIdentity、applicationIdentifier;新增 AppSigningKind(development / distribution / appStore / testFlight / unknown)与判定函数;应用名列内名字后加小标识(开发 / 发布 / 商店 / TF / 未知),整行各列悬停显示三项 | Models.swift、PymobiledeviceClient.swift、DeviceToolsClient.swift、ToolboxView.swift |
| 3 | 复用会话列表已有的 ControlClickAsCommandClick,挂到应用表与崩溃日志表 | ToolboxView.swift |
| 4 | 当前可见项全部已选(且非空)时显示“取消”,点击清空;否则“全选”;文字固定宽度 | ToolboxView.swift |
| 5 | Section 顺序改为应用管理、崩溃日志 | ToolboxView.swift |
| 6 | 新增共享 AppIconStore(磁盘缓存沿用 Caches/Perfowl/AppIcons/<bundle>_<version>.png,内存缓存,最多 3 个并发,同一图标只取一次);主页面列表行可见时请求图标,未到之前显示原字母色块;名称后显示版本号 | 新 AppIconStore.swift、PerfowlWorkbenchView.swift、ToolboxView.swift |
| 7 | DeviceFoundation 增加 cachedApps(for:) 与 adoptApps(_:for:)。工具箱打开时若该设备已有主页面列表,立即显示(大小列显示“计算中…”),后台只做一次含占用空间的读取补齐大小,并把结果回写主页面缓存;安装 / 卸载后的刷新同样回写,主页面无需再读。adoptApps 只更新列表与缓存,不触发连接准备,测试进行中也安全 | DeviceFoundation.swift、ToolboxView.swift |
说明:第 7 项中“大小”只有含占用空间的读取才有,所以后台仍有一次读取;它不阻塞列表显示,不再出现“读取中”等待。若不需要“大小”列,可完全去掉这次读取——留给 Owner 决定。
三、效率目标与验收
- 打开工具箱到应用列表可见:基线约 10.5 s(含占用空间读取)→ 目标:主页面已读过时 < 0.1 s(只是内存映射);大小列约 10.5 s 后补齐。
- 主页面选择应用列表图标:已缓存的图标打开即显示;未缓存的每个约 1 s,3 并发,滚动可见的行优先。
- 签名标识零额外设备请求;解析增加的是两个字符串字段。
- 测试:Swift 单测覆盖签名判定(五类 + 缺失)、列表解析新字段、
adoptApps不触发连接准备、全选 / 取消状态;构建后 E3 实测以上耗时;真机交互(E4)由 Owner 在新包上确认。
Implementation Update · 2026-11-03
| 文件 | 修改 |
|---|---|
PerfowlCore/Models.swift | DeviceAppRecord 增加 signerIdentity、applicationIdentifier(默认空串,旧调用不变);新增 AppSigningKind(判定、两字标识、悬停标题) |
PerfowlCore/PymobiledeviceClient.swift | 列表解析读取 SignerIdentity 与 Entitlements.application-identifier |
PerfowlCore/DeviceToolsClient.swift | ToolboxApp 改为包一条 DeviceAppRecord 加大小,解析复用主页面同一解析函数 |
PerfowlCore/DeviceFoundation.swift | cachedApps(for:)、adoptApps(_:for:keepSelection:):只更新列表与缓存,不读设备、不准备连接;测试进行中保留被测应用选择 |
PerfowlApp/AppIconStore.swift(新) | 共享图标:磁盘 + 内存缓存,3 并发,后到先取 |
PerfowlApp/ToolboxView.swift | 菜单顺序与改名;签名标识与整行悬停;Control+左键多选(应用表、崩溃日志表);全选 / 取消;复用主页面列表、大小列“计算中…”、读取结果回写主页面 |
PerfowlApp/PerfowlWorkbenchView.swift | 去掉“重新检查设备”;选择应用列表显示版本号与真实图标(行出现时请求) |
偏差
- TestFlight 签名单独标“TF”(Owner 列的三类之外,设备 A 实测存在 1 个)。
- Ad Hoc / 企业不细分(原因见第一节)。
- 第 7 项为补齐“大小”列仍有一次后台读取,但不阻塞列表,且结果回写主页面,安装 / 卸载后主页面无需再读。
- 切换回“应用管理”不再重新读取(此前每次切换都读)。
验证
- Swift 全量 459 项、跳过 15、0 失败(基线 455,+4:签名判定、列表字段解析、列表共享不重连、全选 / 取消)(E2)。
- 用设备 A 真实数据渲染工具箱(opt-in 渲染测试):菜单为“应用管理 / 崩溃日志”,47 个应用均显示签名标识,商店 / 发布 / 开发分类与第一节统计一致(E3,截图含真实 Bundle ID,仅存本机)。
- 效率:签名标识零额外设备请求;工具箱在主页面已读过列表时直接显示(内存映射 47 条,无设备请求),基线需等待约 10.5 s;大小列仍约 10.5 s 后补齐(E2/E3 推算,真机计时随新包核对)。
- 真机交互(Control+左键、悬停、全选 / 取消、主页面图标与版本号)待 Owner 在新包上确认(E4 pending)。
Validation Update · 2026-11-03:内部测试包 251 安装
- 来源:main
2209dad6(源码门禁 passed);DMGPerfowl-251-macos-x86_64-internal.dmg,SHA-2569cb781360325e5409c08436abf3d9c05e32b94287d1c0b2198cdbeb6cfc36b60,146,248,090 字节。 codesign --verify --deep --strict通过;安装后目录树与 DMG 一致;冻结 Collector 与源码一致。公证按 Owner 决定暂缓(Gatekeeper 退出码 3);回滚包 250 已校验。- 启动器唯一:
mdfind与lsregister均只剩/Applications/Perfowl.app(E3)。 - 七项真机交互待 Owner 确认(E4 pending)。
Validation Update · 2026-11-03:Owner 真机确认
Owner 在内部包 251 上确认七项真机通过(E4):去掉“重新检查设备”、签名标识与悬停详情、Control+左键多选、全选 / 取消、菜单顺序与改名、主页面应用列表版本号与真实图标、工具箱复用应用列表。单设备(设备 A,iOS 26)。