electron-builder+electron-updater实现应用自动更新过程

autoUpdater:使应用程序能够自动更新
ipcMain:用于从主进程到渲染进程的异步通信。
ipcRenderer:用于从渲染器进程到主进程的异步通信。
更多api在 electron官网(中文)

接上篇 electron将vue项目打包成桌面应用 继续介绍一下在electron-builder打包基础下怎么使用electron-updater实现应用自动监测版本以及更新的。主要包括:

  • electron应用自动更新、主线程与渲染线程之间通信
  • 本地临时服务器搭建
  • 过程中的常见问题
  • electron应用自动更新具体实现流程图
    npm install electron-updater --save
    

    2.在package.json文件增加 publish 配置,打包时可生成latest.yml,用于自动更新的配置信息latest.yml文件是打包过程生成的文件,为避免自动更新出错,打包后禁止对latest.yml文件做任何修改!
    publish中url是安装包和latest.yml的服务器地址。这里我是配置的在本地临时搭建的服务期地址,下面我会介绍。

    "build": {
        "appId": "com.electron.app",
        "productName": "Electron",
        "publish": [
            "provider": "generic",
            "url": "http://192.168.100.***:8000/"  //放置安装包和latest.yml的服务器地址
        "files": [
          "!dist/**/*"
        "mac": {
          "icon": "build/icon.png", // 应用程序图标
          "category": "public.app-category.productivity",
          "artifactName": "${productName}_${version}.${ext}", // 应用程序包名
          "target": [
            "dmg",
            "zip"
        "win": {
          "icon": "build/icon.png",
          "artifactName": "${productName}_${version}.${ext}",
          "verifyUpdateCodeSignature": false,
          "target": [
              "target": "nsis",
              "arch": [
                "ia32"
        "nsis": { 
          "oneClick": false, // 是否一键安装
          "createDesktopShortcut": "always", // 是否添加桌面快捷方式
          "allowToChangeInstallationDirectory": true,// 允许修改安装目录
        "extends": null
    

    build中可以适当增加nsis配置,可以优化用户体验,比如是否允许用户一键安装、自定义安装位置、是否添加桌面快捷方式、安装完成是否立即启动、配置安装图标等等。更多详细参数配置可参见官方文档 nsis配置

    3.在主进程main.js文件中引入 electron-updater,ipcMain添加自动更新检测、事件监听、

    const { app, BrowserWindow, ipcMain } = require('electron') // ipcMain 主线程
    const { autoUpdater } = require('electron-updater')
    const uploadUrl = 'http://192.168.100.***:8000/Desktop/download/' // 安装包helatest.yml所在服务器地址
    // 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
    function updateHandle () {
      let message = {
        error: {status: -1, msg: '检测更新查询异常'},
        checking: {status: 0, msg: '正在检查更新...'},
        updateAva: {status: 1, msg: '检测到新版本,正在下载,请稍后'},
        updateNotAva: {status: 2, msg: '您现在使用的版本为最新版本,无需更新!'},
    let versionInfo = ''
      autoUpdater.setFeedURL(uploadUrl)
    // 检测更新查询异常
      autoUpdater.on('error', function (error) {
        sendUpdateMessage(message.error)
    // 当开始检查更新的时候触发
      autoUpdater.on('checking-for-update', function () {
        sendUpdateMessage(message.checking)
    // 当发现有可用更新的时候触发,更新包下载会自动开始
      autoUpdater.on('update-available', function (info) {
        sendUpdateMessage(message.updateAva)
    // 当发现版本为最新版本触发
      autoUpdater.on('update-not-available', function (info) {
        sendUpdateMessage(message.updateNotAva)
      // 更新下载进度事件
      autoUpdater.on('download-progress', function (progressObj) {
        mainWindow.webContents.send('downloadProgress', progressObj)
     // 包下载成功时触发
      autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
     // 收到renderer进程确认更新
        ipcMain.on('updateNow', (e, arg) => {
          console.log('开始更新')
          autoUpdater.quitAndInstall() // 包下载完成后,重启当前的应用并且安装更新
     // 主进程向renderer进程发送是否确认更新
        mainWindow.webContents.send('isUpdateNow', versionInfo)
    ipcMain.on('checkForUpdate', () => {
        // 收到renderer进程的检查通知后,执行自动更新检查
        // autoUpdater.checkForUpdates()
        let checkInfo = autoUpdater.checkForUpdates()
        checkInfo.then(function (data) {
          versionInfo = data.versionInfo // 获取更新包版本等信息
    // 通过main进程发送事件给renderer进程,提示更新信息
    function sendUpdateMessage (text) {
      mainWindow.webContents.send('message', text)
    

    在主进程createWindow中需要调用一下updateHandle()

    function createWindow () {
      updateHandle()
    

    4.新建preload.js预处理文件,定义ipcRenderer,在main进程中添加preload配置项
    preload.js: preload环境可以使用Node API,又能访问DOM、BOM的特殊环境,即使在dom文档还未形成之前

    window.ipcRenderer = require('electron').ipcRenderer
    

    main.js // 注意这是主渲染进程不是vue的main入口文件

    const path = require('path')
    let windowConfig = {
      width: 1000,
      height: 800,
      webPreferences: {
        nodeIntegration: false, // 使用了预加载之后,即使nodeIntegration为false,也可以使用Node API访问到ipcRenderer
        preload: path.join(__dirname, 'preload.js'),
    

    5.在renderer进程引入ipcRenderer,触发自动更新,并添加自动更新事件的监听,监听从主进程传过来的更新事件
    我这里在app.vue里面进行监听:

    import isElectron from 'is-electron'
    mounted () {
        let vm = this
        if (isElectron()) {
          vm.ipcRenderer = window.ipcRenderer
          vm.ipcRenderer.on('message', (event, data) => {
            console.log('message', data.msg)
          vm.ipcRenderer.on('downloadProgress', (event, progressObj) => {
            console.log('downloadProgress', progressObj)
            // 可自定义下载渲染效果
          vm.ipcRenderer.on('isUpdateNow', (event, versionInfo) => {
              // 自定义选择效果,效果自行编写
            vm.confirm({
              title: '提示',
              content: '检测到新版本' + versionInfo.version + ',是否立即升级?',
              ok: '确定',
              cancel: '取消',
              onOk () {
                vm.ipcRenderer.send('updateNow')
              onCancel (tx) {
          vm.autoUpdate() // electron应用启动后主动触发检查更新函数
      beforeDestroy () {
        // 移除ipcRenderer所有事件
        if (isElectron()) {
          this.ipcRenderer.removeAllListeners()
      methods: {
        autoUpdate () { // 用来触发更新函数
          this.ipcRenderer.send('checkForUpdate')
    

    这里加了一个is-electron,来判断是否在electron应用环境下,避免本地运行报错
    添加依赖命令:npm install --save is-electron
    另外在组件销毁时要及时移除ipcRenderer上的事件,避免重复监听.

    执行electron-builder进行打包,
    windows下会生成安装包exe和latest.yml等文件,执行exe安装软件;
    Mac下会生成安装包dmg、zip和latest-mac.yml文件,执行dmg安装软件。
    Mac.png

    需要注意的一点是:mac上不签名也可以打包成功,安装的时候还要更改电脑权限,但是涉及到自动更新、发布到 app store等功能则不能用。所以说MAC包一定要添加代码签名,参考地址:code-signing

    先修改package.json中的version属性,先放一个高版本:修改 version: “1.7.0”
    执行electron-builder打包,将资源包 上传到main主进程中的设置的uploadUrl地址下
    Windows放置对应的exe、latest.yml文件
    MAC下放置对应的dmg、zip、latest-mac.yml文件
    再修改成低版本version: “1.0.0” 再次执行electron-builder打包,这里以windows为例(mac也是可以做到的,但是他需要代码签名才有效果),将低版本的exe程序安装并且运行之后,可以看到在应用启动后中触发更新检查,electron-updater自动会通过设置的uploadUrl下的.yml文件检查更新。效果如下:
    本地临时服务器搭建

    为了方便测试应用更新的效果,我使用python临时搭建了一个本地服务器作为应用资源的包的放置。(因为是本地服务器,监听不到下载进度,如需要看效果可以请在同一局域网的人帮忙测试一下即可)
    python下载:参考地址
    我是mac,本地是装的python是2.7版本,根据版本在终端输入:

    python2.x: python -m SimpleHTTPServer
    python3.x: python -m http.server
    默认端口号是8000,也可以自定义端口。比如1896
    python2.x: python -m SimpleHTTPServer 1896
    python3.x: python -m http.server 1896