官网介绍了多种更新方式,我们使用的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