Electron开发实战之记账软件14——自动更新

原创
2019/05/07 22:06
阅读数 1.3W

代码仓库: https://gitee.com/XiaoLanMiao/LanMiaoDesktop

官网介绍了多种更新方式,我们使用的electron-builder的更新机制。 https://electronjs.org/docs/tutorial/updates

安装electron-updater模块

npm install electron-updater

配置package.json

在build节点下添加如下内容

    "publish": {
      "provider": "github",
      "repo": "LanMiaoDesktop",
      "owner": "hilanmiao",
      "releaseType": "release"
    },

打包时就会生成latest.yml文件,这里面记录的是当前版本的信息,electron-updater会根据这个和最新版本比较,然后触发相应事件。

编写主进程代码

核心就是触发“checkForUpdates、downloadUpdate”这两个事件

import {autoUpdater} from 'electron-updater'

/**
 * 自动更新
 */
function autoUpdate() {
    // 通过main进程发送事件给renderer进程,提示更新信息
    function sendUpdateMessage(obj) {
        mainWindow.webContents.send('updateMessage', obj)
    }

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

    // 当更新出现错误时触发
    autoUpdater.on('error', (err) => {
        // sendUpdateMessage('error')
        sendUpdateMessage({action: 'error', errorInfo: err})
    })

    // 当开始检查更新的时候触发
    autoUpdater.on('checking-for-update', () => {
        // sendUpdateMessage('checking')
        sendUpdateMessage({action: 'checking'})
    })

    // 当发现一个可用更新的时候触发,更新下载包会自动开始
    autoUpdater.autoDownload = false
    autoUpdater.on('update-available', (info) => {
        // sendUpdateMessage('updateAva')
        sendUpdateMessage({action: 'updateAva', updateInfo: info})
    })

    // 当没有可用更新的时候触发
    autoUpdater.on('update-not-available', (info) => {
        // sendUpdateMessage('updateNotAva')
        sendUpdateMessage({action: 'updateNotAva'})
    })

    // 更新下载进度事件
    autoUpdater.on('download-progress', (progressObj) => {
        mainWindow.webContents.send('downloadProgress', progressObj)
    })

    /**
     * event Event
     * releaseNotes String - 新版本更新公告
     * releaseName String - 新的版本号
     * releaseDate Date - 新版本发布的日期
     * updateUrl String - 更新地址
     */
    autoUpdater.on('update-downloaded', (info) => {
        // 下载太快可能无法触发downloadProgress事件,所以手动通知一下
        mainWindow.webContents.send('downloadProgress', {percent: 100})
        // 可以手动选择是否立即退出并更新
        ipcMain.on('isUpdateNow', (e, arg) => {
            // some code here to handle event
            autoUpdater.quitAndInstall()
        })
    })

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

    ipcMain.on('downloadUpdate', () => {
        // 下载
        autoUpdater.downloadUpdate()
    })
}

下面这三个事件会返回给你一个info,里面存了version、releaseNotes等信息,你可以把这些信息保存下来备用。

需要注意的是如果下载的速度太快,可能无法触发downloadProgress(公司网速太快,一直触发不了),所以需要自己手动触发一次。

编写渲染进程代码

主进程代码已经写好了,这里无非就是通信并接受返回值罢了。我是进入页面就进行一次检测,然后获取releaseNotes并保存到localstorage里了。核心就是触发“checkForUpdates、downloadUpdate”这两个事件。

downloadAndUpdate() {
    this.downloading = true

    // 开始下载
    ipcRenderer.send('downloadUpdate')
    ipcRenderer.on('downloadProgress', (event, progressObj) => {
        this.progress = JSON.stringify(progressObj)
        // console.log(progressObj)
        this.downloadPercent = progressObj.percent.toFixed(0) || 0
        // if(this.downloadPercent === 100) { // 这样写为啥不好使呢?
        if(progressObj.percent === 100) {
            this.downloading = false
            // 询问是否立即更新
            this.dialogUpdateNow = true
        }
    })
},
updateNow() {
   // 立刻退出并更新
   ipcRenderer.send('isUpdateNow')
},
checkForUpdate() {
    // 开始检查
    ipcRenderer.send('checkForUpdate')
    // 添加自动更新事件的监听
    ipcRenderer.on('updateMessage', (event, obj) => {
        if (obj.action === 'updateAva') {
            this.hasNewVersion = true
            this.saveVersionInfoList(obj.updateInfo)
            this.versionInfoList = this.getVersionInfoList()
        } else if (obj.action === 'error') {
            this.showError = true
            this.errorInfo = obj.errorInfo
        } else if(obj.action ==='updateNotAva') {
            this.noNewVersion = true
        } else {
            // console.log(text)
        }
    })
},

效果

确认更新后自动弹出安装界面

说明

我是手动触发的更新,图省事的话可以直接在渲染进程里写就ok了,但是不友好,假如用户正在工作,这时候更新就不合适了,需要优化的地方还有很多,后面会持续优化,例如后台更新这种常见需求。

electron-builder支持从github上更新。这是个开源项目,所以直接用github release 更新就好了,缺点是github可能比较慢,当然你也可以换成自己的服务器或者放到别的地方,例如阿里的OSS,把你的安装包放到某个目录下,然后把生成的latest.放上,再改一下build的publish参数,如下,就可以自动识别和下载了。

 "publish": [
      {
        "provider": "generic",
        "url": "http://**.**.**.**:3002/download/"
      }
    ],

移除监听事件

为避免多次切换页面造成监听的滥用,切换页面前必须移除监听事件。因为main.js中的事件可能是共享给多个页面的,所以这几个页面都会收到main.js发送的通知,这显然是不对的。例如你debug的时候可能会看到这样的消息。

(node:23006) Error: Possible EventEmitter memory leak detected. 11 conn-st listeners added. Use emitter.setMaxListeners() to increase limit

展开阅读全文
加载中
点击加入讨论🔥(1) 发布并加入讨论🔥
1 评论
0 收藏
0
分享
返回顶部
顶部