项目有涉及到electron更新,对于electron更新可谓是踩了不是坑。
electron的更新一般来说有两种方式,全量和增量,顾名思义全量就是下载我们打包好的exe文件或者zip文件,进行全面替换。我们之前说过electron就是用浏览器打开我们的页面,很多时候我们的更新可能只会修改渲染进程,那么我们把我们的渲染进程的文件给替换了不久更新吗,也就是说增量实际上是替换打包好的html,js等文件。那么更新的方式如下:
- 主进程修改:全量更新
- 渲染进程修改:全量或增量更新
而我开始对这个并没有很深刻的认识,看了几遍文章一顿瞎搞,结果搞得是全量更新,看着110mb大小的exe下载当时就麻木了这要是用户能接受吗?
全量更新可以参考 juejin.cn/post/705481… 然后稍微自已处理下,这个文章讲的是非常清晰了。 增量更新:当时看了很多文章,整体逻辑呢接收服务器放更新的代码,本地负责请求下载对比版本号是否有更新一系列操作,废话不多说直接上代码(当时参考了一位CSDN老哥的自已做了修改) 首上创建个.ts文件封装好更新的方法 还有一些用得上的插件比如adm-zip包
const admZip = require("adm-zip");
const request = require("request");
const fs = require("fs");
const path = require("path");
const baseUrl = path.resolve("./") + "/resources/";
const fileUrl = ""; //这里需要修改为自己的资源外网
import { app, ipcMain} from "electron";
/**
* 更新
*/
const downLoad = () => {
return new Promise<boolean>((resolve, reject) => {
// 创建一个可以写入的流,
const stream = fs.createWriteStream(`${baseUrl}app.zip`);
const url = `${fileUrl}app.zip`;
request(url)
.pipe(stream)
.on("close", () => {
const unzip = new admZip(`${baseUrl}app.zip`); //下载压缩更新包
unzip.extractAllTo(`${baseUrl}`, true); //解压替换本地文件
resolve(true);
});
});
};
const CheckForUpdates = () => {
return new Promise((resolve, reject) => {
request(
{
url: `${fileUrl}package.json`, //请求package.json,与本地对比版本号
},
(error: any, res: any, body: any) => {
try {
if (error || res.statusCode !== 200) {
throw "Failed to update the version number, please contact the administrator";
}
const json = JSON.parse(body);
const { version, description } = json;
console.log(version);
/**
* app.getVersion() 返回开发中的 Electron 版本号
*/
const localVersion = app.getVersion();
let flag: boolean = false;
version !== localVersion ? (flag = true) : (flag = false);
ipcMain.on("exist_update", (event, message) => {
event.returnValue = flag;
});
//ipc通信 确认更新下载
ipcMain.handle("new_update", async (event, message) => {
let flag = await downLoad();
return flag;
});
ipcMain.on("Sure", (event, message) => {
app.exit();
app.relaunch();
});
} catch (err) {
console.log(err);
reject(err);
}
},
);
});
};
export { downLoad, CheckForUpdates };
然后主进程引入这个ts文件的方法 调用就可以了 例如:
import {
CheckForUpdates
}from '@/util/renew' //这是引入的方法
async function createWindow() {
// Create the browser window.
Menu.setApplicationMenu(null); //隐藏菜单
win = new BrowserWindow({
width: 1000,
height: 600,
center: true, // 默认居中
frame: false,
transparent: true,
resizable: false,
webPreferences: {
nodeIntegration: true, // 使用node
contextIsolation: false,
enableRemoteModule: true,
},
});
win.webContents.openDevTools();//控制台
CheckForUpdates();
就不展示完了
渲染进程
我是用了element-ui-plus 定义个方法里面去做具体的逻辑每个人都都不一样,我是需要进来这个页面就去获取一遍是否需要更新的弹窗··· 然后生命周期调用
click() {
//发送通知是否存在更新
let a = ipcRenderer.sendSync("exist_update");
console.log(a);
if (a) {
//有更新
state.renew = 1;
ElMessageBox.confirm(
lang.systemLang.update_version,
lang.systemLang.update_prompt,
{
confirmButtonText: lang.systemLang.Confirm,
cancelButtonText: lang.systemLang.Cancel,
type: "warning",
},
)
.then(() => {
ipcRenderer.invoke("new_update").then((res) => {
if (res) {
ElMessageBox.confirm(
lang.systemLang.update_completed,
lang.systemLang.reboot,
{
confirmButtonText: lang.systemLang.Confirm,
cancelButtonText: lang.systemLang.Cancel,
type: "warning",
},
)
.then((res) => {
ipcRenderer.send("Sure");
})
.catch((err) => {});
}
});
})
.catch(() => {
//取消
});
} else {
//没有更新
state.renew = 2;
}
},
});
onMounted(() => {
state.click();
});
哦 对了打包还需要设置 vue.config.js 我是用的asar true 打出来的包 默认是false app文件夹的那种(有个小问题之前问过大佬 是说打包完有app.asar优先使用app.asar 所以我就直接打asar的包不需要app的)
asar: true,
正常打包electron客户端后,把这个app.asar文件压缩,放到服务器上,还有package.json文件也要放上去。
adm-zip需要手动安装 npm install adm-zip --save
好了 基本核心的就是这些东西了。有什么不懂的欢迎留言