全量更新是最经典、最可靠的桌面应用更新方式。它的思路很直白:当新版本发布后,应用检测到更新,下载完整的安装包,然后触发操作系统的安装流程,替换掉旧版本。虽然增量更新在某些场景下能节省流量,但全量更新的实现更简单、出错后恢复更容易,因此绝大多数 Electron 应用(包括 VS Code、Discord、Notion)仍然首选全量更新。
这一节我们将使用 electron-updater(electron-builder 生态的官方更新模块)来实现一套完整的全量更新流程,覆盖版本检测、包下载和安装替换三个环节。electron-updater 底层封装了 Squirrel(Windows)和 DMG/ZIP(macOS)的安装逻辑,也支持 AppImage 和 deb(Linux),你不需要关心不同平台的安装差异。
17.3.1 版本检测:自动检查 or 手动触发
electron-updater 默认会在应用启动后自动检查更新,但你也可以根据业务需求改成手动触发(比如用户在设置页面点击“检查更新”按钮)。检测更新的核心方法是 autoUpdater.checkForUpdates(),它会向你配置的服务器请求一个 latest.yml(或 latest-mac.yml、latest-linux.yml)文件,该文件里包含了最新版本号、安装包下载地址、文件哈希等信息。
准备工作
首先在 package.json 中添加依赖并调整打包配置:
// devDependencies 中加入 electron-builder(包含 electron-updater)
{
"devDependencies": {
"electron": "^28.0.0",
"electron-builder": "^24.9.0"
},
"dependencies": {
"electron-updater": "^6.1.0"
}
}
在 electron-builder 的配置中开启发布选项,指定一个存放安装包的静态服务器或 S3/GitHub Releases。最简单的方案是用一个可访问的 HTTP 服务器,把打包产物完整上传:
# electron-builder.yml
appId: com.example.myapp
productName: MyApp
publish:
provider: generic
url: https://your-server.com/updates/ # 存放 latest.yml 和安装包的目录
执行 electron-builder 打包后,生成目录下会出现 latest.yml 文件和 .exe/.dmg/.AppImage 等安装包。你只需将整个目录原样上传到服务器对应的路径下。
主进程中的更新逻辑
在主进程里引入 autoUpdater,并添加必要的事件监听:
// main.js
const { autoUpdater } = require('electron-updater');
const { app, BrowserWindow, ipcMain } = require('electron');
// 禁用自动下载(可配),让用户决定何时下载
autoUpdater.autoDownload = false;
// 当检测到新版本时,通知渲染进程
autoUpdater.on('update-available', (info) => {
// info.version 是新版本号
mainWindow.webContents.send('update-available', info.version);
});
// 下载进度(可选,用于展示进度条)
autoUpdater.on('download-progress', (progress) => {
mainWindow.webContents.send('download-progress', progress.percent);
});
// 下载完成,准备安装
autoUpdater.on('update-downloaded', () => {
mainWindow.webContents.send('update-downloaded');
});
// 错误处理
autoUpdater.on('error', (err) => {
console.error('更新出错:', err);
mainWindow.webContents.send('update-error', err.message);
});
// 启动后自动检查(也可由渲染进程触发)
app.whenReady().then(() => {
// ... 创建窗口等操作
autoUpdater.checkForUpdates(); // 自动检查
});
// 允许渲染进程主动触发检查或下载
ipcMain.handle('check-for-update', () => {
return autoUpdater.checkForUpdates();
});
ipcMain.handle('download-update', () => {
return autoUpdater.downloadUpdate();
});
ipcMain.handle('install-update', () => {
// 退出应用并安装
autoUpdater.quitAndInstall();
});
渲染进程配合显示
在渲染进程中,你可以收到主进程发来的事件,并根据状态展示不同的 UI:
// renderer.js (或 Vue/React 组件内)
const { ipcRenderer } = require('electron');
ipcRenderer.on('update-available', (_, version) => {
console.log(`发现新版本 ${version}`);
// 显示提示框,询问用户是否下载
});
ipcRenderer.on('download-progress', (_, percent) => {
console.log(`下载进度: ${percent}%`);
// 更新进度条
});
ipcRenderer.on('update-downloaded', () => {
// 显示“安装并重启”按钮
});
手动触发检查
如果你想在用户点击“检查更新”时才发起请求,只需取消自动调用,改为在渲染进程通过 IPC 调用:
// 前端点击按钮后
document.getElementById('check-update-btn').addEventListener('click', async () => {
const result = await ipcRenderer.invoke('check-for-update');
// result 包含 updateInfo 等信息
});
17.3.2 包下载:进度反馈与断点续传
electron-updater 会自动处理下载过程,你无需手动写 HTTP 请求。它内置了智能的重试和断点续传(基于文件大小校验),并且默认会校验安装包的 SHA512 哈希值,避免下载到被篡改或损坏的文件。
download-progress 事件可以让你为界面提供实时的下载进度反馈,这对用户体验很重要。如果你想让用户看到具体的下载速度,可以在主进程中利用 autoUpdater 的其他事件或自己扩展(如监听 net 模块),但通常给出百分比就够了。
如果下载过程因为网络波动失败,electron-updater 会在下一次 checkForUpdates 时自动尝试继续未完成的下载。如果你希望手动控制,可以调用 autoUpdater.downloadUpdate(),它会返回一个 Promise,下载完成后 resolve。
17.3.3 安装替换:平台差异与静默安装
下载完成后,update-downloaded 事件触发。此时安装包已经保存在系统的临时目录中。调用 autoUpdater.quitAndInstall() 会发生以下操作:
- Windows(使用 NSIS 或 Squirrel.Windows):退出应用,启动安装程序,等待安装完成后自动重启应用(如果安装包支持)。
- macOS(使用 DMG):应用退出,自动挂载 DMG 并尝试将新版本拷贝到
/Applications,之后重新启动。如果你使用zip格式,行为类似。 - Linux(AppImage 或 deb):
electron-updater会尝试替换当前 AppImage 文件,或在 deb 模式下调用系统包管理器进行安装。
静默安装与强制更新
有些场景(比如安全热修复)需要强制用户更新。这时你可以在检测到更新后禁用应用的主要功能,只显示一个“正在更新”的界面,直到安装完成。也可以使用 autoUpdater.autoDownload = true 并开启动静默下载,下载完成后通过 autoUpdater.quitAndInstall(true, true) 强制关闭应用并安装,两个参数分别表示:是否强制关闭窗口(即使有未保存的工作)和是否以静默模式安装。
重要提示:代码签名
在 macOS 上,自动更新能正常工作的前提是应用已被签名且对应的证书有效,否则系统可能会阻止安装。Windows 上也建议对安装包进行代码签名,以避免 SmartScreen 的警告。签名配置请参考 electron-builder 的 win.certificateFile 和 mac.identity 选项。
17.3.4 手动实现更新方案(可选)
如果你不想依赖 electron-updater(比如需要对接公司内部的私有更新逻辑),也可以手动实现全量更新。基本流程是:
- 维护一个远程版本文件(JSON),包含
version、url、size、hash等字段。 - 应用启动或定时请求该文件,与本地
app.getVersion()比较。 - 如果有新版本,使用 Electron 自带的
net模块或 Node.js 的https下载安装包到临时目录。 - 校验哈希,然后使用
shell.openPath(Windows 执行 exe,macOS 打开 dmg,Linux 执行安装命令)触发安装。
手动实现的优势是完全可控,但需要自己处理断点续传、平台差异、静默安装等细节,工作量较大。对于大多数项目来说,electron-updater 是更务实的选择。
全量更新方案是保证桌面应用持续交付的基石。配合 electron-updater,你只需要配置一个静态服务器,就能让所有用户无缝升级到最新版本,极大减少了因为旧版本遗留问题而产生的用户投诉。在下一节,我们将讨论如何在此基础上加入灰度发布和增量更新的策略,进一步优化更新体验。