说明:
- 本文适用于win和mac这两个端
- mac端若要调试更新功能, 一定要把旧版本和新版本都配置mac的代码签名, 至于怎么配置, 主要就是先成为苹果开发者,然后去帐号那边下一个证书, 然后.....
一. 在package.json配置更新参数
参考: Publish - electron-builder
"build": {
"productName": "打包后的名称",
"appId": "com.app.autoupdatertester-nsis", // 随便写, 如果要上传到app Store, 则填写申请的appId
"directories": {
"output": "build"
},
"files": [
"dist/electron/**/*"
],
"dmg": { // mac打包的属性
"contents": [
{
"x": 410,
"y": 150,
"type": "link",
"path": "/Applications"
},
{
"x": 130,
"y": 150,
"type": "file"
}
]
},
"mac": {
"icon": "src/icon/icon-mac.icns",
"artifactName": "SlientPrint_${version}.${ext}",
"target": [
"dmg",
"zip"
]
},
"win": {
"icon": "src/icon/icon.ico",
"artifactName": "SlientPrint_${version}.${ext}",
"target": [
"nsis"
]
},
"linux": {
"icon": "src/icon"
},
"nsis": {
"oneClick": false,
"perMachine": true,
"allowElevation": true,
"allowToChangeInstallationDirectory": false,
"uninstallDisplayName": "${productName}",
"deleteAppDataOnUninstall": true
},
"publish": [
{
"provider": "generic", // 普通静态资源服务器填这个就行, 其他的看官网
"url": "文件服务器地址,写到路径名就行了,别加文件名地址"
}
]
},
二. 项目中加入electron-updater, electron-log
electron-updater: 要用在生产环境里面的,所以要在package.json的dependencies字段里面.
electron-log: 为了在调试更新时查看更新途中的日志, 排查问题
yarn add electron-updater, electron-log
三. 新建autoUpdater.js
import { app, BrowserWindow, ipcMain, dialog } from 'electron'
import log from '../config/logger'
import { autoUpdater } from 'electron-updater'
const fs = require('fs-extra')
const path = require('path')
// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
export function updateHandle({ mainWindow }) {
// 清除每次更新下载的文件,否则无法进行更新
//= ==============================================================================================================
// updaterCacheDirName的值与src/main/app-update.yml中的updaterCacheDirName值一致,在windows中会创建一个类似
// C:\Users\Administrator\AppData\Local\slient-print-updater\pending文件存储更新下载后的文件"*.exe"和"update-info.json"
let updaterCacheDirName = 'slient-print-updater'
const updatePendingPath = path.join(autoUpdater.app.baseCachePath, updaterCacheDirName, 'pending')
log.warn('updatePendingPath:' + updatePendingPath)
fs.emptyDir(updatePendingPath)
let message = {
error: '检查更新出错',
checking: '正在检查更新……',
updateAva: '检测到新版本,正在下载……',
updateNotAva: '现在使用的就是最新版本,不用更新'
}
// 也可以通过代码配置文件服务地址
autoUpdater.setFeedURL({
provider: 'generic',
url: '服文件地址'
})
// 设置是否自动下载,默认是true,当点击检测到新版本时,会自动下载安装包,所以设置为false
autoUpdater.autoDownload = false
autoUpdater.logger = log
// 正在检查更新
autoUpdater.on('error', function (error) {
sendUpdateMessage(message.error, mainWindow)
})
autoUpdater.on('checking-for-update', function () {
sendUpdateMessage(message.checking, mainWindow)
})
// 有新的可用更新
autoUpdater.on('update-available', function (info) {
sendUpdateMessage(message.updateAva, mainWindow)
})
// 没有可用的更新,也就是当前是最新版本
autoUpdater.on('update-not-available', function (info) {
sendUpdateMessage(message.updateNotAva, mainWindow)
})
// 更新下载进度事件
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) => {
log.warn('开始更新')
autoUpdater.quitAndInstall()
})
mainWindow.webContents.send('isUpdateNow')
})
ipcMain.on('checkForUpdate', () => {
// 执行自动更新检查
log.warn('执行自动更新检查, isDestroyed:', mainWindow.isDestroyed())
// 解决mac重启App 报错 的问题: object has been destroyed
if (mainWindow &&!mainWindow.isDestroyed()) {
autoUpdater.checkForUpdates()
}
})
ipcMain.on('downloadUpdate', () => {
// 下载
log.warn('执行下载')
autoUpdater.downloadUpdate()
})
}
// 通过main进程发送事件给renderer进程,提示更新信息
function sendUpdateMessage(text, mainWindow) {
mainWindow.webContents.send('message', text)
}
四. 在主进程中调用更新的函数main.js
import { updateHandle } from './autoUpdater.js'
function createWindow(key) {
mainWindow = new BrowserWindow({
webPreferences: {
webSecurity: true,
nodeIntegration: true,
enableRemoteModule: true,
},
height: 600,
useContentSize: true,
width: 750,
show: true,
})
mainWindow.loadURL(winURL)
mainWindow.on('close', e => {
if (process.platform !== 'darwin') {
mainWindow = null
}
})
// 尝试更新, 只有当用户第一次打开app时才触发
if (key == 1) updateHandle({ mainWindow })
}
app.on('ready', () => {
createWindow(1)
})
五. logger.js代码
const log = require('electron-log')
log.transports.file.fileName = 'main.log';
log.transports.file.level = 'false';
// 达到最大上限后,备份文件并重命名为:main.old.log,有且仅有一个备份文件
log.transports.file.maxSize = 1048576;
log.transports.console.level = 'silly';
export default log
六. 渲染进程
<template>
<div class="app-container">
<el-dialog
:title="title"
:visible.sync="visible"
width="400px"
:close-on-click-modal="false"
:close-on-press-escape="false"
@closed="$emit('dialogClosed')"
class="update-dialog"
center
>
<span>{{ remark }}</span>
<span slot="footer" class="dialog-footer">
<el-button size="small" type="primary" @click="updateApp">立即升级</el-button>
<el-button size="small" @click="visible = false">取 消</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { ipcRenderer, remote } from 'electron'
export default {
name: 'landing-page',
mounted: function () {
// 给主进程发送事件
ipcRenderer.send('web-created')
// 检查更新
ipcRenderer.send('checkForUpdate')
// 监听自动更新事件
ipcRenderer.on('message', (event, text) => {
if (text === '检测到新版本,正在下载……') {
this.$nextTick(() => {
this.visible = true
})
}
})
},
data() {
return {
title: '软件更新',
remark: '发现新版本, 确定升级吗?',
visible: false
}
},
methods: {
downloadUpdate() {
this.downloadPercent = 0
ipcRenderer.send('downloadUpdate')
// //注意:“downloadProgress”事件可能存在无法触发的问题,只需要限制一下下载网速就好了
ipcRenderer.on('downloadProgress', (event, progressObj) => {
this.downloadPercent = parseInt(progressObj.percent || 0)
})
ipcRenderer.on('isUpdateNow', () => {
ipcRenderer.send('isUpdateNow')
})
},
},
}
</script>
七. 查看效果
八. main.log日志