首页 / Electron 入门教程 / 自动更新详解:检查、下载与安装

Electron 入门教程

自动更新详解:检查、下载与安装

本教程共 45 篇 · 第 30 篇 · 更新于 2026-08-03

ElectronautoUpdater更新事件electron-updater代码签名

30. 自动更新详解:检查、下载与安装

本节目标

  • 掌握 setFeedURLcheckForUpdates 的配置与调用。
  • 理解 update-availableupdate-downloaded 等关键事件。
  • quitAndInstall 完成安装并处理好退出时机。
  • 了解 electron-updater 这套第三方思路的差异。
  • 明确代码签名、首次启动锁等上线注意事项。

1-1 设置更新源

使用内置 autoUpdater 的第一步,是告诉它去哪里找更新。通过 autoUpdater.setFeedURL(options) 设置更新服务器地址。

options 里最重要的是 url(feed 地址)。macOS 还可传 headers(HTTP 请求头,常用于鉴权)和 serverType(json 或 default)。Windows 的 MSIX 包支持 allowAnyVersion,允许降级到更老版本。

// 主进程 main.js
const { autoUpdater } = require('electron/main')

autoUpdater.setFeedURL({
  url: 'https://update.electronjs.org/your-name/your-app/darwin/v1.0.0'
})

对于开源且用 GitHub Releases 发布的应用,官方维护的 update-electron-app 模块能一行完成配置:它会根据 package.json 里的 repository 字段自动拼出 feed。

// 主进程 main.js
require('update-electron-app')()

这一行等价于手动 setFeedURL + 绑定所有事件。若你的应用符合「开源、公开仓库、GitHub Releases、已签名」的条件,这是最省事的方案。

1-2 触发检查

设置好 feed 后,调用 autoUpdater.checkForUpdates() 主动询问服务器。它会发出 checking-for-update 事件表示开始检查。

注意一个坑:checkForUpdates() 必须先于 setFeedURL 之后调用,否则会找不到地址。而且调用两次会下载两次更新,不要在定时器里重复无脑调用。

// 主进程 main.js
autoUpdater.on('checking-for-update', () => {
  console.log('正在检查更新…')
})

autoUpdater.checkForUpdates()

常见做法是:应用启动几秒后检查一次;之后每隔一段时间(如每小时)再检查。不要在 Squirrel.Windows 首次启动的锁期间立即检查。

1-3 关键事件:有无更新

检查完成后,会落在两个互斥事件之一:update-available 表示有新版本,update-not-available 表示已经是最新。

update-available 触发时,下载会自动开始,你不需要再手动调用下载方法。下面的代码演示监听这两个事件并更新 UI 提示。

// 主进程 main.js
autoUpdater.on('update-available', (info) => {
  console.log('发现新版本:', info.version)
  // 可在渲染进程通知用户「正在下载」
})

autoUpdater.on('update-not-available', (info) => {
  console.log('已是最新:', info.version)
})

error 事件在更新过程中出问题时触发,务必监听它,否则下载失败会悄无声息。错误可能来自网络、签名不匹配或 feed 格式错误。

// 主进程 main.js
autoUpdater.on('error', (err) => {
  console.error('更新出错:', err)
})

1-4 下载完成与安装

下载结束后触发 update-downloaded 事件。它的回调里带 releaseNotesreleaseNamereleaseDateupdateURL 等元信息,可用来展示更新日志。

此时你有两种选择:一是直接调用 autoUpdater.quitAndInstall() 立即重启安装;二是先提示用户,等其确认后再重启。即便什么都不做,已下载的更新也会在下次正常启动时自动应用。

// 主进程 main.js
autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName, releaseDate, updateURL) => {
  console.log('更新已下载:', releaseName)

  // 提示用户后安装(这里简化为直接安装)
  autoUpdater.quitAndInstall()
})

关于退出时机,before-quit-for-update 事件在 quitAndInstall() 被调用后、窗口关闭前发出。它和普通的 before-quit 不同:调用更新安装时不会先发 before-quit,所以想在做更新前清理资源,应监听这个专用事件。

1-5 把更新状态告诉渲染进程

主进程拿到更新状态后,通常通过 IPC 推给渲染进程,让界面显示进度或弹窗。继续沿用本教程的安全范式:ipcMain 发事件,contextBridge 暴露监听方法。

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

function broadcast(channel, data) {
  for (const win of BrowserWindow.getAllWindows()) {
    win.webContents.send(channel, data)
  }
}

autoUpdater.on('update-available', () => broadcast('update:available'))
autoUpdater.on('update-downloaded', () => broadcast('update:downloaded'))
// 预加载脚本 preload.js
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('updater', {
  onAvailable: (cb) => ipcRenderer.on('update:available', () => cb()),
  onDownloaded: (cb) => ipcRenderer.on('update:downloaded', () => cb())
})
// 渲染进程 renderer.js
window.updater.onDownloaded(() => {
  if (confirm('新版本已下载,现在重启更新?')) {
    // 通过 IPC 让主进程调用 quitAndInstall
  }
})

1-6 electron-updater 思路对比

除了内置 autoUpdater,社区里最常见的第三方方案是 electron-updater(由 electron-builder 生态提供)。它的思路和内置模块不同:内置模块绑定 Squirrel,而 electron-updater 用一套自己的下载与校验逻辑,支持更多更新源(GitHub、S3、通用 HTTP 等),配置也更灵活。

它的典型用法是在主进程里:

// 主进程 main.js(使用 electron-updater,第三方方案)
const { autoUpdater } = require('electron-updater')

autoUpdater.checkForUpdatesAndNotify()

需要明确:本章主线仍是 Electron 内置 autoUpdater + update.electronjs.org,这是官方文档推荐的最小依赖路径。若你的发布场景更复杂(私有服务器、多平台统一方案、需要增量更新),可以研究 electron-updater,但它属于 electron-builder 生态,与本书「打包主线用 Electron Forge」并不冲突——两者只在更新这一环可替换。

1-7 上线注意事项

代码签名是自动更新的地基。macOS 上 Squirrel.Mac 要求应用必须签名,未签名不仅无法自动更新,系统也会拦截启动。Windows 上建议对安装包签名,减少 SmartScreen 拦截。

首次启动锁要规避。Windows 的 Squirrel.Windows 安装后会有短暂文件锁,头几秒 checkForUpdates() 会失败。做法是检测到 --squirrel-firstrun 参数时跳过检查,或给检查加超时重试。

feed 与版本号要对齐。更新源的版本号通常取自 package.jsonversion,发布时务必先升版本再打包,否则服务器会认为「已是最新」而拒绝下发。

Linux 不在内置 autoUpdater 支持范围。需要走系统包管理器,或自行提供更新机制,发布策略里要单独规划。

1-8 检查时机与用户引导

更新体验的好坏,很大程度取决于「何时检查、如何提示」。常见的节奏是:应用启动后延迟几秒检查一次,避免和启动逻辑抢占资源;之后每隔一小时再查,保证长时间运行也能收到更新。

提示文案要准确。仅下载中时写「正在下载更新」,下载完成后写「新版本已就绪,重启后生效」,不要含糊地统称「更新中」。用户点确认后再 quitAndInstall(),比强制重启更友好。

// 主进程 main.js
setTimeout(() => {
  autoUpdater.checkForUpdates()
}, 5000)

setInterval(() => {
  autoUpdater.checkForUpdates()
}, 60 * 60 * 1000)

需要再次提醒:Windows 的 Squirrel.Windows 在首次运行带 --squirrel-firstrun 期间有文件锁,此时检查会失败。可在启动参数里识别该标志,跳过首启检查,或给检查加重试,避免一启动就报「更新出错」。

开发阶段想验证更新流程,建议直接打一个更高版本的包做本地测试,而不是依赖线上 feed。把 setFeedURL 指向本地或测试服务器,用两个不同 version 的包互相更新,能更快发现签名、路径或事件绑定上的问题,也不会污染正式发布渠道。

常见误区

不要重复调用 checkForUpdates()。每次调用都会重新下载,定时器里应加去重或节流,避免用户带宽被反复占用。

不要忽略 error 事件。下载失败、签名不符都会从这里抛出,不监听就无从排错,用户也永远停在「检查中」。

不要把「下载完成」等同于「已安装」。update-downloaded 只是下载好了,必须 quitAndInstall() 或下次启动才会真正生效,UI 文案要表达准确。