161 lines
7.4 KiB
Markdown
161 lines
7.4 KiB
Markdown
# 应用自动更新
|
||
|
||
## 概述
|
||
|
||
基于 `electron-updater` 实现应用内自动更新,支持 macOS / Windows (NSIS) / Linux 自动下载安装,Windows MSI 安装引导到下载页(优先 OSS 安装包直链)。
|
||
|
||
**强制使用 latest.json**:应用与 Release 流程均以 OSS 上的 `latest.json` 为**唯一数据源**。版本检查、各平台下载地址、签名与大小均来自该文件;不直接依赖 GitHub Release 或 electron-builder 生成的 yml 作为来源。
|
||
|
||
**更新源(macOS / Linux 应用内升级)**:检查与下载均走阿里云 OSS。
|
||
|
||
- **检查更新**:**仅**拉取 OSS `latest/latest.json` 获取最新版本;其中 `platforms` 已包含各平台完整的 OSS 下载包地址(url、signature、size)。若有更新则将 electron-updater 的 feed 设为版本化 OSS 路径 `${OSS_BASE}/electron-v${version}`。
|
||
- **下载安装包**:安装包地址**仅**来自 `latest.json` 的 `platforms`(已是完整 OSS URL)。electron-updater 实际下载时从 feed 请求的 `latest-mac.yml` / `latest-linux.yml` 等,**必须**由同一份 `latest.json` 的 `platforms` 在 Release 流程中派生生成,不得使用 GitHub 自带的 yml。
|
||
- **失败处理**:OSS 不可达或元数据异常时,直接报错并引导用户前往下载页,不回退到 GitHub。
|
||
|
||
## 核心文件
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `src/main/services/autoUpdater.ts` | 更新服务:检查、下载、安装、状态管理 |
|
||
| `src/renderer/components/pages/AboutPage.tsx` | 关于页面:手动检查更新 UI |
|
||
| `src/main/window/trayManager.ts` | 托盘菜单:检查更新入口 |
|
||
| `src/main/ipc/appHandlers.ts` | IPC 处理:checkUpdate / downloadUpdate / installUpdate / openReleasesPage |
|
||
| `src/preload/index.ts` | preload 暴露 API |
|
||
| `src/shared/types/updateTypes.ts` | 类型定义:UpdateState / UpdateInfo / UpdateProgress |
|
||
| `dev-app-update.yml` | 开发模式更新源配置 |
|
||
|
||
## 更新流程
|
||
|
||
### 1. 启动自动检查
|
||
|
||
```
|
||
App 启动 → 延迟 10s → checkForUpdates()
|
||
│
|
||
├── 无更新 → 静默,不提示
|
||
│
|
||
├── 有更新 → 检查 skipped version
|
||
│ │
|
||
│ ├── 已跳过 → 不弹窗
|
||
│ │
|
||
│ └── 未跳过 → 弹窗提示
|
||
│ │
|
||
│ ├── "立即更新" → 下载 → 二次确认 → 重启安装
|
||
│ │
|
||
│ └── "跳过此版本" → 记录到文件,下次不再提示
|
||
│
|
||
└── 失败 → 静默记录日志
|
||
```
|
||
|
||
### 2. 手动检查(About 页面)
|
||
|
||
```
|
||
用户点击 "检查更新"
|
||
│
|
||
├── 检查中... (loading 状态)
|
||
│
|
||
├── 无更新 → 提示 "当前已是最新版本",重置按钮
|
||
│
|
||
├── 有更新 → 显示 "下载更新" 按钮
|
||
│ │
|
||
│ └── 点击 → 下载(显示进度条)→ 完成 → Modal 确认 → 重启安装
|
||
│
|
||
└── 错误 → 显示错误信息 + 重试按钮
|
||
```
|
||
|
||
### 3. 手动检查(托盘菜单)
|
||
|
||
与 About 页面类似,但使用原生 `dialog.showMessageBox` 弹窗交互。
|
||
|
||
## Windows 安装类型检测
|
||
|
||
通过检查 NSIS 卸载程序文件是否存在来区分安装方式:
|
||
|
||
```typescript
|
||
// NSIS 安装会生成: {appDir}/Uninstall {productName}.exe
|
||
// MSI 安装由 Windows Installer 管理,无此文件
|
||
function detectInstallerType(): InstallerType {
|
||
const nsisUninstaller = path.join(appDir, `Uninstall ${productName}.exe`);
|
||
return fs.existsSync(nsisUninstaller) ? 'nsis' : 'msi';
|
||
}
|
||
```
|
||
|
||
| 安装类型 | 自动更新 | 行为 |
|
||
|----------|---------|------|
|
||
| NSIS (.exe) | 支持 | 下载 → 重启安装 |
|
||
| MSI (.msi) | 不支持 | 引导到下载页(按 MSI 优先解析下载包) |
|
||
| macOS (.dmg) | 支持 | 下载 → 重启安装 |
|
||
| Linux (.AppImage/.deb) | 支持 | 下载 → 重启安装 |
|
||
|
||
## 跳过版本
|
||
|
||
- 用户在启动弹窗中选择"跳过此版本"后,版本号写入 `~/.qimingclaw/.skipped-update-version`
|
||
- 下次启动时,若远程最新版本与已跳过版本相同,不弹窗
|
||
- 出现更新的版本(高于已跳过版本)时,重新弹窗提示
|
||
- 手动检查更新(About 页面 / 托盘菜单)不受跳过逻辑影响
|
||
|
||
## 安装前清理
|
||
|
||
`installUpdate()` 在调用 `quitAndInstall()` 之前,先执行 `cleanupAllProcesses()`:
|
||
|
||
- 停止 Computer Server
|
||
- 销毁 Unified Agent Service
|
||
- 终止 Agent Runner / Lanproxy / File Server 进程
|
||
- 清理 MCP Proxy
|
||
- 停止所有 Engine 进程
|
||
|
||
## 开发模式
|
||
|
||
- 通过 `dev-app-update.yml` 配置更新源(GitHub)
|
||
- `forceDevUpdateConfig = true` 启用开发模式检查
|
||
- 允许检查更新(验证 API 通路)
|
||
- 下载和安装被阻止(Squirrel.Mac bundle ID 不匹配会导致崩溃)
|
||
- `autoInstallOnAppQuit = false`
|
||
|
||
## OSS 单源策略(强制 latest.json)
|
||
|
||
所有更新元数据**强制以 latest.json 为准**:应用端只读 OSS `latest/latest.json` 做版本判断与地址解析;Release 流程只产出并上传由该文件派生的 yml,禁止使用或上传 GitHub 自带的 yml。
|
||
|
||
| 步骤 | 策略 |
|
||
|--------------|------|
|
||
| 检查更新 | 仅 OSS latest.json |
|
||
| Feed 基地址 | 仅 OSS 版本化路径 |
|
||
| 下载安装包 | 仅 OSS(yml 必须由 latest.json 的 platforms 派生) |
|
||
| OSS 异常 | 报错 + 引导下载页,不回退 GitHub |
|
||
|
||
**数据源规则**:OSS 上**只**维护并信任 `latest.json`(含 version、notes、pub_date、platforms 多架构与完整 OSS 下载地址)。Release 流程(`.github/workflows/release-electron.yml`)**必须**根据该 `latest.json` 的 `platforms` 生成 electron-updater 所需的 `latest-mac.yml`、`latest-linux.yml`、`latest.yml`,并写入 release-assets 后一并上传;**禁止**使用或上传 GitHub 自带的 yml;yml 内下载地址为相对路径(相对 feed 基地址即 OSS 版本化路径)。
|
||
|
||
本地触发 OSS 同步时,可在本 crate 下执行 `scripts/sync-oss.sh <tag>`(如 `electron-v0.8.0`),会触发上述 workflow 并轮询直至完成;依赖 `gh`、`jq`。
|
||
|
||
## 自定义更新源
|
||
|
||
通过环境变量 `QIMING_UPDATE_SERVER` 可指定自定义更新服务器:
|
||
|
||
```bash
|
||
QIMING_UPDATE_SERVER=http://localhost:8080/updates npm run dev
|
||
```
|
||
|
||
使用 `generic` provider,适合本地测试。
|
||
|
||
## UpdateState 类型
|
||
|
||
```typescript
|
||
interface UpdateState {
|
||
status: 'idle' | 'checking' | 'available' | 'not-available' | 'downloading' | 'downloaded' | 'error';
|
||
version?: string;
|
||
progress?: { percent: number; bytesPerSecond: number; transferred: number; total: number };
|
||
error?: string;
|
||
canAutoUpdate?: boolean; // false 表示 MSI 安装,需手动下载
|
||
}
|
||
```
|
||
|
||
## IPC 通道
|
||
|
||
| 通道 | 方向 | 说明 |
|
||
|------|------|------|
|
||
| `app:checkUpdate` | renderer → main | 手动检查更新 |
|
||
| `app:downloadUpdate` | renderer → main | 下载更新 |
|
||
| `app:installUpdate` | renderer → main | 重启安装 |
|
||
| `app:getUpdateState` | renderer → main | 获取当前更新状态 |
|
||
| `app:openReleasesPage` | renderer → main | 打开下载页(从 latest.json 解析 OSS 安装包直链) |
|
||
| `update:status` | main → renderer | 推送更新状态变化 |
|