★ 本人在公司项目中实现的Electron更新功能。
★ 将实现更新过程的每一步都总结了出来,以及过程中我遇到了哪些问题,如何去解决的问题,有哪些注意事项。
★ 使用贴合实际应用的HTTP服务器做为载体实现更新,而非github。
开始:
程序配置:
-
构建工具:Electron-builder
-
更新工具:Electron-updater
在进行更新时,Electron
框架提供了更新的模块。但是我的程序是使用Electron-builder
进行的构建。我就使用了Electron-builder
这个构建工具提供的自动更新的工具Electron-updater
来实现更新:

更新的思路流程:
-
首先安装
electron-updater
:cssnpm i electron-updater
-
进行更新的配置,官网有提供,在
build
下的publish
中进行设置javascriptpublish: { provider: "generic", //generic通用HTTP服务器,当然有些人使用github做为更新载体这个地方的值就写github,我使用的是http服务器,在局域网中使用。 url: "http://xxxxxx/electron-updater" // 指向服务器对应更新的目录,这个路径的后缀electron-updater是我自定义的,具体原因文章最后讲。 channel: "latest", },
-
单独新建了一个文件,来写更新的逻辑代码,重点来咯...
(下列代码意思都有详细注释)
javascript/** * 应用更新 */ const { app, dialog, ipcMain, nativeImage } = require("electron"); const { autoUpdater } = require("electron-updater"); const log = require("electron-log"); // 为了输出更新的日志:为安装了 electron-log => npm i electron-log const path = require("path"); function initAppUpdate(win) { // 配置日志,这个日志在 windows:C:\Users\Administrator\AppData\Roaming\你的程序名\logs autoUpdater.logger = log; autoUpdater.logger.transports.file.level = "info"; // 禁用增量更新:代表用户每次进行更新,都会将服务器上完整的程序进行下载更新,而不会更新指定修改的块文件。 // 当然肯定是增量更新更好,但是为什么我禁用了呢,文章最后讲。 autoUpdater.disableDifferentialDownload = true // 退出时自动安装:当用户使用程序的时候,按兵不动。等待用户关闭程序了退出了之后,程序自动安装,这样下次用户再次打开就是更新后的程序,但我为了让客户感知到更新,我禁用了退出时自动安装。 autoUpdater.autoInstallOnAppQuit = false; // 检查更新(应用启动时触发) app.whenReady().then(() => { autoUpdater.checkForUpdates(); }); // 监听下载完成事件(这里就是具体给用户展示的更新的对话框,这个对话框的视图在文章开头我贴出来了) autoUpdater.on("update-downloaded", () => { dialog .showMessageBox(win, { type: "info", buttons: ["稍后", "立即安装"], message: "更新已下载", detail: "新版本已就绪,是否立即安装?", defaultId: 1, // 默认选中"立即安装"(索引1) cancelId: 0, // 按Esc键等同于点击"取消" }) .then((res) => { if (res.response === 1) autoUpdater.quitAndInstall(); // 如果他对话框点击"立即安装",就退出开始安装 }); }); // 错误处理 autoUpdater.on("error", (err) => { log.error("更新失败", err); }); checkUpdate(win); } // 渲染进程触发的检查更新(这个我在程序里有个专门让用户用来检测更新的地方) function checkUpdate(win) { ipcMain.handle("checkUpdate", async () => { const res = await autoUpdater.checkForUpdates(); if (!res.isUpdateAvailable) { dialog.showMessageBox(win, { type: "info", buttons: ["我知道了"], message: "当前版本已经是最新版本", icon: loadIcon(), }); } }); } // 加载图标(兼容开发和生产环境) function loadIcon() { try { let iconPath = path.join(__static, "right.png"); return nativeImage.createFromPath(iconPath); } catch (e) { console.error("加载图标失败:", e); return null; } } // 这个函数,要引入到主进程的启动程序文件里,还要将win传参给该函数 // 为什么要传递win呢? 因为你不传的话,这个提示更新的dialog就和程序是两个程序。如果你传了win给dialog的话,dialog就在当前win上弹出。 module.exports = { initAppUpdate };
-
将上面的
initAppUpdate
函数引入启动程序文件,我这里的是background.js
:

-
更新的配置到此已经都完成了。接下来要确定程序的版本号,在
package.json
中有version
这个键,设置一个程序版本号。比如你这次打包的程序是1.0.0,那么下次更新就是1.0.1。程序的更新是去检测版本号是不是更新了,版本号更新了才会拉取更新的程序文件。(每次更新构建的时候,记得提高版本号) -
打包构建:运行
npm run build
,在构建后的目录就会有latest.yml
这个文件和 程序文件等。 -
构建成功后,你需要在服务器上建一个目录,用来放程序文件等。
-
在你服务器新建一个目录(我命名为
electron-updater
),上传文件:-
第一个文件:
latest.yml
这个文件包含了更新的版本信息以及程序包的信息等。 -
第二个文件:
xxx.exe
,应用程序。 -
第三个文件:
xxx.exe.blockmap
,块映射文件。用于增量更新,每次更新只更新变动的文件。但是有需要注意的事项:
- 你想要实现增量更新,需要将
.blockmap
块映射文件上传到对应的服务器目录下,并且你还要保留更新前版本的块映射文件。因为增量更新,需要比对更新前的块映射文件和准备要更新的块映射文件之间的差异,来实现增量更新。 - 比如:你服务器上的程序版本现在是1.0.0,现在程序要更新为1.0.1,那么你想让客户端实现增量更新,你的服务器需要放置的文件有
- 版本
1.0.1
的latest.yml
文件 - 版本
1.0.1
的xxx.exe
文件 - 版本
1.0.1
的xxx.exe.blockmap
文件 - 版本
1.0.0
的xxx.exe.blockmap
文件
- 版本
- 还有一个增量更新的注意事项,写在下面了👇
- 你想要实现增量更新,需要将
-
-
先把你在服务器上创建的放置更新文件、程序文件的目录映射出去。也就是为了解决文章开始写到的配置
publish
的时候,其中有个url:http://xxxxxx/electron-updater
,这个url
就是直接访问我们新建的这个目录。-
我新建的目录名字叫做
electron-updater
目录名称。但是我在服务器上创建的electron-updater
并不和 url 中的electron-updater
是一个哦,是因为我用electron-updater
这个路径代理了electron-updater
这个目录,当然代理的路径也可以改为别的,那么这时 url 的对应路径也要改。 -
如何让
http://xxxxxx/electron-updater
访问到服务器上创建的electron-updater
放置文件的目录呢?使用代理服务器!当我开发测试的时候,我使用的是
nginx
来映射的目录。测试了一下,发现实现了更新的功能、以及增量更新,一切都成功了。但是了解到使用方的服务器代理使用的apache
,所以我又使用apache
来实现,这次遇到问题了,在测试实现增量更新的时候,一直报错响应头的Content-Type
错误,针对该错误我去apache
添加响应头,测试依旧有新报错,随后就没有再去尝试了。所以开头写到了,我采用了完整更新,而非增量更新。完整更新都是可以正常下载更新,只有使用apache
的时候增量更新有问题。但使用nginx
是不用格外配置就可以成功实现 完整更新 和 增量更新,所以没有代理服务器要求的,使用nginx
方便一些。-
nginx 配置
: -
apache 配置
:
bash# 映射本地目录到URL路径 Alias "/electron-updater" "D:/xxx/electron-updater" ...
-
-
-
总结:
-
注意我在配置更新的时候,禁用了退出程序后自动更新,当然也可以打开这个配置哦。用户打开程序再次退出关闭后,自动更新程序,这个功能还是挺不错的。
-
保存路径:
- 程序更新日志保存路径:
C:\Users\Administrator\AppData\Roaming\你的程序名\logs
- 程序更新下载后的保存路径:
C:\Users\Administrator\AppData\Local\xxxxx_electron-updater\pending
- 程序更新日志保存路径:
-
一定要注意有新版本后,要提高程序的版本号,再
build
打包构建哦~ -
此外我还设置了一个小功能,就是不仅在程序刚打开的时候去检测是否有更新。用户在使用的过程中也加了按钮可以让用户点击查看是否需要更新,如果不需要更新,会提示用户此版本为最新版本,多么贴心的功能....... (前面的代码里面有写到)
此时Electron的更新功能,或者说Electron的自动更新就算圆满结束!