人人都会AI编程

17.2 内置 autoUpdater 模块用法与局限

更新时间:2026-07-11

Electron 提供了一个内置的 autoUpdater 模块,让你能够实现桌面应用的自动更新。它的底层封装了 macOS 的 Squirrel.Mac 和 Windows 的 Squirrel.Windows 更新框架,通过一套统一的 JavaScript API 为应用提供“检测新版本→下载→安装”的能力。本节将深入它的用法,同时真实还原它在生产环境中的若干硬性限制。

17.2.1 基本工作原理

autoUpdater 的工作流程可以概括为四步:

  1. 配置更新源(Feed URL):告诉 Electron 去哪里查询新版本信息。
  2. 检查更新:调用 API 去服务器拉取一个描述最新版本的文件(macOS 为 JSON,Windows 为 RELEASES 文件)。
  3. 下载更新:如果发现新版本,自动下载安装包。
  4. 应用更新:下载完成后,触发重启安装逻辑。

整个过程由一系列事件驱动,你只需要在主进程中监听事件,然后向渲染进程反馈状态,即可构建出流畅的用户提示体验。

17.2.2 必须满足的前置条件

在你开始写代码之前,有两个硬性要求必须满足,否则 autoUpdater 根本无法工作:

  • 代码签名

macOS:应用必须使用 Apple Developer ID 签名,否则 Squirrel.Mac 会在验证更新包时失败。
Windows:安装程序(.exe)必须具备有效的 Authenticode 数字签名,否则 Squirrel.Windows 会拒绝更新。

  • 更新服务器

你需要一个能够响应更新请求的 HTTP(S) 服务器。macOS 端需要提供更新信息的 JSON 文件,Windows 端需要提供 RELEASES 文件及 .nupkg 包(或对应的 .exe 安装文件)。通常这些文件会在打包阶段由工具自动生成,但你仍需将它们部署到线上。

如果你是用 electron-builder 打包,可以在配置中指定 publish 字段,electron-builder 会自动生成符合 Squirrel 规范的更新文件和安装包。但 autoUpdater 本身并不关心服务器是如何搭建的,它只对 feed URL 做 HTTP 请求。

17.2.3 基础用法示例

以下是一个完整的、可以直接用于主进程的配置片段,演示了如何在 macOS 和 Windows 上启用自动更新。

// main.js(主进程)
const { app, autoUpdater, dialog, BrowserWindow } = require('electron');

// 根据平台设置不同的更新源
const server = 'https://my-app-updates.example.com';
const feedURL = `${server}/update/${process.platform}/${app.getVersion()}`;

autoUpdater.setFeedURL({ url: feedURL });

// 每隔一段时间自动检查更新(也可在渲染进程手动触发)
app.whenReady().then(() => {
  autoUpdater.checkForUpdates();
  setInterval(() => {
    autoUpdater.checkForUpdates();
  }, 60 * 60 * 1000); // 每小时检查一次
});

// 事件监听
autoUpdater.on('checking-for-update', () => {
  console.log('正在检查更新...');
  // 可以发送到渲染进程显示状态
});

autoUpdater.on('update-available', (info) => {
  console.log('发现新版本', info.version);
  // 可选:通知用户有更新可用
});

autoUpdater.on('update-not-available', (info) => {
  console.log('当前已是最新版本');
});

autoUpdater.on('error', (err) => {
  console.error('更新出错', err);
  // 在渲染进程提示用户检查失败
});

autoUpdater.on('download-progress', (progressObj) => {
  let logMessage = `下载速度: ${progressObj.bytesPerSecond}`;
  logMessage += ` - 已下载 ${progressObj.percent}%`;
  logMessage += ` (${progressObj.transferred}/${progressObj.total})`;
  console.log(logMessage);
  // 将进度发送给渲染进程,可展示进度条
});

autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName) => {
  const dialogOpts = {
    type: 'info',
    buttons: ['重启应用', '稍后再说'],
    title: '应用更新',
    message: process.platform === 'win32' ? releaseNotes : releaseName,
    detail: '新版本已下载完成,是否立即重启以应用更新?',
  };
  dialog.showMessageBox(dialogOpts).then((returnValue) => {
    if (returnValue.response === 0) {
      autoUpdater.quitAndInstall();
    }
  });
});

几点说明:

  • setFeedURL 的参数是一个对象,url 属性即为更新服务器的地址。macOS 会拼接 url/appcast.xml 或自定义的 JSON 路径,Windows 则直接从该 URL 读取 RELEASES 文件。实际使用中更推荐分别设置,例如 macOS 直接指向完整的 JSON 文件地址,Windows 指向包含 RELEASES 文件的目录。
  • checkForUpdates 可以自动触发,也可以由渲染进程通过 IPC 调用主进程方法来完成手动检查。建议在应用空闲时自动检查,避免启动高峰阻塞。
  • update-downloaded 事件是唯一可以安全提示用户重启的时机。下载完成后,调用 autoUpdater.quitAndInstall() 即可重启应用并安装新版。
  • download-progress 可用来实现进度条,提升用户体验。

如果结合 preload 脚本和 IPC,可以把这些状态通过渲染进程的用户界面展示出来:

// preload.js 示例
contextBridge.exposeInMainWorld('updaterAPI', {
  onStatus: (callback) => ipcRenderer.on('update-status', (event, status) => callback(status)),
  checkNow: () => ipcRenderer.send('check-update'),
});
// 主进程中将事件转发
autoUpdater.on('checking-for-update', () => {
  mainWindow.webContents.send('update-status', 'checking');
});

17.2.4 内置模块的真实局限

尽管 autoUpdater 看起来提供了一个标准的更新能力,但在实际项目中,你会很快撞上它的边界。这些局限并非设计缺陷,而是由于底层 Squirrel 框架的固有特性和 Electron 团队的保守策略。

1. 仅支持 Squirrel 更新机制

autoUpdater 硬绑定了 Squirrel.Mac 和 Squirrel.Windows,这意味着你无法使用自定义的更新服务(例如直接下载 .zip 解压替换,或使用 electron-updater 的 NSIS 差分更新等)。如果你的应用是通过 .pkg 分发,或者想用增量更新,那么内置模块完全帮不上忙。

2. 平台支持不完整(无 Linux)

autoUpdater 在 Linux 上根本不可用,接口虽然存在但会直接抛出错误。如果你想覆盖 Linux 平台,必须寻找第三方方案或者自己实现一套基于 appimage-updater 或原生包管理器的更新逻辑。

3. 强依赖代码签名

macOS 上必须使用 Apple Developer ID 签名,否则 Squirrel.Mac 会因无法验证包完整性而报错。同样,Windows 也需要 Authenticode 签名。开发环境下几乎无法测试更新流程,因为开发版本很少有正式的代码签名,这导致调试极其麻烦。你往往需要搭建一套 staging 签名流程才能完整验证。

4. 更新包格式受限

  • macOS:只接受 .zip 格式的更新包(Squirrel.Mac 的 .app 变更基于 .zip 差分)。如果你用 .dmg 分发,则需要额外的服务器配置来返回正确的 JSON,并确保内容格式匹配。
  • Windows:需要 .nupkg 文件(NuGet 包)以及 RELEASES 元文件。这意味着你的 Electron 应用必须被打包成 Squirrel.Windows 的安装程序结构(也就是 electron-buildernsissquirrel 目标),不能是一个普通的绿色版 exe

5. 无法暂停/恢复下载,控制粒度粗

autoUpdater 不提供暂停下载或恢复下载的 API。一旦开始下载,要么完全完成,要么出错终止。进度反馈只能通过 download-progress 事件获取百分比,无法断点续传。对于在公网环境下更新大体积应用的用户,体验不佳。

6. 服务器配置复杂且文档缺失

更新服务器上需要放置特定的元数据文件,这些文件的生成通常依赖打包工具(如 electron-builderpublish 配置)。但如果你需要自建服务器,就必须深入了解 Squirrel.Mac 的 JSON 格式或 Squirrel.Windows 的 RELEASES 文件规范。Electron 官方文档对这一部分着墨甚少,开发者往往需要反复试错。

7. 不支持多通道更新(Staging / Beta)

原生的 autoUpdater 没有内置“通道”概念(如 stable、beta、alpha)。虽然你可以通过改变 feed URL 手动切换,但远不如第三方库(如 electron-updater)提供的 provider 机制灵活,后者可以直接对接 GitHub Releases、S3 等,天然支持版本通道。

17.2.5 内置模块适用场景总结

考虑到上述限制,autoUpdater 的内置模块更适用于以下情况:

  • 你的应用已严格遵循 Squirrel 分发规范(macOS 签名 + Windows 安装包)。
  • 你不介意花时间自行搭建更新服务器,并愿意维护元数据文件。
  • 你只需要 macOS 和 Windows 两个平台,Linux 用其他方案或根本不考虑。

如果你的需求超出了这个范围,比如需要 GitHub 发布更新、需要增量更新、或者要在 Linux 上提供自动更新,那么下一节将要介绍的 electron-updater(electron-builder 提供的第三方库)会是更务实的选择。它几乎已成为社区的事实标准,解决了内置模块的大部分痛点。

在真实的商业项目中,很少有团队直接裸用 autoUpdater。更多时候,他们要么在它的基础上封装一层来处理平台差异,要么直接转向更成熟的 electron-updater。但作为一个内置模块,理解它的运行机制有助于你更好地把握 Electron 更新的底层逻辑,也为评估第三方库的改进提供了参照系。