如何使用electron-builder及electron-updater给项目配置自动更新

作者:Wonder233 时间:2024-04-17 10:02:04 

说明:

本文的自动更新功能使用的项目为 electron-vue 脚手架搭建一个默认项目。

参考的文章如下:

  • electron-vue 中文文档

  • electron-builder 文档

  • Windows 下支持自动更新的 Electron 应用脚手架

  • Electron 文档 Docs / API / autoUpdater

开始:新建一个 electron 项目

首先你得有一个需要配置自动更新功能的 electron 项目。这里我为了测试自动更新功能是否成功搭建使用的是 electron-vue 脚手架搭建的项目。

搭建过程如下:

# 安装 vue-cli 和 脚手架样板代码
npm install -g vue-cli
vue init simulatedgreg/electron-vue autoUpdataTest
# 安装依赖并运行你的程序
cd autoUpdataTest
npm install
npm run dev

程序运行后的界面如下:

如何使用electron-builder及electron-updater给项目配置自动更新

脚手架生成的文件结构:

|- autoUpdateTest
|- .electron-vue # 压缩及运行环境的配置文件
|- build #
|- icons # 图标文件
|- ... # 打包生成的文件在此处
|- dist # 用 webpack 压缩项目后生成的压缩文件在此处
|- node_modules
|- src # 资源文件
|- main # 主进程
|- renderer # 渲染进程
|- index.ejx # 入口文件
|- static # 静态资源
|- .babelrc
|- .gitignore
|- .travis
|- appveyor.yml
|- package-lock.json # npm 自动生成的文件
|- package.json
|- README.md

使用 electron-builder 最关键的配置在 package.json 里:(为了观察我们所需要的地方,把此篇文章里不需要关注的代码给删掉了。)

{
"name": "autoupdatetest",
"version": "0.0.0",
"author": "wonder <xxxxxxxxx@qq.com>",
"description": "An electron-vue project",
"main": "./dist/electron/main.js",
"scripts": {
"build": "node .electron-vue/build.js && electron-builder",
"dev": "node .electron-vue/dev-runner.js",
},
"build": {
"productName": "autoupdateteset",
"appId": "org.simulatedgreg.electron-vue",
"directories": {
 "output": "build"
},
"files": "dist/electron/**/*",
"win": {
 "icon": "build/icons/icon.ico"
}
},
"dependencies": {
},
"devDependencies": {
}
}

解析:

前四行是一般的 package.json 会有的:

  • name — 项目名

  • version — 版本号

  • author — 开发人员及邮箱号

  • description — 项目描述 。

下面重点看后面的内容:electron-builder详细配置文档

  • "main": "./dist/electron/main.js" — 这里的 main 入口文件指的是用 electron-builder 打包主程序的入口文件,这里的路径是使用 webpack 压缩项目后文件输出的位置。

  • scripts — 脚本

    • "build": "node .electron-vue/build.js && electron-builder" — 生产环境,压缩打包项目。先运行 .electron-vue 文件夹下的 build.js 脚本对项目进行压缩,输出的位置在 dist 文件夹下,然后再使用配置好的 electron-builder 对 dist 文件夹下的文件进行打包生成应用的安装包。

    • "dev": "node .electron-vue/dev-runner.js" — 开发环境,可以运行我们的项目并测试。这里使用了热更新,改动代码不需要刷新即可看到应用的改变。

  • build — electron-builder 配置项

    • "productName": "autoupdateteset", — 工程项目名

    • "appId": "org.simulatedgreg.electron-vue" — 应用程序 ID。强烈建议设置显式ID。

    • directories

    • "output": "build" — 生成的安装包输出目录。

    • "files": "dist/electron/**/*" — 安装包源文件目录,支持多路径(数组)

    • "win": { "icon": "build/icons/icon.ico"} — 打包成 Windows 系统下安装包应用程序图标路径,还有别的配置项可以在详细文档中查看。

有关 electron-vue 的使用的更详细的说明请看 中文文档。

自动更新

安装依赖

自动更新功能的实现依赖 electron-builderelectron-updater

因为我们是用的electron-builder脚手架生成的项目,已经有 electron-builder 依赖了,所以只需要安装 electron-updater

# 目录 E:\GitHub\autoupdateteset
npm i electron-updater --save # 必须安装为运行依赖,否则运行会出错

配置 package.json

为了配合打包 package.json 需要给 build 新增配置项:

"build": {
"publish": [
 {
  "provider": "generic",
  "url": "http://127.0.0.1:5500/" #这里是我本地开的服务器的地址
 }
],
...
}

主进程(参考:electron 中文文档)

主进程的入口文件是 src/main/index.js

import {
app,   // app 模块是为了控制整个应用的生命周期设计的。
BrowserWindow, // BrowserWindow 类让你有创建一个浏览器窗口的权力。
ipcMain
} from 'electron';
// 引入自动更新模块
const { autoUpdater } = require('electron-updater');
// 不支持 ES6 则用如下方式引入
// const autoUpdater = require("electron-updater").autoUpdater
const feedUrl = `http://127.0.0.1:5500/win32`; // 更新包位置
/**
* Set `__static` path to static files in production
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
*/
if (process.env.NODE_ENV !== 'development') {
global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\');
}
let mainWindow, webContents;
const winURL = process.env.NODE_ENV === 'development' ?
`http://localhost:9080` :
`file://${__dirname}/index.html`;
function createWindow() {
/**
 * Initial window options
 */
mainWindow = new BrowserWindow({
 height: 563,
 useContentSize: true,
 width: 1000
});
mainWindow.loadURL(winURL);
webContents = mainWindow.webContents;
mainWindow.on('closed', () => {
 mainWindow = null;
});
}
// 主进程监听渲染进程传来的信息
ipcMain.on('update', (e, arg) => {
console.log("update");
checkForUpdates();
});
let checkForUpdates = () => {
// 配置安装包远端服务器
autoUpdater.setFeedURL(feedUrl);
// 下面是自动更新的整个生命周期所发生的事件
autoUpdater.on('error', function(message) {
 sendUpdateMessage('error', message);
});
autoUpdater.on('checking-for-update', function(message) {
 sendUpdateMessage('checking-for-update', message);
});
autoUpdater.on('update-available', function(message) {
 sendUpdateMessage('update-available', message);
});
autoUpdater.on('update-not-available', function(message) {
 sendUpdateMessage('update-not-available', message);
});
// 更新下载进度事件
autoUpdater.on('download-progress', function(progressObj) {
 sendUpdateMessage('downloadProgress', progressObj);
});
// 更新下载完成事件
autoUpdater.on('update-downloaded', function(event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
 sendUpdateMessage('isUpdateNow');
 ipcMain.on('updateNow', (e, arg) => {
  autoUpdater.quitAndInstall();
 });
});
//执行自动更新检查
autoUpdater.checkForUpdates();
};
// 主进程主动发送消息给渲染进程函数
function sendUpdateMessage(message, data) {
console.log({ message, data });
webContents.send('message', { message, data });
}
app.on('ready', () => {
createWindow();
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
 app.quit();
}
});
app.on('activate', () => {
if (mainWindow === null) {
 createWindow();
}
});

渲染进程

渲染进程的入口文件是 src/renderer/index.js

这里我们主要修改 App.vue,将原来的内容全删掉并使更新的整个周期在界面上打印出来。

<template>
<div id="app">
 <!-- <router-view></router-view> -->
 <button @click="autoUpdate()">获取更新</button>
 <ol id="content">
  <li>生命周期过程展示</li>
 </ol>
</div>
</template>
<script>
// import { ipcRenderer } from 'electron';
const { ipcRenderer } = require('electron');
export default {
name: 'my-project1',
mounted() {
 var _ol = document.getElementById("content");
 ipcRenderer.on('message',(event,{message,data}) => {
  let _li = document.createElement("li");
  _li.innerHTML = message + " <br>data:" + JSON.stringify(data) +"<hr>";
  _ol.appendChild(_li);
  if (message === 'isUpdateNow') {
   if (confirm('是否现在更新?')) {
    ipcRenderer.send('updateNow');
   }
  }
 });
},
methods: {
autoUpdate() {
 ipcRenderer.send('update');
}
}
};
</script>
<style>
/* CSS */
</style>

显示的界面如下:

如何使用electron-builder及electron-updater给项目配置自动更新

自动更新过程简单介绍

1.将 webpack.json 里的版本号先改为 0.0.1,然后npm run build生成一个版本为0.0.1的安装包。

如何使用electron-builder及electron-updater给项目配置自动更新 

如何使用electron-builder及electron-updater给项目配置自动更新

注意上面一步会生成一个latest.yml文件,autoUpdate 实际上通过检查该文件中安装包版本号与当前应用版本号对比来进行更新判断的。

latest.yml文件内容如下:

如何使用electron-builder及electron-updater给项目配置自动更新

2.然后将上一步生成的安装包放在本地开启的服务器文件夹下,对应你在主程序入口文件中配置的服务器位置。

如何使用electron-builder及electron-updater给项目配置自动更新

3.将 package.json 中的版本号改回0.0.0,再npm run build一遍,运行 build 文件夹下的 exe 安装包,就将软件安装在你电脑里面了。点击安装完成后桌面上的快捷方式,再次点击上面的获取更新的按钮就可以看到显示在界面的自动更新生命周期了。(但这里因为会给你直接自动更新,所以会一闪而过,你可以在 autoUpdate 的各个生命周期事件里设置主进程与渲染进程通信,则可以一步一步观察到整个自动更新的生命周期了。)

通过测试总结 autoUpdate 生命周期图

如何使用electron-builder及electron-updater给项目配置自动更新

更新过程展示

1、无版本更新

如何使用electron-builder及electron-updater给项目配置自动更新 

如何使用electron-builder及electron-updater给项目配置自动更新

2、有版本更新

如何使用electron-builder及electron-updater给项目配置自动更新 

点击取消后会先不更新,在应用关闭后更新:

如何使用electron-builder及electron-updater给项目配置自动更新 

点击确认后则会直接更新:

如何使用electron-builder及electron-updater给项目配置自动更新

踩过的坑

1、主进程与渲染进程通信

最开始我是直接在主进程直接运行更新

如何使用electron-builder及electron-updater给项目配置自动更新 

然后想在渲染进程中打印主进程传过来的消息,但是发现只有 isUpdateNow 事件运行时才有日志显示。

结果发现原来主进程与渲染进程之间通信必须在渲染进程已经运行的时候(即那个界面完全显示出来)才能够进行。所以我将自动更新改为界面按钮触发,这样才能检测到自动更新的整个流程。

来源:https://blog.csdn.net/Wonder233/article/details/80563236

标签:electron-builder,electron-updater,自动更新
0
投稿

猜你喜欢

  • Python获取CPU、内存使用率以及网络使用状态代码

    2023-03-14 22:43:36
  • JavaScript入门学习书籍的阶段选择

    2008-01-11 19:39:00
  • Adobe发布Flash Player 10正式版

    2008-10-15 17:15:00
  • Python实现统计文本文件字数的方法

    2023-05-24 11:46:04
  • Python用dilb提取照片上人脸的示例

    2021-07-04 23:34:47
  • SQL Server 分页编号的另一种方式【推荐】

    2024-01-25 15:53:53
  • python协程与 asyncio 库详情

    2023-08-23 12:08:36
  • SQL Server 中调整自增字段的当前初始值

    2024-01-27 13:53:01
  • Python简单实现阿拉伯数字和罗马数字的互相转换功能示例

    2021-08-29 08:52:57
  • 基于python的Tkinter编写登陆注册界面

    2022-12-20 09:44:30
  • django实现支付宝支付实例讲解

    2023-08-27 04:45:44
  • MSSQL段落还原脚本,SQLSERVER段落脚本

    2024-01-22 14:48:15
  • 利用python GDAL库读写geotiff格式的遥感影像方法

    2023-08-31 13:15:06
  • 浅析Golang切片截取功能与C++的vector区别

    2024-04-23 09:34:51
  • python数据结构链表之单向链表(实例讲解)

    2021-01-17 12:51:19
  • PHP简单实现正则匹配省市区的方法

    2023-11-14 22:24:09
  • python logging多进程多线程输出到同一个日志文件的实战案例

    2021-01-08 16:25:17
  • Python转换itertools.chain对象为数组的方法

    2022-10-27 08:38:16
  • CentOS7.6安装MYSQL8.0的步骤详解

    2024-01-17 02:48:28
  • 深入了解vue2与vue3的生命周期对比

    2024-05-11 09:14:32
  • asp之家 网络编程 m.aspxhome.com