注:本人初学记录,用法并非最优,仅供参考。
一、更新流程
1、客户端启动,调用服务器接口,获取是否有更新配置(服务端返回发布的最新版本号和更新内容)。
2、客户端比对当前版本和服务端接口返回版本是否一致,若版本号大于本地版本,弹出升级提示。
3、用户点击升级,页面显示下载进度、下载完毕自动更新、重启。
二、update.js,需要配置updateUrl,既软件安装包所在服务器的目录,如http://域名/app/,其中app目录下存放的latest.yml、安装包.exe(mac端是latest-mac.yml、安装包.dmg、安装包.zip)
const { ipcMain } = require('electron')
const { autoUpdater } = require('electron-updater')
// 更新地址,该地址下放的是安装包和latest.yml
const updateURL = 'http://你的软件下载网络地址/'
const message = {
error: '软件更新异常,请重试',
checking: '正在检查更新',
updateAva: '检测到新版本,准备下载',
updateDown: '软件下载中,请耐心等待',
updateSet: '下载完成,准备安装',
updateNotAva: '已经是最新版本',
}
//软件版本更新
ipcMain.handle('on-soft-update', (e) => {
autoUpdater.checkForUpdates()
})
// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
function handleUpdate(mainWindow, callback) {
// 设置是否自动下载,默认是true,当点击检测到新版本时,会自动下载安装包,所以设置为false
autoUpdater.autoDownload = true
// 如果安装包下载好了,当应用退出后是否自动安装更新
autoUpdater.autoInstallOnAppQuit = false
// 设置版本更新服务器地址
autoUpdater.setFeedURL(updateURL)
// 更新发生错误时触发
autoUpdater.on('error', function () {
sendUpdateMessage(message.error)
})
// 开始检查更新事件
autoUpdater.on('checking-for-update', function () {
sendUpdateMessage(message.checking)
})
// 没有可更新版本
autoUpdater.on('update-not-available', function (info) {
sendUpdateMessage(message.updateNotAva)
})
// 发现可更新版本
autoUpdater.on('update-available', function (info) {
sendUpdateMessage(message.updateAva)
})
// 更新下载进度事件
autoUpdater.on('download-progress', function (progressObj) {
sendUpdateMessage(message.updateDown)
mainWindow.webContents.send('on-soft-download', progressObj.percent)
})
// 下载监听
autoUpdater.on(
'update-downloaded',
function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
mainWindow.webContents.send('on-soft-download', 100)
sendUpdateMessage(message.updateSet)
//3秒后更新
setTimeout(() => {
autoUpdater.quitAndInstall()
}, 3000)
}
)
// 向渲染进程发送消息
function sendUpdateMessage(text) {
mainWindow.webContents.send('on-soft-message', text)
}
}
module.exports = {
handleUpdate,
}
三、index.js ,既electron主进程的启动文件
const { app, BrowserWindow, Tray, Menu, nativeImage } = require('electron')
const autoUpdate = require('./update.js')
const path = require('path')
//防止应用多开
const gotTheLock = app.requestSingleInstanceLock()
if (!gotTheLock) {
app.quit()
} else {
//创建托盘
const createTray = (win) => {
const trayMenu = [{ label: '我的软件', role: 'quit' }]
const tray = new Tray(nativeImage.createFromPath(path.join(__dirname, 'favicon.ico')))
tray.setToolTip('我的软件')
tray.on('click', (e) => {
win.isVisible() ? win.hide() : win.show()
})
tray.setContextMenu(Menu.buildFromTemplate(trayMenu))
}
//创建窗口
const createWindow = () => {
const mainWindow = new BrowserWindow({
width: 760,
height: 500,
center: true,
minWidth: 760,
minHeight: 500,
useContentSize: false,
backgroundColor: '#00000000',
hasShadow: true,
icon: path.join(__dirname, 'logo.png'),
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js'),
},
show: false,
})
//加载页面,略,mainWindow.loadURL 或 mainWindow.loadFile
//加载完毕打开窗口
mainWindow.on('ready-to-show', () => {
autoUpdate.handleUpdate(mainWindow)
mainWindow.show()
})
//创建托盘
createTray(mainWindow)
}
//报错:ERROR:gpu_init.cc(481)] 修复,禁用硬件加速
app.disableHardwareAcceleration()
//屏蔽安全告警在console控制台的显示
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
}
四、preload.js针对进度加载,由于页面不能使用渲染进程remote,这里使用ipc方式
//更新软件
const softUpdate = () => {
ipcRenderer.invoke('on-soft-update')
}
//更新信息
let message = ''
ipcRenderer.on('on-soft-message', (e, arg) => {
message = arg
})
const upInfo = () => {
return message
}
//更新下载进度
let progress = 0
ipcRenderer.on('on-soft-download', (e, arg) => {
progress = arg
})
const upProgress = () => {
return progress
}
//定义所有的接口方法
contextBridge.exposeInMainWorld('myApi', {
upInfo,
upProgress,
softUpdate,
})
五、更新弹出框SoftUpdate.vue
<template>
<el-dialog
v-dialogDrag
title="软件升级"
width="550px"
:visible.sync="isVisible"
:close-on-click-modal="false"
:close-on-press-escape="false"
@close="handleClose"
>
<el-card class="page-header" shadow="hever">
<!--新的版本,当有新版本时候显示-->
<div class="page-header-up">
<template>
<p class="page-header-up-title">更新进度:{{ upInfo }}</p>
<el-progress :text-inside="true" :stroke-width="25" :percentage="percentage" />
<el-divider />
</template>
<div style="float: right; margin-top: 5px">
<el-button type="primary" @click="updateVersion" size="mini">更新</el-button>
<el-button @click="handleClose" size="mini">关闭</el-button>
</div>
</div>
</el-card>
</el-dialog>
</template>
<script>
export default {
name: 'SoftUpdate',
data() {
return {
isVisible: false,
upInfo: '',
percentage: 0,
}
},
//生命周期若已设置定时器,需清空定时器beforeDestroy()
beforeDestroy() {
clearInterval(this.refreshData)
},
methods: {
/**
* 打开
*/
showDialog() {
this.isVisible = true
},
//更新
async updateVersion() {
myApi.softUpdate()
this.upInfo = ''
this.percentage = 0
if (this.refreshData == null) {
this.refreshData = setInterval(() => {
this.upInfoData()
}, 1000)
}
},
//更新进度
upInfoData() {
this.upInfo = myApi.upInfo()
this.percentage = parseInt(myApi.upProgress())
},
/**
* 关闭
*/
handleClose() {
clearInterval(this.refreshData)
this.upInfo = ''
this.percentage = 0
this.isVisible = false
},
},
}
</script>
<style lang="scss" scoped>
::v-deep .el-dialog {
background-color: #f1f3f4;
}
::v-deep .el-dialog__header {
position: relative;
padding: 6px;
background-color: #fff;
}
::v-deep .vab-theme-blue-black .el-dialog__headerbtn {
margin-top: -7px;
background: 0 0;
border: none;
}
::v-deep .el-dialog__body {
padding: 0px;
font-size: 12px;
color: #f1f3f4;
word-break: break-all;
}
.page-header {
background: #f7ffffbd; //f8fff7bd
transition: none;
&-up {
flex: auto;
margin: 0 20px 45px 20px;
&-title {
font-size: 14px;
color: #1890ff;
}
&-description {
font-size: 12px;
color: #808695;
}
}
}
</style>
六、package.json配置
"publish": [
{
"provider": "generic",
"url": "" //半自动更新,所以这里没加的地址
}
]
七、需要自己实现(比如页面启动调用服务端接口获取最新版本,比对当前版本和服务器最新版本,然后弹出SoftUpdate.vue)