公司项目是使用elctron-vue构建的,之前一直是打包成一个绿色免安装版给用户使用的,也没有在线更新的功能,每次更新了新的版本用户可能都不知道。为了提升用户体验,最近打算把在线更新这个功能解决了。
公司项目是使用elctron-vue构建的,之前一直是打包成一个绿色免安装版给用户使用的,也没有在线更新的功能,每次更新了新的版本用户可能都不知道。
为了提升用户体验,最近打算把在线更新这个功能解决了。
这两天研究了下,基本已经实现,现在对实现做一些总结:
现在实现了window端在线下载安装更新,Mac端由于没有证书。。目前是检测到有更新后,跳转到浏览器下载新的安装包。
使用electron-builder打包
在开始使用electron-vue构建项目的时候,记得选用electron-builder
electron-vue集成了两种打包方式:electron-packager和electron-builder
他们的区别是:(应该是这些区别吧)
- electron-packager打包成的是绿色安装包,没有实现自动更新功能;
- electron-builder打包好的是安装文件,配合插件实现了自动更新。
所以我们要实现自动更新,记得选用electron-builder打包的方式。
之前项目是使用的electron-packager构建方式,在改成electron-builder的没有成功。。。最后只有重新构建了项目,把现有的代码复制过去了(据同事说他弄成功了?????excuse me?!)
安装electron-builder模块
- 安装模块
1
| npm install --save electron-builder
|
- 配置package.json
为了打包时生成latest.yml文件,需要在 build 参数中添加 publish 配置。
其他配置,请阅读官方文档
1 2 3 4 5 6 7 8 9 10 11 12 13
| "build": { "publish": [ { "provider": "generic", "url": "http://**.**.**.**:3002/download/", } ], ..., "nsis":{ } }
|
注意:配置了publish才会生成latest.yml(mac环境是生成的latest-mac.yml)文件,用于自动更新的配置信息;latest.yml文件是打包过程生成的文件,为避免自动更新出错,打包后禁止对latest.yml文件做任何修改。如果文件有误,必须重新打包获取新的latest.yml文件!!!
- 增加nsis配置(可省略)
nsis配置不会影响自动更新功能,但是可以优化用户体验,比如是否允许用户自定义安装位置、是否添加桌面快捷方式、安装完成是否立即启动、配置安装图标等。nsis 配置也是添加在 build 参数中。 详细参数配置可参见官方文档:nsis配置
1 2 3 4 5 6 7 8 9 10
| "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.检测到更新后,会立即下载,然后退出应用或者点击事件会触发更新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| import { app, BrowserWindow, ipcMain } from 'electron'
import { autoUpdater } from "electron-updater"
let uploadUrl = 'http://xxxx/download/'
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("开始更新"); autoUpdater.quitAndInstall(); });
mainWindow.webContents.send('isUpdateNow') });
ipcMain.on("checkForUpdate",()=>{ autoUpdater.checkForUpdates(); }) }
function sendUpdateMessage(text) { mainWindow.webContents.send('message', text) }
|
2. 检测到更新应用,手动触发下载,并更新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| 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) }); 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 2 3 4 5 6 7 8 9 10 11
| import {ipcRenderer} from 'electron'
ipcRenderer.on("message", (event, text) => { console.log('text=',text) });
ipcRenderer.on("downloadProgress", (event, progressObj) => { this.downloadPercent = parseInt(progressObj.percent) || 0; });
|
项目打包
将新版本latest.yml文件和exe文件(MAC下将latest-mac.yml,zip和dmg文件)放到package.json中build -> publish中的url对应的地址下
注意:mac下需要有证书才能进自动更新,但没有证书也能打包成功
mac打包签名可以看下这篇文章:Electron 打包Mac安装包代码签名问题解决方案
7.软件升级版本,修改package.json中的version属性
至此整个打包自动更新的主要流程完成了
如有疑问,可在本文留言,看到会第一事件回复。
感谢阅读