Eectron框架 Electron中文网 官网
electron 的自动更新不会像 React Native 一样直接下载 Web 代码静默更新,因为它还有主进程(Node.js)代码,因此需要走安装流程。
electron-updater 是一个用于 Electron 应用程序的第三方库,它提供了丰富的接口和功能来帮助开发者实现应用程序的自动更新
最主要的优势还是支持自定义更新服务。公司发布新版本安装包,直接上传到自己的静态服务器即可,无需再搭建一个专门的更新服务
目录
想了解打包, 欢迎查阅 Electron系列 -- vue项目嵌套electron打包成桌面应用(上)-CSDN博客
一. 安装 electron-updater 实现自动更新
安装依赖 electron-updater
npm install electron-updater
在根目录src下 新建 handleUpdate.js 文件, 粘贴下面的代码
const { autoUpdater } = require("electron-updater");
const { dialog, ipcRenderer } = require("electron");
var mainWin = null;
const checkUpdate = (win, ipcMain) => {
autoUpdater.autoDownload = true; // 自动下载
autoUpdater.autoInstallOnAppQuit = true; // 应用退出后自动安装
mainWin = win;
const checkForUpdates = () => {
// 检测是否有更新包并通知
autoUpdater.checkForUpdatesAndNotify().catch();
};
// 应用启动时检查更新
checkForUpdates();
// 设置每小时检查一次更新
// setInterval(checkForUpdates, 1000 * 60 * 60);
// 监听渲染进程的 install 事件,触发退出应用并安装
ipcMain.handle("install", () => autoUpdater.quitAndInstall());
autoUpdater.on("update-available", (info) => {
console.log("有新版本需要更新");
});
autoUpdater.on("update-not-available", (info) => {
console.log("无需更新");
});
//下载进度
autoUpdater.on("download-progress", (prog) => {
mainWin.webContents.send("update", {
speed: Math.ceil(prog.bytesPerSecond / 1000), // 网速
percent: Math.ceil(prog.percent), // 百分比
});
});
//事件监听器的回调函数接收三个参数:
//event:一个对象,提供了事件相关的信息和功能
//releaseNotes:一个字符串,包含了新版本的发布说明或更新日志。
//releaseName:一个字符串,通常包含了新版本的名称或版本号。
autoUpdater.on("update-downloaded", (event, releaseNotes, releaseName) => {
//更新已经被下载到本地,以便进一步处理
mainWin.webContents.send("downloaded");
let opts = {
type: "info",
buttons: ["现在重启", "稍后"],
title: "应用程序更新",
message: `收银台系统新版本已下载`, // 使用模板字符串来包含变量
detail: "新版本已下载,是否现在重启应用程序以更新?",
};
dialog.showMessageBox(opts).then((response) => {
if (response== 0) {
// 用户选择安装更新,重启应用
autoUpdater.quitAndInstall();
}
});
// 下载完成后强制用户安装,不推荐
// autoUpdater.quitAndInstall();
});
};
module.exports = checkUpdate;
在background.js 中引入 handleUpdate.js文件 ,放置在createWindow方法中 , 调用它
const handleUpdate = require("./handleUpdate");
...
//检查更新
handleUpdate(win, ipcMain)
...
二. 客户端打包前, 进行latest.yml配置
在vue.config.js 中加入latest.yml配置
//latest.yml配置
publish: [
{
provider: "generic",
url: https://xxxx/updateExe, //更新包地址
},
],
package.json 中修改 名字 版本号,
以window平台为例, 打包后会生成多个文件
应用打包,生成安装包和版本配置
版本号取自 package.json 文件中的 version 选项。
假设当前版本号是 1.0.0,我们首先更新版本号为 1.0.1,然后执行打包命令以window平台为例, 打包后会生成多个文件, 以下两个文件需要上传 xxx_1.0.0.exe(安装包) 和 latest.yml(版本配置)
上传到服务器后,需要通过 publish 中配置的地址访问到,最终访问地址如下:
https://xxx/updateExe/xxx_1.0.0.exe 下载安装包
https://xxx/updateExe/latest.yml 检测版本更新
( 控制台是看不到更新请求的, 他是通过electron 主进程发起的, 但是我们可以通过抓包工具来捕捉到它 ,比如 Fiddler 等)
三. 后端配合
配置 nginx 使访问地址生效
我们将上一步的两个文件上传到服务器的 /data/updateExe
目录下,然后在 nginx 配置中添加一个 location 如下:
location /updateExe{
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods GET,POST;
alias /data/updateExe;
sendfile on;
autoindex on;
}
使用 "nginx -s reload" 重新加载配置,访问文件的地址便生效了。
四. 手动更新如何触发
为什么要引入preload.js文件, 你可以把它认为是 Vue 项目与 Electron 之间的桥梁, 有了它我们就可以实现手动检测更新, 并实现更新进度条展示
1. 新建一个preload.js 文件 ,放置在src 同级的public静态目录中,
// preload.js
const { contextBridge, ipcRenderer } = require("electron");
contextBridge.exposeInMainWorld("elecAPI", {
onUpdate: (callback) => ipcRenderer.on("update", callback),
checkForUpdate: () => ipcRenderer.send("checkForUpdate"),
});
2. 将preload.js 引入配置
const win = new BrowserWindow({
width: 1200,
height: 1080,
// autoHideMenuBar: true, // 隐藏菜单栏
webPreferences: {
// Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION, // 禁用上下文隔离
webSecurity: false, //关闭安全策略, 解决跨域问题
preload: isDevelopment
? path.join(__dirname, "../public/preload.js")
: __dirname + "\\preload.js",
},
});
preload这里的写法非常有意思, 我也是踩坑小能手, 这是最终写法, 通过判断是否为开发环境 来实现不同的引入方法, 因为无论是在开发还是生产环境, 常规写法默认都会去找dist_electron/bundled/preload.js 文件, 第一次未打包, 你报错了, 打包一次再执行, 有该文件, 你有可以了, 二次修改后, 突然又异常了 !!
3.在xxx.vue页面引入
通过一个 clickTest事件来触发
....
//引入element-ui 的进度条组件
<el-progress
:text-inside="true"
:stroke-width="20"
:percentage="update_info.percent"
status="exception"
></el-progress>
<el-button @click="clickTest"></el-button>
....
data(){
return{
update_info:null
}
}
....
method:{
clickTest() {
window.elecAPI.checkForUpdate();
},
},
mounted(){
// 监听onUpdate事件, 监听到更新时间后显示进度条
if (window.elecAPI && window.elecAPI.onUpdate) {
window.elecAPI.onUpdate((_event, info) => {
//参数1 网速 ,参数2 百分比
console.log("onUpdate", _event, info);
that.update_info = info;
});
}
}
handleUpdate.js 加入下面代码(已有请忽略 )
//下载进度
autoUpdater.on("download-progress", (prog) => {
mainWin.webContents.send("update", {
speed: Math.ceil(prog.bytesPerSecond / 1000), // 网速
percent: Math.ceil(prog.percent), // 百分比
});
});
在background.js 中加入下面代码, 用于触发手动检查更新
ipcMain.on("checkForUpdate", () => {
try {
autoUpdater.checkForUpdatesAndNotify().catch();
} catch (error) {
console.log(error);
}
});
五. 其他问题
1. 项目中在electron进程打印,console.log 没有反应?
通过添加环境变量,大部分能打印出来(实测)
ELECTRON_ENABLE_LOGGING: true
ELECTRON_ENABLE_STACK_DUMPING: true
总结
经过上述的好几个步骤,现在要发布新版本,只需要执行 2 个步骤。
- 更新版本号,打包。
- 上传到服务器。
如果不加手动触发更新, 也是可以的, 加个轮询机制, 每x个小时主动检查一次更新,否则只能应用打开的第一次检查一次, 陆续不会检测!