electron-vue构建桌面客户端使用electron-updater实现在线更新

公司项目是使用elctron-vue构建的,之前一直是打包成一个绿色免安装版给用户使用的,也没有在线更新的功能,每次更新了新的版本用户可能都不知道。

为了提升用户体验,最近打算把在线更新这个功能解决了。

这两天研究了下,基本已经实现,现在对实现做一些总结:

现在实现了window端在线下载安装更新,Mac端由于没有证书。。目前是检测到有更新后,跳转到浏览器下载新的安装包。

使用electron-builder打包

在开始使用electron-vue构建项目的时候,记得选用electron-builder

electron-vue集成了两种打包方式:electron-packager和electron-builder

他们的区别是:(应该是这些区别吧)

  1. electron-packager打包成的是绿色安装包,没有实现自动更新功能;
  2. electron-builder打包好的是安装文件,配合插件实现了自动更新。

所以我们要实现自动更新,记得选用electron-builder打包的方式。

之前项目是使用的electron-packager构建方式,在改成electron-builder的没有成功。。。最后只有重新构建了项目,把现有的代码复制过去了(据同事说他弄成功了?????excuse me?!)

安装electron-builder模块

  1. 安装模块
npm install --save electron-builder
  1. 配置package.json

为了打包时生成latest.yml文件,需要在 build 参数中添加 publish 配置。

其他配置,请阅读官方文档

  "build": {
    "publish": [
      {
        "provider": "generic",
        "url": "http://**.**.**.**:3002/download/",//更新服务器地址,可为空
      }
    ],
    ...,
    "nsis":{
        
    }
  }
  

注意:配置了publish才会生成latest.yml(mac环境是生成的latest-mac.yml)文件,用于自动更新的配置信息;latest.yml文件是打包过程生成的文件,为避免自动更新出错,打包后禁止对latest.yml文件做任何修改。如果文件有误,必须重新打包获取新的latest.yml文件!!!

  1. 增加nsis配置(可省略)

nsis配置不会影响自动更新功能,但是可以优化用户体验,比如是否允许用户自定义安装位置、是否添加桌面快捷方式、安装完成是否立即启动、配置安装图标等。nsis 配置也是添加在 build 参数中。 详细参数配置可参见官方文档:nsis配置

    "nsis": {
      "oneClick": true,
      "perMachine": true,
      "allowElevation": true,
      "allowToChangeInstallationDirectory": true,
      "createDesktopShortcut": true,
      "runAfterFinish": true,
      "installerIcon": "./build/icon.ico",
      "uninstallerIcon": "./build/icon.ico"
    },

4.配置主进程main.js文件(或主进程main中的index.js文件),引入 electron-updater 文件,添加自动更新检测和事件监听:

这里有两种情况(按你自己情况自己选择,还可以有其他的方式,这里列两种比较常见的更新方式):

1.检测到更新后,会立即下载,然后退出应用或者点击事件会触发更新

import { app, BrowserWindow, ipcMain } from 'electron'

// 注意这个autoUpdater不是electron中的autoUpdater
import { autoUpdater } from "electron-updater"
// 更新服务器地址,比如"http://**.**.**.**:3002/download/"
let uploadUrl = 'http://xxxx/download/' //和package.json中build -> publish中的url对应

// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
function updateHandle() {
  let message = {
    error: '检查更新出错',
    checking: '正在检查更新……',
    updateAva: '检测到新版本,正在下载……',
    updateNotAva: '现在使用的就是最新版本,不用更新',
  };
  const os = require('os');

  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) {

    ipcMain.on('isUpdateNow', (e, arg) => {
      console.log(arguments);
      console.log("开始更新");
      //some code here to handle event
      autoUpdater.quitAndInstall();
    });

    mainWindow.webContents.send('isUpdateNow')
  });

  ipcMain.on("checkForUpdate",()=>{
      //执行自动更新检查
      autoUpdater.checkForUpdates();
  })
}

// 通过main进程发送事件给renderer进程,提示更新信息
function sendUpdateMessage(text) {
  mainWindow.webContents.send('message', text)
}

2. 检测到更新应用,手动触发下载,并更新

//检查更新
function checkForUpdates(){
  autoUpdater.autoInstallOnAppQuit = false // 阻止退出自动更新
  autoUpdater.autoDownload = false // 阻止自动下载
  let message = {
    error: '检查更新出错',
    checking: '正在检查更新……',
    updateAva: '检测到新版本,正在下载……',
    updateNotAva: '现在使用的就是最新版本,不用更新',
  };
  autoUpdater.setFeedURL(feedURL) // 设置检测更新地址
// 下面是自动更新的整个生命周期所发生的事件
  sendUpdateMessage('currentVersion', autoUpdater.currentVersion.version); // 获取当前应用的版本号
  autoUpdater.on('error', function (error) {
    sendUpdateMessage('error', message.error);
  });
  autoUpdater.on('checking-for-update', function () {
    sendUpdateMessage('checking-for-update', message.checking);
  });
  autoUpdater.on('update-available', function (info) {
    sendUpdateMessage('newVersion', info);
    sendUpdateMessage('update-available', message.updateAva);
  });
  autoUpdater.on('update-not-available', function (info) {
    sendUpdateMessage('notAvailable', info);
    sendUpdateMessage('update-not-available', message.updateNotAva);
  });
  autoUpdater.checkForUpdates() // 检测是否有新版本

}
// 手动触发下载
ipcMain.on("downLoadAndUpdate", () => {
  autoUpdater.autoDownload = true // 开启自动下载
  // 更新下载进度事件
  autoUpdater.on('download-progress', function (progressObj) {
    webContents.send('downloadProgress', progressObj)
    // sendUpdateMessage('downloadProgress', progressObj);
  });
  //下载完后执行
  autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateURL) {
    sendUpdateMessage('isUpdateNow',"下载完毕,即将更新...")
    setTimeout(() => {
      autoUpdater.quitAndInstall();
    },1500)

  })
  autoUpdater.checkForUpdates()
})
// 登录成功后检测更新
ipcMain.on("checkNewVersion", () => {
  checkForUpdates()
})

// 主进程主动发送消息给渲染进程函数
function sendUpdateMessage(message, data) {
  webContents.send('message', {message, data});
}
  1. 在视图层做处理
    import {ipcRenderer} from 'electron'

    ipcRenderer.on("message", (event, text) => {
        // 这里来处理自动更新的生命周期中的一些事件
        console.log('text=',text)
        
    });
    // 下载进度
    ipcRenderer.on("downloadProgress", (event, progressObj) => {
        this.downloadPercent = parseInt(progressObj.percent) || 0;
    });
  1. 项目打包

将新版本latest.yml文件和exe文件(MAC下将latest-mac.yml,zip和dmg文件)放到package.json中build -> publish中的url对应的地址下

注意:mac下需要有证书才能进自动更新,但没有证书也能打包成功

mac打包签名可以看下这篇文章:Electron 打包Mac安装包代码签名问题解决方案

7.软件升级版本,修改package.json中的version属性

至此整个打包自动更新的主要流程完成了

如有疑问,可在本文留言,看到会第一事件回复。

感谢阅读

文章归类于: 码不停蹄

文章标签: #Vue#Javascript#项目

版权声明: 自由转载-署名-非商用