Skip to content

工具箱、设备信息与深灰主题:产品设计 ​

Owner 2026-11-02(内部包 244 试用后):① 会话列表按住 Control 单击弹出菜单不对;② 整体纯黑改深灰;③ 设备信息过于简单,参考 codesign4qc 的设备信息获取与展示,保留最重要的;④ 设备信息底部加“工具箱”按钮,打开独立窗口,仿 PerfDog 工具箱的样式与功能(崩溃日志获取、应用管理),实现参考 codesign4qc 的应用管理与日志获取。

一、Control+单击 ​

Owner 期望 Control+单击用于跳选。macOS 默认 Control+单击等同右键;在会话列表内把 Control+左键单击转换为 ⌘+单击(跳选),右键与触控板双指点按仍弹出菜单。只作用于会话列表区域,不影响其他界面。

二、深灰主题 ​

页面背景由深海军蓝(#0B1020 系)改为中性深灰(参考 PerfDog 工具箱):页面 #22252E、侧栏 #282B35、卡片 #2F333E、凸起 #383C48、边框 #484D5C、分隔 #3C404D;文字、强调蓝与状态色不变。只改 App;官网品牌 Token 不变。

三、设备信息 ​

数据来源与 codesign4qc 一致(设备内置 pymobiledevice3,三条只读查询,约 1–1.5 秒/条,切换设备或手动刷新时读取,60 秒内不重复读取):

  • lockdown info:设备名称、型号、型号号码与地区、序列号、CPU 架构、UDID;
  • lockdown get --domain com.apple.disk_usage:总容量、可用空间;
  • diagnostics battery single:电量、是否充电、最大容量(健康度)、循环次数。

展示(只保留最重要的):

分组项
设备设备名称、设备型号(商品名 + 型号代码)、系统版本(iOS 与 Build)、序列号、UDID(可复制)
状态存储(可用 / 总量与占用条)、电池(电量、充电中、健康度、循环次数)
连接连接方式与状态、目标应用

内部诊断信息仍只在开发者模式显示。底部固定“工具箱”按钮。

四、工具箱(独立窗口,仿 PerfDog) ​

窗口标题“工具箱”,左侧两项:崩溃日志获取、应用管理;右侧顶部为设备选择(已连接设备)。

崩溃日志获取 ​

  • crash ls --depth 9 读取全部日志路径(约 1 秒),解析文件名得到应用/类型与时间;按时间倒序。
  • 表格:勾选、文件名、日期(可排序);顶部“共 N 个日志文件”、搜索框、“刷新列表”。
  • 底部:全选、已选 N 项、“删除文件”(二次确认,crash clear <路径>)、“导出到本地”(选择文件夹,crash pull,完成后在 Finder 中显示)。
  • 与 PerfDog 的差异:设备不提供文件大小,不显示“大小”列。

应用管理 ​

  • apps list --type User --calculate-sizes(约 3 秒):应用名、Bundle ID、版本、大小(静态 + 动态)。
  • 图标:springboard icon,后台两路并行加载并按 Bundle ID + 版本缓存到本机,先显示占位图。
  • 顶部:“导入 IPA”(apps install,进度提示)、刷新、搜索(名称 / Bundle ID);“已安装应用:N”。
  • 表格:勾选、图标与名称、Bundle ID、版本、大小(可排序);行尾卸载按钮。
  • 底部:全选、已选 N 项与总大小、“批量卸载”(二次确认,apps uninstall,逐个执行并汇报成功数)。
  • 不包含 PerfDog 的“浏览”(应用沙盒文件浏览,仅对开启文件共享的应用有效),后续单独评估。

安全 ​

  • 删除、卸载均二次确认;正在测试的目标应用不允许卸载(提示先结束测试)。
  • 所有命令带超时(列表 30 秒、安装 10 分钟、卸载 60 秒),失败如实显示错误。

验收 ​

  • E2:解析(崩溃日志文件名、应用列表含大小、设备信息三类 JSON)单元测试。
  • E3:本机已连接设备上读取设备信息、应用列表与崩溃日志。
  • E4:Owner 操作导入、卸载、导出与删除日志。

Implementation Update · 2026-11-02 ​

文件修改
PerfowlApp/ControlClickSelection.swift(新)、SessionReviewViews.swift会话列表区域内的 Control+左键单击转换为 ⌘+单击(跳选),右键与双指点按仍弹出菜单;只在该区域生效。
PerfowlApp/PerfowlPalette.swift页面、侧栏、卡片、凸起、边框、分隔改为中性深灰(#22252E 系);文字与强调色不变。
PerfowlCore/DeviceToolsClient.swift(新)DeviceDetail(lockdown/磁盘/电池三类 JSON 合并,电池健康 = 最大容量 ÷ 设计容量)、ToolboxApp(含静态+动态大小)、CrashLogEntry(文件名解析进程与时间、只保留文件、按时间倒序);客户端封装 lockdown info、lockdown get --domain com.apple.disk_usage、diagnostics battery single、apps list --calculate-sizes、springboard icon、apps install/uninstall、crash ls --depth 9、crash pull --remote-file、crash clear <路径>,均带超时。
PerfowlApp/DeviceDetailStore.swift(新)、PerfowlWorkbenchView.swift设备信息按“设备 / 状态 / 连接”分组:设备名称、型号(商品名+代码+型号号码与地区)、系统版本、序列号、UDID;存储(可用/总量)、电池(电量、充电、健康、循环);连接状态与目标应用。切换设备时读取,60 秒内不重复,手动刷新可强制。底部固定“工具箱”与刷新按钮。
PerfowlApp/ToolboxView.swift(新)独立“工具箱”窗口(仿 PerfDog):左侧崩溃日志获取/应用管理;顶部设备选择。应用管理:导入 IPA、刷新、搜索、可排序表格(图标、应用名、Bundle ID、版本、大小、行内卸载)、全选、已选数量与总大小、批量卸载(二次确认,测试进行中不能卸载被测应用),图标两路并行加载并按 Bundle ID+版本缓存。崩溃日志:共 N 个、刷新、搜索、可排序表格(文件名、日期)、全选、删除文件(二次确认)、导出到本地(完成后在 Finder 中显示)。

偏差 ​

  • 崩溃日志不显示“大小”:crash ls 只返回路径,逐个查询大小代价高;如需要可后续用 AFC 批量读取。
  • 未实现 PerfDog 的“浏览”(应用沙盒文件),见设计说明。
  • 删除日志(crash clear <路径>)与安装/卸载未在本机真实执行,以免改动 Owner 的测试手机;导出(crash pull)已在真机验证。

验证 ​

  • E2:新增 DeviceToolsClientTests 3 项(设备详情合并与缺失不补 0、应用大小、日志列表解析排序);Swift 全量 451 项 0 失败(13 项跳过,含手动开启的真机/渲染测试)。
  • E3:本机已连接手机(设备 A)上实测:设备详情读到存储与电池(健康 93%、循环 1159 次);应用 44 个、44 个均有大小;崩溃日志 71 个;图标读取与日志导出成功;工具箱两页用真实数据渲染核对。
  • E4 待测:Owner 在 245 上操作 Control 跳选、深灰主题观感、设备信息、工具箱导入/卸载/导出/删除。

Validation Update · 2026-11-02:内部包 245 构建与同址安装(E3) ​

  • 来源:main cf8de2d1,Developer ID 签名构建 177.6 秒,来源门禁 passed。
  • 校验:冻结核心 107 个模块与 CLI 和源码一致,严格签名、DMG 与安装后文件树一致,安装后 probe ready;启动器只剩 /Applications/Perfowl.app。
  • 产物:MacApp/dist/Perfowl-245-macos-x86_64-internal.dmg,144,342,158 B,SHA-256 47bc7a7e6234acbf5cb2b3ac736e032d263a5e8604a167aebe9667dac05e57bd;244 安装包与回滚包在私有归档,回滚已核对。
  • 未完成:公证暂缓(Gatekeeper exit 3);工具箱安装/卸载/删除与界面观感的真机 E4 待 Owner 确认。

Plan Update · 2026-11-02:查看文件与设备信息精简(245 试用后) ​

Owner 反馈:① 工具箱导入与删除测试通过(E4);② 应用管理缺少“查看文件”(codesign4qc 有);③ 去掉工具箱按钮旁的刷新按钮;④ 设备信息中“状态”“连接”下为空,删掉;增加产品类型、WiFi 地址、蓝牙地址、可用容量;内容可选中复制,但不放复制按钮。

  • 查看文件:设备内置 CLI 的 apps afc 交互壳在冻结包内不可用,改由采集组件新增只读子命令 container ls|pull(pymobiledevice3 HouseArrestService,VendContainer 打开整个应用容器,非仅 Documents)。列目录一次连接内 listdir + 逐项 stat(单项失败容忍,不阻断),超时 60 秒;导出用 pull,超时 15 分钟。界面为应用管理行内“查看文件”按钮与右键菜单,弹出浏览窗口:返回上级、路径、刷新、名称/大小/修改时间表格(文件夹在前),双击进入,选中后“导出到本地”(完成后在 Finder 中显示)。不提供写入、删除。
  • 设备信息:改为单列平铺:设备名称、设备型号、产品类型(型号代码 + 型号号码与地区)、系统版本、序列号、UDID、WiFi 地址、蓝牙地址、可用容量(可用 / 共总量);文本可选中复制,无复制按钮;去掉“状态”“连接”分组与刷新按钮。异常时仍显示“重新检查设备 / 重新连接”。

Implementation Update · 2026-11-02:查看文件与设备信息精简 ​

文件修改
Sidecar/perfowl_collector_core/app_container.py(新)、perfowl_collector_core_cli.pycontainer ls/pull --udid --bundle-id --path [--output],输出 JSON(entries / pulled / error,出错退出码 2)。
PerfowlCore/DeviceToolsClient.swiftDeviceDetail 增加 WiFi / 蓝牙地址;ContainerEntry(文件夹在前、自然排序、错误透出);AppContainerClient(调用采集组件 container)。
PerfowlApp/ContainerBrowserView.swift(新)、ToolboxView.swift文件浏览窗口;应用管理行尾“查看文件”按钮与右键“查看文件”。
PerfowlApp/PerfowlWorkbenchView.swift设备信息平铺 9 项、可选中文本;删除“状态”“连接”分组与刷新按钮。原分组为空的原因:同一分组内行使用重复 id,SwiftUI 只渲染了首行之外的空白。

偏差 ​

  • 未复用设备内置 CLI 的 apps afc(冻结包内交互壳不可用),改走采集组件,与性能采集共用同一 pymobiledevice3 内核。
  • 只读:不提供上传、删除容器内文件。

验证 ​

  • E2:DeviceToolsClientTests 4 项(新增 WiFi/蓝牙解析、容器目录排序与错误透出);Swift 全量 453 项 0 失败(14 项跳过,含手动开启的真机/渲染测试);Python 3145 项,失败均为既有环境基线(native_direct_archive、native_raw_graph、sw1)及一项与本批无关的墙钟基准(双回归并行时机器繁忙)。
  • E3:本机已连接手机(设备 A)上,目标 App A 容器 /Documents 列出 30 项、单文件导出成功;浏览窗口用真实数据渲染核对。
  • E4 待测:Owner 在 246 上操作查看文件(进入、返回、导出)、设备信息新字段与选中复制。

Validation Update · 2026-11-02:内部包 246 构建与同址安装(E3) ​

  • 来源:main e6ce454c,Developer ID 签名构建 157.6 秒,来源门禁 passed。
  • 校验:冻结核心 108 个模块与 CLI 和源码一致(新增 app_container),包内采集组件在设备 A 上 container ls 列出 30 项;严格签名、DMG 与安装后文件树一致,安装后 probe ready;启动器只剩 /Applications/Perfowl.app。
  • 产物:MacApp/dist/Perfowl-246-macos-x86_64-internal.dmg,149,616,923 B,SHA-256 f8e3a7b7086707777bfbf4edbd0c2d806ca465a69cff4e6629b43804052d2321;245 安装包与回滚包在私有归档,回滚已核对。
  • 未完成:公证暂缓(Gatekeeper exit 3);查看文件与设备信息新字段的真机 E4 待 Owner 确认。

Fix Plan · 2026-11-02:查看文件 InstallationLookupFailed(246 试用后) ​

  • 现象(E4,Owner):部分应用“查看文件”报 PyMobileDevice3Exception: InstallationLookupFailed。
  • 复现(E3,设备 A 全部 43 个用户应用逐一测试):完整容器(VendContainer)35 个成功、8 个被系统拒绝;被拒绝的 8 个中,2 个开启了文件共享,只读 Documents(VendDocuments)可读;其余 6 个两种方式都被拒绝(含 TestFlight)。被拒绝的确切条件未证实,不写成定论。
  • 修复:完整容器被拒绝时自动退回 Documents 模式;该模式下根目录只列出 Documents,其他路径不可访问;窗口状态栏注明“仅文件共享目录”。两种方式都被拒绝时显示“系统不允许读取此应用的文件”,不再透出原始异常。仍只读,每次操作一次连接,额外开销仅在被拒绝时多一次握手(约 0.3 秒)。

Implementation Update · 2026-11-02 ​

文件修改
Sidecar/perfowl_collector_core/app_container.py完整容器被拒绝(InstallationLookupFailed)时退回 Documents 模式:根目录只列 Documents,其他路径返回“此应用只开放文件共享目录(Documents)”;导出根目录即导出 Documents;两种方式都被拒绝时返回“系统不允许读取此应用的文件”;ls 输出增加 documentsOnly。
PerfowlCore/DeviceToolsClient.swift、PerfowlApp/ContainerBrowserView.swiftAppContainerClient.list 同时返回是否仅 Documents;浏览窗口状态栏注明“此应用仅开放文件共享目录”。

验证:E2 DeviceToolsClientTests 4 项(新增 documentsOnly 解析),Swift 全量 453 项 0 失败;E3 设备 A 上:开启文件共享的应用根目录列出 Documents、进入后可读,/Library 返回中文提示;两种方式都被拒绝的应用返回“系统不允许读取此应用的文件”;普通应用完整容器不受影响。E4 待 Owner 在 247 上确认。

Validation Update · 2026-11-02:内部包 247 构建与同址安装(E3) ​

  • 来源:main 8ed6ab1f,Developer ID 签名构建 393.7 秒,来源门禁 passed。
  • 校验:冻结核心 108 个模块与 CLI 和源码一致,包内采集组件对开启文件共享的应用返回 Documents;严格签名、DMG 与安装后文件树一致,安装后 probe ready;启动器只剩 /Applications/Perfowl.app。
  • 产物:MacApp/dist/Perfowl-247-macos-x86_64-internal.dmg,149,451,078 B,SHA-256 83528a2909ffa937dd56c64d2c2ec45a1a263fd12beeb818e1b87e568432285e;246 安装包与回滚包在私有归档,回滚已核对。
  • 未完成:公证暂缓(Gatekeeper exit 3);查看文件回退与提示的真机 E4 待 Owner 确认。

Perf Plan · 2026-11-02:查看文件加载提速(247 试用后) ​

  • 现象(E4,Owner):查看文件每次进入/返回目录都要 3 秒以上,体验不如 PerfDog。
  • 剖析(E3,设备 A,目标 App A,30 项目录):每次操作新启动冻结采集组件约 0.5–1.0 秒,向设备申请容器(VendContainer)约 1.1 秒,列目录 0.003 秒,30 项逐个 stat 0.06 秒;单次命令总计约 2.3–2.5 秒,加上界面调度体感超过 3 秒。耗时几乎全在“每次都重新启动进程和重新申请容器”。
  • 方案:
    1. 采集组件新增 container serve --udid --bundle-id:启动一次、申请一次容器,之后按行读取请求(ls / pull),按行返回 JSON;连接异常时下一请求自动重开一次;标准输入关闭即退出。
    2. App 端浏览窗口打开时启动会话、关闭时结束;请求串行,ls 超时 60 秒、pull 15 分钟,超时或进程退出则丢弃会话,下次请求重建。
    3. 已浏览目录缓存:返回或再次进入时先显示缓存,再在后台刷新。
  • 目标:首次打开约 1.5–2 秒(启动+申请容器各一次,与 PerfDog 首次同量级);之后进入/返回目录 < 0.2 秒。常驻进程只在窗口打开期间存在,空闲无轮询。

Implementation Update · 2026-11-02:查看文件加载提速 ​

文件修改
Sidecar/perfowl_collector_core/app_container.py、perfowl_collector_core_cli.py新增 container serve:一次申请容器,按行处理 ls/pull;文件级错误(AFC 错误、不在 Documents 内)只回报不重连,连接类错误重开一次;标准输入关闭即退出。一次性 ls/pull 保留。
PerfowlCore/DeviceToolsClient.swiftAppContainerSession(actor):窗口内常驻一个采集组件进程,请求串行,单请求看门狗超时(ls 60 秒、pull 15 分钟),超时或进程退出即丢弃并在下一请求重建;进程登记到 OwnedProcessShutdownRegistry,App 退出时一并结束。LineQueue 按行拆分标准输出。
PerfowlApp/ContainerBrowserView.swift浏览窗口使用会话;已浏览目录缓存后先显示再后台刷新;窗口关闭结束会话;导出固定在发起时的目录。

验证:

  • E2:Swift 全量 455 项 0 失败(新增 LineQueue 分块与 EOF 测试;手动开启的会话计时测试);Python 无新增失败。
  • E3(设备 A、目标 App A、源码解释器运行采集组件):命令层 serve 首次 2.0 秒,此后 /Documents 30 项 54 ms、/Library 31 ms、返回 / 11 ms、路径不存在 2 ms 且不重连;App 端会话首次 2.8 秒(源码解释器启动较冻结包慢),此后 6–53 ms。对照提速前每次 2.3–2.5 秒(命令层)。
  • 偏差:首次打开仍需启动进程与申请容器(冻结包约 2 秒),未做“选中行即预热”,以免为未打开的应用常驻进程。
  • E4 待 Owner 在 248 上确认体感。

Validation Update · 2026-11-02:内部包 248 构建与同址安装(E3) ​

  • 来源:main 153a03be,Developer ID 签名构建 263.9 秒,来源门禁 passed。
  • 提速实测(冻结采集组件,设备 A,目标 App A):serve 首次打开 2.28–2.42 秒(新二进制第一次运行 3.8 秒),此后 /Documents 30 项 67 ms、/Library 50 ms、返回 / 14 ms;提速前每次操作 2.3–2.5 秒。
  • 校验:冻结核心 108 个模块与 CLI 和源码一致,严格签名、DMG 与安装后文件树一致,安装后 probe ready;启动器只剩 /Applications/Perfowl.app。
  • 产物:MacApp/dist/Perfowl-248-macos-x86_64-internal.dmg,147,068,292 B,SHA-256 a72c23d52fd9f33cc66e7411dc8d31de39bc8df46d25491ecd3e5b9450e4dc8e;247 安装包与回滚包在私有归档,回滚已核对。
  • 未完成:公证暂缓(Gatekeeper exit 3);体感 E4 待 Owner 确认。

Fix Plan · 2026-11-02:248 试用反馈(读取失败提示、重新连接按钮、Dock 退出、应用列表刷新) ​

  1. AfcException [Errno 10] READ_DIR:设备 A 上可读完整容器的 36 个应用逐层扫描(3 层),唯一失败目录是每个应用都有的 /SystemData,AFC 状态 10 = 无权限(系统保护目录,E3)。修复:错误按状态码转为中文(10“没有权限读取此文件夹(系统保护目录)”、8“文件或文件夹不存在”);进入失败时停留在原目录并保留原列表,只在状态栏提示。
  2. 设备信息“重新连接”按钮:连接过程中短暂出现,连接成功后消失,Owner 要求去掉;该按钮整体移除(无设备时的“重新检查设备”保留)。
  3. 打开查看文件后无法从 Dock 退出:服务进程收到 SIGTERM 0.01 秒内退出(已排除);查看文件以工具箱窗口上的弹出层(sheet)呈现,弹出层未关闭时退出请求被搁置。修复:改为独立窗口(与工具箱相同方式,按应用复用,关闭即结束会话),退出 App 时窗口一并关闭。
  4. 应用列表刷新按钮:应用管理页去掉刷新按钮;安装、卸载完成后已自动刷新(保持);切换设备、打开窗口时自动读取。崩溃日志页保留刷新(日志会在设备上新增)。

Implementation Update · 2026-11-02:248 试用反馈 ​

文件修改
Sidecar/perfowl_collector_core/app_container.pyAFC 状态码转中文:10“没有权限读取此文件夹(系统保护目录)”、8“文件或文件夹不存在”;会话与一次性命令共用。
PerfowlApp/ContainerBrowserView.swift查看文件改为独立窗口(ContainerBrowserWindows,按设备+应用复用,关闭窗口即结束会话);进入失败时退回原目录并保留列表,状态栏提示“无法打开‘X’:原因”。
PerfowlApp/ToolboxView.swift去掉弹出层;应用管理页去掉刷新按钮(崩溃日志页保留),安装/卸载后自动刷新不变。
PerfowlApp/PerfowlWorkbenchView.swift设备信息去掉“重新连接”按钮;无设备时“重新检查设备”保留,且无按钮时不再留空白。

验证:E2 Swift 全量 455 项 0 失败,Python 无新增失败;E3 设备 A:/SystemData 返回“没有权限读取此文件夹(系统保护目录)”,不存在路径返回“文件或文件夹不存在”,随后 /Documents 30 项正常(会话不断开)。Dock 退出问题的原因(弹出层阻止退出请求)为推断,未能在本机自动化复现,待 Owner 在 249 上确认(E4)。

Validation Update · 2026-11-02:内部包 249 构建与同址安装(E3) ​

  • 来源:main d92306fb,Developer ID 签名构建 165.1 秒,来源门禁 passed;包内采集组件读取 /SystemData 返回“没有权限读取此文件夹(系统保护目录)”。
  • 校验:冻结核心 108 个模块与 CLI 和源码一致,严格签名、DMG 与安装后文件树一致,安装后 probe ready;启动器只剩 /Applications/Perfowl.app。
  • 产物:MacApp/dist/Perfowl-249-macos-x86_64-internal.dmg,147,975,099 B,SHA-256 d8dd5517cdec54918dce75008d9ba449622b50aac101bcd4556c0c07d97ea9de;248 安装包与回滚包在私有归档,回滚已核对。
  • 未完成:公证暂缓(Gatekeeper exit 3);Dock 退出、按钮移除与读取提示的 E4 待 Owner 确认。

Validation Update · 2026-11-03:Owner 真机确认 ​

Owner 在内部包 251 上确认 2026-11-02 各批工具箱修改真机通过(E4):导入 IPA、卸载、查看文件(含文件共享目录回退、加载提速、/SystemData 中文原因)、打开查看文件窗口后可从 Dock 退出、去掉“重新连接”与刷新按钮、设备信息九项。单设备(设备 A,iOS 26)。

Perfowl · Performance Observer