Skip to content

工具箱签名标识、多选与应用列表共享:方案与实现 ​

Owner 2026-11-03(内部包 250 试用后)七项需求,复述后 Owner 确认:

  1. 未连接设备时,设备信息下方“重新检查设备”按钮去掉;
  2. 应用管理给每个应用加签名类型标识(开发证书 / 发布证书 / App Store),不新增列;鼠标悬停显示签名 ID(签名证书的 application-identifier)、证书名称、可执行文件名;发布证书不细分标识,悬停中说明 Ad Hoc / 企业;
  3. 工具箱列表内 Control+左键改为多选(同 ⌘+左键),Shift+左键连续多选,右键 / 双指点按仍弹菜单;
  4. “全选”点击后变“取消”,再点变回“全选”,按钮宽度固定;
  5. 工具箱左侧菜单应用管理放首位、崩溃日志第二,“崩溃日志获取”改名“崩溃日志”;
  6. 主页面“选择测试应用”列表显示版本号,图标换成应用真实图标;
  7. 主页面选设备后已读过应用列表,打开工具箱不再重新读取。

一、实测依据(设备 A,内部包 250 自带 pymobiledevice3,只读) ​

操作耗时说明
apps list --type User --no-calculate-sizes(主页面所用)2.90 s / 2.97 s47 个应用,JSON 611 KB
apps list --type User --calculate-sizes(工具箱所用)10.49 s多出的 7.5 s 是设备计算占用空间
springboard icon(单个应用)0.99 sPNG 约 9.6 KB;本机缓存已有 45 个

应用列表每项已带签名相关字段,无需额外请求:

字段47 个应用中的取值
SignerIdentityApple iPhone OS Application Signing 17;Apple Distribution: … 27;Apple Development: … 2;TestFlight Beta Distribution 1
Entitlements.application-identifier47 个均有
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
2DeviceAppRecord、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
5Section 顺序改为应用管理、崩溃日志ToolboxView.swift
6新增共享 AppIconStore(磁盘缓存沿用 Caches/Perfowl/AppIcons/<bundle>_<version>.png,内存缓存,最多 3 个并发,同一图标只取一次);主页面列表行可见时请求图标,未到之前显示原字母色块;名称后显示版本号新 AppIconStore.swift、PerfowlWorkbenchView.swift、ToolboxView.swift
7DeviceFoundation 增加 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.swiftDeviceAppRecord 增加 signerIdentity、applicationIdentifier(默认空串,旧调用不变);新增 AppSigningKind(判定、两字标识、悬停标题)
PerfowlCore/PymobiledeviceClient.swift列表解析读取 SignerIdentity 与 Entitlements.application-identifier
PerfowlCore/DeviceToolsClient.swiftToolboxApp 改为包一条 DeviceAppRecord 加大小,解析复用主页面同一解析函数
PerfowlCore/DeviceFoundation.swiftcachedApps(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);DMG Perfowl-251-macos-x86_64-internal.dmg,SHA-256 9cb781360325e5409c08436abf3d9c05e32b94287d1c0b2198cdbeb6cfc36b60,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)。

Perfowl · Performance Observer