Electron 更新方案浅析
在 Electron 应用的迭代过程中,版本更新是不可或缺的一环。如何在保证用户体验的前提下,实现稳定、高效、安全的更新机制,是每个 Electron 应用开发团队都需要解决的问题。本文将分享我们在实现 Electron 全量更新与热更新 过程中的技术方案、关键细节及经验总结。
一、设计目标
本次更新机制设计的目标主要包括:
- 实现热更新,且支持覆盖非 asar 部分的文件
- 支持后台下载,确保更新过程对用户无感或影响最小
- 全量更新等其他基础需求
通过以上目标,可以让用户在使用应用时获得更流畅的体验,避免频繁重启或等待更新安装的情况。
二、更新方案简述
2.1 全量更新
基于 electron-updater 实现,支持完整的应用版本更新,本质是下载安装包后进行安装操作。
2.2 热更新
基于文件替换机制实现:
- 签名处理:应用签名本身是对安装包的完整性验证,若直接对应用进行文件替换,本质上影响了签名验证,可能会导致应用打开失败(如 macOS),Windows 验证相对宽松,但本质上文件替换会导致签名失效。
- 热更新场景及方案:
-
- 依次更新:适用于部分游戏应用场景,下载多个热更包
-
- 差量更新:生成所有历史版本与最新版本的差量包,根据当前版本选择对应的热更包进行更新
-
- 降级处理:退化至全量更新,认知成本较低
- 技术选型:原设计基于
electron-asar-hot-updater,原理也是文件替换,但仅支持 asar 文件,且请求更新信息时仅支持POST请求,不利于 CDN 式响应(原方案在本地启动了 Node 服务进行转发)。
三、全量更新
3.1 版本检测
当应用启动或用户手动触发更新时,electron-updater 会执行:
autoUpdater.checkForUpdates() 其内部会访问配置文件中的更新 URL(例如来自 package.json 的 publish 字段):
"publish": [{
"provider": "generic",
"url": "https://update.example.com/releases/"
}]
服务端需返回一个 YAML 格式的最新版本信息文件(通常名为 latest.yml 或 latest-mac.yml),其内容示例:
version: 2.27.0
files:
- url: peanut_test_CUCU_2.27.0_202510091527.exe
sha512: 23i2/6XRpJG5DIEzlaz+LEQR2NhTYASri0ob1O/6VZURX3BGo0jZLMh4n33Be4u1ZV8+EcugIVuGlzkcLrHChw==
size: 201224256
path: peanut_test_CUCU_2.27.0_202510091527.exe
sha512: 23i2/6XRpJG5DIEzlaz+LEQR2NhTYASri0ob1O/6VZURX3BGo0jZLMh4n33Be4u1ZV8+EcugIVuGlzkcLrHChw==
releaseDate: '2025-10-09T07:28:53.684Z'
electron-updater 会读取当前版本号 (app.getVersion()) 与该文件的 version 字段对比:
- 若版本号不同(且服务端版本更高),则触发下载
- 若版本号相同但配置中启用强制更新,则也可下载
- 若允许
downgrade,且版本号低于当前版本号,则也可以下载
3.2 更新包下载
autoUpdater.downloadUpdate() 触发下载,UI 层监听 download-progress 事件实现进度更新。
文件缓存在 appdata/local 文件夹下,支持文件完整性校验及断点续传。
3.3 安装与重启
下载完成后,autoUpdater.quitAndInstall() 触发安装。
注意:autoInstallOnAppQuit 此配置默认为 true,若存在已下载未安装的更新包,会在退出应用时自动更新。
四、热更新
4.1 版本检测
当存在热更新时,updater 模块会请求 CDN 中的更新配置,获取详细的更新信息,其内容示例:
{
"versionCode": 22814,
"minimumVersionCode": 22813,
"file": {
"name": "resources.zip",
"url": "http://192.168.91.87:8080/resources.zip",
"targetPath": "./resources",
"md5": "487f7b22f68312d2c1bbc93b1aea445b",
"size": 190971754
},
"fullFile": {
"name": "resources.zip",
"url": "http://192.168.91.87:8080/resources.zip",
"targetPath": "./resources",
"md5": "487f7b22f68312d2c1bbc93b1aea445b",
"size": 190971754
}
}
versionCode为热更版本号
minimumVersionCode为热更最低版本限制
上述版本号会跟当前版本进行对比:
- 当
versionCode大于当前版本号,则存在有效更新
- 当
minimumVersionCode大于当前版本号,则说明本地存在部分内容未更新的情况,强制回退至全量版本热更(建议是 resources 下所有文件)
4.2 热更包下载
下载更新 zip 包至缓存目录 hot-update,根据热更信息中文件 md5 值进行文件完整性校验。此处下载不进行解压缩操作,防止出现可能的文件篡改/丢失导致热更失败且不能回退的情况。
4.3 安装与重启
此方案基于文件替换,不同环境文件操作有所区别:
- 解压缩:将热更包解压缩
- 文件替换:
-
- 若是 macOS 环境,则直接
renameSync或者复制后删除
- 若是 macOS 环境,则直接
-
- 若是 Windows 环境,由于文件可能被应用占用,需要关闭应用后使用第三方程序进行移动
- 文件合并:主进程使用
spawn启动updater.exe,updater.exe会在启动五秒后进行文件合并操作,将热更文件夹与目标文件夹进行覆盖式合并:
-
- 若此前不存在,则新增
-
- 若此前存在,则覆盖
-
- 不支持对文件进行删除操作
4.4 注意事项
- asar 文件处理:asar 文件下载/解压时先命名为
.tmp,再重命名,否则会报错
- 文件占用机制:Windows 文件占用机制与 macOS 不同,需要特殊处理
- 残留进程:如
app.quit被阻断,导致进程未正确关闭,可以使用process.exit(0)。当前使用的是等待 5s 方案
4.5 热更新-差分更新
electron-updater本身也实现了热更新。原理是基于 blockmap 文件进行差量对比。相当于将整个 exe 文件划分成 N 等分,根据新旧版本的 blockmap 对比结果,找出需要更新的分片然后下载。全部分片下载完成后组装成新的完整的 exe 安装包,再进行应用安装。
区别于 文件替换,此方案由 electron-updater 支持,仅需 publish 端保存新旧版本 blockmap 文件,且支持差分下载(CDN 或者 OSS 配置支持)即可。
相对于全量下载,下载量大大减少,基本为全量的 15%-35%,适合 resources 文件夹,尤其是 asar 文件夹较大的场景。
五、业务使用流程
- 检测更新信息:业务检测更新信息
- 强制更新判断:存在强更或者最低版本,则直接触发强制更新
- 后台下载:存在非强更则触发后台下载
- 用户手动更新:当用户手动更新时,会处理后台下载的进度更新事件,要么提示更新完成待安装,要么提示更新中,正确显示更新进度
- 热更新处理:若触发热更,且低于最低热更版本则触发全量热更