Electron 自动更新 - 全量更新

线上客户端版本需要更新一般有两种方式 全量更新增量更新

当前为全量更新:

  • 更新流程:应用内通知、下载后(打包后的.exe文件或者.zip),唤起安装过程重新安装覆盖之前的版本
  • 适用场景:重大 BUG 的修复、大的改版。让你 「 无法保持情绪稳定 」 的更新
  • 当应用代码改动较大时,比如 Electron 的版本升级、项目架构调整等,我们就可能需要用户下载全量的升级包来升级。Electron 官方提供了多种应用更新方案主要包括使用 Electron 团队维护的 update.electron.org 实现自动更新,以及 electron-builder 打包方案。
  • Electron 应用的自动更新推荐使用 electron-builder 中的 AutoUpdate 功能。
  • 在打包配置文件中,需要配置 publish 选项,指定 providerurl,其中 url 是存放升级更新包的服务器。
  // @see https://www.electron.build/configuration/configuration
  {    "appId": "com.test.app",    "asar": true,    "directories": {      "output": "dist/",    },    "mac": {      "target": ["dmg", "zip"]    },    "win": {      "target": [        {          "target": "nsis",          "arch": ["x64"],        },      ],    },    "publish": {      "provider": "generic",      "url": "https://www.test.com/download/", // 资源服务器      "channel": "latest",    },  }
  • 打包完成后,我们将打包目录下生成的latest.ymlapp-0.0.2.exe放到资源服务器,给应用提供下载。
  ├── dist  ├── win-unpacked  ├── app-0.0.2.exe  ├── app-0.0.2.exe.blockmap  ├── builder-effective-config.yaml  ├── latest.yml
  • 更新步骤:
    1. 客户端通过定时检测、或者服务端推送方式检测是否有更新
    2. 执行 autoUpdater.checkForUpdates() 的检测逻辑,读取资源服务器 latest.yml 文件,对比文件摘要
    3. 有更新则执行文件下载操作,可以配合显示下载进度
    4. 下载完成之后,通知渲染进程页面显示本次更新的相关内容
    5. 应用重启进行更新
  • 主进程代码
  import { app, BrowserWindow, shell, ipcMain, session, Menu, Tray, safeStorage } from 'electron'  import { autoUpdater } from 'electron-updater'    // 执行自动更新检查  ipcMain.on('checkForUpdate', () => {    isRobot = false    autoUpdater.checkForUpdates()  })  // 主进程推送消息到渲染进程  function sendUpdateMessage(obj: any) {    win?.webContents.send('updateMessage', obj)  }    // 执行下载  ipcMain.on('downloadUpdate', () => {    autoUpdater.downloadUpdate()  })  // 是否自动下载更新,设置为 false 时将通过 API 触发更新下载  autoUpdater.autoDownload = false;  // 是否允许版本降级,也就是服务器版本低于本地版本时,依旧以服务器版本为主  autoUpdater.allowDowngrade = true;  // 更新错误  autoUpdater.on('error', function (err) {    sendUpdateMessage({ action: 'update-error', errorInfo: err })  })  // 检查中  autoUpdater.on('checking-for-update', function () {    sendUpdateMessage({ action: 'checking' })  })  // 发现新版本,通知渲染进程吊起确认下载更新按钮  autoUpdater.on('update-available', function (info) {    sendUpdateMessage({ action: 'updateAva', updateInfo: info })  })  // 当前版本为最新版本  autoUpdater.on('update-not-available', function (info) {    setTimeout(function () {      // 项目中做了增量更新,所以加了增量更新逻辑      //hotUpdate() // 增量更新检查    }, 1000)  })  // 更新下载进度事件  autoUpdater.on('download-progress', function (progressObj) {    console.log('触发下载。。。')    console.log(progressObj)    win?.webContents.send('downloadProgress', progressObj)  })  // 安装包下载完成  autoUpdater.on('update-downloaded', function () {    // 安装包下载进度    win?.webContents.send('downloadProgress', { percent: 100 })    // ipcMain.on('isUpdateNow', (e, arg) => {    // 可以手动选择是否立即退出并更新    ipcMain.on('isUpdateNow', (e, arg) => {      // some code here to handle event      autoUpdater.quitAndInstall()    })  })
  • 渲染进程
  import { ipcRenderer } from 'electron'  // 添加自动更新事件的监听  ipcRenderer.on('updateMessage', (event, obj) => {    if (obj.action === 'updateAva') {      // 发现新版本    } else if (obj.action === 'update-error') {      // 更新错误    } else if (obj.action === 'updateNotAva') {      // 没有新版本    } else {    }  })
  • 要使上面流程能正确地执行下去,还需要提供一个正确的服务返回一个正确的更新配置:
  • electron-updater 将会请求该链接的服务地址,这个地址需要返回一个更新配置信息文件,这个文件就是 electron-builder 打包出来的 YML 文件。
  • 需要注意下面几点:
  1. electron-updater 会校验配置中 version 的格式,需要符合为 semver version 规范,但是一般 Windows 应用是四位版本号,所以采用像 *.*.*-* 这种形式能通过检验
  2. electron-updater 会校验配置中的 sha512 值与更新下载下来的文件的 sha512 值,不匹配会抛出更新错误,所以不能随意修改安装程序(只要文件 MD5 值不变即可)
  3. 配置中的 path 值即是 electron-updater 执行下载更新的目标地址,是新版本程序安装包的文件地址
  • 全量更新方案的优缺点:
    • 优点
      • 打包配置简单,只需添加 publish 即可
      • 代码逻辑简单,添加 autoUpdater 即可
    • 优点
      • 安装包体积过大时,浪费带宽,增加用户升级时间
      • 代码改动量小时,全量升级完全没有必要
      • 当我们的应用依赖一些第三方 SDK 时,当第三方 SDK 有打包问题时,可能会出现升级失败的情况