# 21 实现 Android 设备搜索 - 类型:需求 - 父级大工单:#1 - 所属 MVP / 版本:#2 / MVP - 状态:已实现,待验收 - 日期:2026-08-07 - Gitea 工单:http://ilaer.eicp.net:8418/chengma/cmautobuy/issues/21 ## 背景与目标 设置页原有“搜索”按钮只会发出信号,没有执行 ADB 查询。此次补齐实际搜索能力,让用户能够在不阻塞界面的情况下查看电脑当前识别的 USB 和 Wi-Fi Android 设备。 ## 最终方案 - 新增独立的 `AndroidDeviceService`,使用标准库执行 `adb devices -l`。 - 解析设备号、USB/Wi-Fi 连接方式、型号和 ADB 状态;正常设备再查询 Android 版本。 - 单台设备的属性读取失败时保留该设备,并用 `—` 表示未知属性。 - 使用 `QObject + moveToThread` 在后台搜索,工作线程不访问 QWidget。 - 搜索期间禁用设备管理命令;成功、无设备、失败和超时使用页面原有状态区反馈。 - 搜索失败保留上一次列表;搜索成功按稳定设备号保留仍有效的勾选。 - 页面关闭时停止后续属性查询、断开界面信号,并等待当前 ADB 命令在有限超时内结束。 - 没有增加依赖,没有修改数据库、Admin 接口、设备连接和 PDD 自动化逻辑。 该任务是现有设置页的局部交互补全,没有改动布局,因此按 Windows UI/UX 规范跳过 HTML 原型。 ## 改了哪些 - `client/src/android_device_service.py`:ADB 命令执行、列表解析、属性补充和可读错误。 - `client/src/settings_ui_event.py`:搜索 Worker、线程生命周期、状态反馈和重复点击保护。 - `client/src/settings_ui.py`:注入设备服务,并补充设备状态区无障碍名称。 - `client/test/test_android_device_service.py`:覆盖 USB/Wi-Fi、属性读取、ADB 缺失、失败和超时。 - `client/test/test_settings_ui_event.py`:覆盖成功、空列表、失败保留、勾选保持、主线程响应和关闭安全。 ## 验收结果 | 验收标准 | 结果 | |---|---| | 点击搜索会在后台执行 ADB,Qt 主线程保持响应 | 通过 | | USB 和 Wi-Fi 设备正确区分 | 通过 | | 正常设备显示型号、Android 版本和已连接状态 | 自动测试通过,待可见真机核对 | | 离线、未授权设备显示且不可勾选 | 通过 | | 无设备时保留占位行并提示 | 通过 | | ADB 缺失、失败和超时提供恢复提示 | 通过 | | 搜索期间防止重复搜索,完成后恢复按钮 | 通过 | | 刷新按设备号保持或清除勾选 | 通过 | | 页面关闭后忽略迟到结果 | 通过 | | 不增加依赖,不修改数据库和 Admin 接口 | 通过 | | 全量测试、语法检查和差异检查 | 通过 | ## 测试 - 执行的命令: ```powershell # client 目录 C:/Python310/python.exe -m py_compile src/android_device_service.py src/settings_ui.py src/settings_ui_event.py test/test_android_device_service.py test/test_settings_ui_event.py $env:QT_QPA_PLATFORM="offscreen" C:/Python310/python.exe -m unittest discover -s test -p "test_*.py" ``` - 结果:Client 全量 61 项测试通过;真实 ADB 服务调用曾识别到 1 台 Wi-Fi 设备;设备断开后的真实离屏按钮搜索正确显示无设备状态。 - **没验证到的部分**:尚未在设备保持连接时,用可见窗口人工核对设备号、型号、Android 版本和状态列;未验证打包后的 exe 查找系统 ADB;Narrator、高对比度和 200% 缩放未做人工检查。 测试环境仍会输出现有 PyQt5 字体目录缺失和 sip API 过时警告,不影响测试结果。 ## 相关提交 - `45fde81` `feat: 实现 Android 设备搜索 (#21)`