主题:在移动端测试工具中实现「选择本机 APK → 安装到已连接 Android 设备」的完整链路,以及可选的扩展(内部分发、批量安装)。
1. 功能概述
1.1 业务场景
- 测试同学需要频繁将 APK 安装到真机 进行回归、联调或验收:
- 本机已有 APK 文件(如 CI 构建产物、内部分发包),希望一键安装到当前连接的设备。
- 避免手工敲
adb install -r xxx.apk或拖拽到模拟器。 - 目标:在工具内通过 选择文件 → 选择设备(可选)→ 安装,完成从本机 APK 到设备安装的闭环。
1.2 能力范围
- 当前实现:
- 通过系统对话框选择本机 APK 文件。
- 将所选 APK 安装到当前选中的 Android 设备(或默认第一台)。
- 安装成功后可选刷新应用列表。
- 可扩展:
- 从内网/制品库下载 APK 再安装。
- 多设备批量安装、安装记录与版本管理。
2. 技术实现
2.1 整体流程
用户点击「安装应用」
→ 调用主进程「选择 APK 文件」对话框
→ 用户选择本机 APK,获得 filePath
→ DeviceService.installAndroidApp(filePath, deviceId)
→ adb install -r "" 安装到设备
→ 返回成功/失败,前端提示并可选刷新应用列表
2.2 主进程:选择 APK 文件
- 职责:弹出系统「打开文件」对话框,限制为 APK 类型,将用户选择的文件路径返回给渲染进程。
- 实现(
electron/main.js):
ipcMain.handle('select-apk-file', async () => {
if (!mainWindow) {
return { canceled: true, filePath: '' }
}
const result = await dialog.showOpenDialog(mainWindow, {
title: '选择 APK 文件',
properties: ['openFile'],
filters: [
{ name: 'Android 应用包 (*.apk)', extensions: ['apk'] },
{ name: '所有文件', extensions: ['*'] }
]
})
return {
canceled: result.canceled,
filePath: result.canceled ? '' : (result.filePaths[0] || '')
}
})
- 说明:
properties: ['openFile']表示单选文件。filters优先展示.apk,同时保留「所有文件」避免误选其它格式。- 取消或未选时返回
canceled: true或filePath: '',由前端判断并直接 return,不发起安装。
2.3 预加载层暴露 API
- preload.cjs 中暴露:
selectApkFile: () => ipcRenderer.invoke('select-apk-file'),
- 渲染进程通过
window.electronAPI.selectApkFile()调用,得到{ canceled, filePath }。
2.4 DeviceService:统一安装接口
- DeviceService.installAndroidApp(apkPath, deviceId):
仅做平台转发,实际安装逻辑在 adb.installApp(apkPath, deviceId)。
- 调用方:Android 设备面板中的「安装应用」按钮,传入当前设备 ID(或空则使用默认设备)。
2.5 ADB 层:installApp 实现
- 位置:
src/utils/adb.js的installApp(apkPath, deviceId)。 - 要点:
- 参数:
apkPath为本机 APK 绝对路径;deviceId为空时取getDevices()[0].id。 - 设备校验:若无设备,直接返回
{ success: false, error: '未找到 Android 设备' }。 - 路径安全:对路径中的双引号转义(
replace(/"/g, '\"')),避免在 shell 中截断。 - 命令:
adb -s install -r ""。
-r 表示覆盖安装(保留数据),适合测试场景多次安装同一包。
- 超时:安装可能较慢(大包或低性能设备),当前使用 300 秒超时。
- 结果判断:根据
result.success以及 stdout/stderr 中是否包含success或成功判断安装是否成功;否则将 stderr/stdout 或 error 作为错误信息返回。
const installCmd = `-s ${deviceId} install -r "${safePath}"`
const result = await this.execute(installCmd, { timeout: 300000 })
const output = ((result.stdout || '') + 'n' + (result.stderr || '')).toLowerCase()
if (result.success && (output.includes('success') || output.includes('成功'))) {
return { success: true, message: '应用安装成功', stdout: result.stdout, stderr: result.stderr }
}
return {
success: false,
error: result.error || result.stderr || result.stdout || '安装失败,请检查 APK 是否有效、设备是否已连接'
}
2.6 前端:安装入口与反馈
- 入口:Android 设备面板中「安装应用」按钮,点击后调用
installApp(deviceId)(如当前设备 ID 或列表第一台)。 - 流程:
- 检查
window.electronAPI?.selectApkFile是否存在,不存在则提示「缺少选择文件能力」。 await window.electronAPI.selectApkFile(),若canceled || !filePath则直接 return。loading.value = true,调用DeviceService.installAndroidApp(filePath, deviceId)。- 根据
result.success弹出成功/失败通知;成功且当前在「应用」Tab 时可调用showAppList(currentDeviceId)刷新应用列表。 - 在
finally中loading.value = false。
- 错误提示:失败时用
result.error或 catch 的String(error)作为 Notification 的 message,便于用户排查(如「未找到 Android 设备」「安装失败,请检查 APK 是否有效」)。
3. 错误处理与体验
3.1 常见错误
| 现象 | 可能原因 | 处理建议 | |------|----------|----------| | 选择文件后无反应或安装失败 | 路径含空格/特殊字符导致 shell 解析错误 | 已对双引号转义;若路径含空格,确保外层用双引号包裹(当前 "${safePath}" 已满足) | | 提示「未找到 Android 设备」 | 未连接设备或 adb devices 无 device | 检查 USB 连接、设备是否开启 USB 调试、是否授权本机 | | 安装失败,stderr 含 signature 等 | 已安装版本签名与当前 APK 不一致 | 先卸载旧版本再安装,或使用 install -r -d 等(按需扩展) | | 超时 | APK 体积大或设备慢 | 当前 300s;若仍超时可适当加大或提示用户等待 |
3.2 体验优化
- 安装中:按钮或区域 loading,避免重复点击。
- 安装成功:成功提示 + 可选自动刷新应用列表,便于立刻看到新装应用。
- 安装失败:错误信息直接展示在 Notification 中,必要时在控制台输出完整 stdout/stderr 便于排查。
4. 与 Assist Agent 的区分
- 本功能:用户主动选择本机任意 APK 并安装到设备,面向「装被测应用、装内部分发包」等场景。
- Assist Agent:工具内置的
android-assist-agent/build/app-release.apk,用于应用列表、HTTP 代理等能力;由ensureAssistAgentInstalled()在设备列表就绪后按需静默安装,无需用户选择文件。 - 两套逻辑独立:用户安装 APK 走
selectApkFile+installAndroidApp;Assist Agent 走ensureAssistAgentInstalled+ 固定路径 APK。
5. 扩展方向(可选)
- 从 URL 安装:
增加「输入 APK 下载地址」或从内网制品库选择版本,主进程或渲染进程下载到临时目录后调用 installAndroidApp(tempPath, deviceId),安装完成后删除临时文件。
- 多设备批量安装:
用户选择一台或多台设备,对同一 APK 路径循环调用 installAndroidApp(apkPath, deviceId),汇总成功/失败列表并提示。
- 安装记录:
将每次安装的包名、版本、设备 ID、时间记录到本地或上报,便于统计或回溯。
小结
- Android 端 APK 功能通过 主进程文件选择对话框 + DeviceService.installAndroidApp + adb install -r 实现「选文件 → 装到设备」的闭环。
- 路径转义、超时、成功判定与错误信息统一在 adb 层处理,前端只负责调用与提示;与 Assist Agent 的自动安装相互独立,便于维护和扩展。







Comments | NOTHING