Electron 桌面应用自动更新,核心不是“写一段下载代码”,而是把版本来源、包体元数据、下载与校验、安装时机、失败回退连成一条可维护的链路。通常建议先明确你的分发渠道(自有服务器、对象存储、GitHub Releases 或企业内网),再决定是用社区常见的 autoUpdater 类方案,还是自己写主进程下载逻辑配合安装器。不同方案对签名、平台差异和权限的要求差别很大,先确认环境再动手,比先抄代码更重要。
Electron 自动更新的可行路径是:主进程定时拉取版本清单,比对本地版本后下载差量或全量包,校验完整性并在退出或重启时安装。适用场景是你能控制发布端且安装包具备签名条件;需要确认三件事:更新源可访问、包体能被校验、失败时能回退到旧版本。不具备签名或无法保证更新源稳定时,建议先做“提示有新版本+跳转下载页”的轻量方案,而不是强推静默更新。
先确认当前场景和目标
自动更新是否值得做,取决于更新频率和用户规模。如果应用只在少数内网机器上运行、每次发版都能人工安装,那么做完整自动更新的维护成本可能高于收益;如果用户分散、发版频繁、旧版本造成的兼容问题多,自动更新才有明确价值。开始前需要确认以下信息:
- 分发渠道:更新包放在哪里,是否支持 HTTPS 和稳定的文件命名,是否允许携带版本清单文件。
- 目标平台:Windows、macOS、Linux 的安装方式和权限模型不同,macOS 通常要求应用签名,Windows 安装器类型也会影响静默安装能否成功。
- 发布流程:谁来生成安装包、谁负责上传、版本号从哪里读取,版本号规则必须唯一且单调递增。
- 回退能力:旧版本安装包是否保留,用户更新失败后能否重新安装旧版。
- 灰度与强制更新:是否需要按用户分组控制更新范围,是否存在必须强制升级的最低版本。
判断条件可以简化成一句:如果你能稳定产出一个“版本号+安装包+校验值”的清单,并且用户机器有权限执行安装,那么自动更新可以落地;否则先把发布流程理顺。
按这个顺序处理
第一步,确定版本清单的格式和托管位置。清单是更新链路的事实来源,建议用一个 JSON 文件描述最新版本、各平台安装包地址和校验值。示例片段如下,字段名和值需要替换成你自己的实际内容:
{
"version": "1.4.0",
"notes": "修复若干问题",
"platforms": {
"win32": {
"url": "https://your-domain.example/app/MyApp-1.4.0-setup.exe",
"sha256": "替换为真实校验值",
"minVersion": "1.2.0"
},
"darwin": {
"url": "https://your-domain.example/app/MyApp-1.4.0.dmg",
"sha256": "替换为真实校验值",
"minVersion": "1.2.0"
}
}
}这份清单建议放在能被应用读取的静态地址上,发布时由构建脚本生成,避免手工填写出错。minVersion 表示低于该版本必须先升级,可用于处理不兼容变更。
第二步,在主进程里实现检查逻辑。不要把更新检查放在渲染进程,渲染进程没有文件系统权限,也容易受页面生命周期影响。一个通用的主进程骨架如下,重点是版本比对、下载、校验三步分开,任一步失败都不进入安装:
const { app, dialog } = require('electron');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const https = require('https');
const MANIFEST_URL = 'https://your-domain.example/app/latest.json';
function compareVersion(a, b) {
const pa = a.split('.').map(Number);
const pb = b.split('.').map(Number);
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
const x = pa[i] || 0;
const y = pb[i] || 0;
if (x !== y) return x > y ? 1 : -1;
}
return 0;
}
async function checkForUpdate(platformKey) {
const manifest = await fetchJson(MANIFEST_URL);
if (compareVersion(manifest.version, app.getVersion()) <= 0) return null;
const entry = manifest.platforms[platformKey];
if (!entry) return null;
return entry;
}
function sha256File(filePath) {
return new Promise((resolve, reject) => {
const hash = crypto.createHash('sha256');
const stream = fs.createReadStream(filePath);
stream.on('data', chunk => hash.update(chunk));
stream.on('error', reject);
stream.on('end', () => resolve(hash.digest('hex')));
});
}
async function downloadAndVerify(url, expectedSha, destPath) {
await downloadTo(url, destPath);
const actual = await sha256File(destPath);
if (actual !== expectedSha) {
fs.unlinkSync(destPath);
throw new Error('checksum mismatch');
}
}
app.whenReady().then(async () => {
const update = await checkForUpdate(process.platform);
if (!update) return;
const dest = path.join(app.getPath('temp'), path.basename(update.url));
await downloadAndVerify(update.url, update.sha256, dest);
// 此处再根据平台调用对应安装方式,或提示用户重启安装
});代码里的 fetchJson 和 downloadTo 需要你自己按网络库补齐。关键是校验必须在安装之前完成,校验不通过就删除文件并记录日志,不要继续弹出“更新失败”后还保留半包。
第三步,处理安装时机。Windows 的安装包通常在下载完成后启动安装器并退出当前进程;macOS 的 dmg 不适合直接静默覆盖,需要结合签名和安装辅助工具确认可行性。如果暂时无法做静默安装,稳妥做法是下载并校验成功后提示用户“重启并安装”,由用户主动确认,避免应用被强制关闭导致数据丢失。

第四步,给检查加上节流和开关。应用启动时检查一次、之后按固定间隔检查即可,不要在每次窗口聚焦时都请求清单。建议在配置中保留一个关闭更新的开关,方便内网部署或排查问题时停用。
改完后怎么验证
验证要覆盖“无更新、有新版本、下载失败、校验失败、安装成功”五种路径。可以先在本机用两个版本号构造测试清单:把清单里的 version 写成等于当前版本,确认应用不会提示更新;再把 version 提高一档,观察是否进入下载流程。验证动作和预期信号包括:
- 清单请求:观察主进程日志是否发起请求、HTTP 状态是否成功、解析出的版本号是否与预期一致。
- 版本比对:把本地版本设为高于清单版本,确认应用不下载任何文件,说明比对方向没有写反。
- 校验环节:故意把清单里的 sha256 改成错误值,确认下载的文件被删除且没有进入安装步骤,日志中应出现校验不通过记录。
- 安装时机:确认安装触发时应用当前状态是否符合预期,是否有未保存的数据提示,是否存在重复启动安装器的情况。
- 回退:用旧版本安装包重装一次,确认应用仍可启动,说明旧版本没有被发布流程删除。
如果条件允许,在一台干净的测试机上完整走一遍从旧版到新版的流程,比只在开发机上验证更有意义,因为权限、路径和签名问题往往只在干净环境里暴露。
容易忽略的边界
第一,签名与系统策略。macOS 对未签名或签名不一致的应用限制较多,Windows 的 SmartScreen 也可能拦截未知来源安装包。签名配置不完整时,自动更新可能在下载成功后被系统阻止,这类情况需要先确认签名链路再决定是否推进自动更新。
第二,更新源与网络环境。企业内网机器可能无法访问公网更新源,建议为更新地址提供可配置项,或者在部署时替换成内网镜像地址。更新源不稳定时,应用需要能容忍请求超时并降级为“下次再检查”,而不是反复弹窗。
第三,版本号与回滚。自动更新默认只升不降,如果新版本出现严重问题,需要人工发布更高版本号来覆盖,不能指望用户自动回退。因此发布前保留上一版安装包,并在清单中保留 minVersion 语义,是成本较低的保护措施。
第四,不适用条件。如果应用运行在无安装权限的受限账户下,或者安装包依赖的运行时环境无法自动替换,自动更新可能无法完成,此时建议回退为“检查更新+引导用户手动下载安装”的方案,而不是强行静默更新。