Electron自动更新详解—包教会版

★ 本人在公司项目中实现的Electron更新功能。

★ 将实现更新过程的每一步都总结了出来,以及过程中我遇到了哪些问题,如何去解决的问题,有哪些注意事项。

★ 使用贴合实际应用的HTTP服务器做为载体实现更新,而非github。

开始:

程序配置:

  1. 构建工具:Electron-builder

  2. 更新工具:Electron-updater

在进行更新时,Electron 框架提供了更新的模块。但是我的程序是使用Electron-builder进行的构建。我就使用了Electron-builder这个构建工具提供的自动更新的工具Electron-updater 来实现更新:

更新的思路流程:

  1. 首先安装 electron-updater

    css 复制代码
    npm i electron-updater
  2. 进行更新的配置,官网有提供,在build下的 publish 中进行设置

    javascript 复制代码
    publish: {    
    	provider: "generic", //generic通用HTTP服务器,当然有些人使用github做为更新载体这个地方的值就写github,我使用的是http服务器,在局域网中使用。
    	url: "http://xxxxxx/electron-updater" // 指向服务器对应更新的目录,这个路径的后缀electron-updater是我自定义的,具体原因文章最后讲。
    	channel: "latest",
    },
  3. 单独新建了一个文件,来写更新的逻辑代码,重点来咯...

    (下列代码意思都有详细注释)

    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 };
  4. 将上面的 initAppUpdate 函数引入启动程序文件,我这里的是background.js

  1. 更新的配置到此已经都完成了。接下来要确定程序的版本号,在package.json 中有 version 这个键,设置一个程序版本号。比如你这次打包的程序是1.0.0,那么下次更新就是1.0.1。程序的更新是去检测版本号是不是更新了,版本号更新了才会拉取更新的程序文件。(每次更新构建的时候,记得提高版本号)

  2. 打包构建:运行 npm run build ,在构建后的目录就会有 latest.yml 这个文件和 程序文件等。

  3. 构建成功后,你需要在服务器上建一个目录,用来放程序文件等。

    1. 在你服务器新建一个目录(我命名为 electron-updater),上传文件:

      1. 第一个文件:latest.yml 这个文件包含了更新的版本信息以及程序包的信息等。

      2. 第二个文件:xxx.exe,应用程序。

      3. 第三个文件:xxx.exe.blockmap ,块映射文件。用于增量更新,每次更新只更新变动的文件。

        但是有需要注意的事项:

        1. 你想要实现增量更新,需要将 .blockmap 块映射文件上传到对应的服务器目录下,并且你还要保留更新前版本的块映射文件。因为增量更新,需要比对更新前的块映射文件和准备要更新的块映射文件之间的差异,来实现增量更新。
        2. 比如:你服务器上的程序版本现在是1.0.0,现在程序要更新为1.0.1,那么你想让客户端实现增量更新,你的服务器需要放置的文件有
          1. 版本 1.0.1latest.yml 文件
          2. 版本 1.0.1xxx.exe 文件
          3. 版本 1.0.1xxx.exe.blockmap 文件
          4. 版本 1.0.0xxx.exe.blockmap 文件
        3. 还有一个增量更新的注意事项,写在下面了👇
    2. 先把你在服务器上创建的放置更新文件、程序文件的目录映射出去。也就是为了解决文章开始写到的配置 publish 的时候,其中有个 url:http://xxxxxx/electron-updater,这个 url 就是直接访问我们新建的这个目录。

      1. 我新建的目录名字叫做 electron-updater 目录名称。但是我在服务器上创建的 electron-updater 并不和 url 中的 electron-updater 是一个哦,是因为我用 electron-updater 这个路径代理了 electron-updater 这个目录,当然代理的路径也可以改为别的,那么这时 url 的对应路径也要改。

      2. 如何让 http://xxxxxx/electron-updater 访问到服务器上创建的 electron-updater 放置文件的目录呢?使用代理服务器!

        当我开发测试的时候,我使用的是 nginx 来映射的目录。测试了一下,发现实现了更新的功能、以及增量更新,一切都成功了。但是了解到使用方的服务器代理使用的 apache ,所以我又使用 apache 来实现,这次遇到问题了,在测试实现增量更新的时候,一直报错响应头的 Content-Type 错误,针对该错误我去 apache 添加响应头,测试依旧有新报错,随后就没有再去尝试了。所以开头写到了,我采用了完整更新,而非增量更新。完整更新都是可以正常下载更新,只有使用 apache 的时候增量更新有问题。但使用 nginx 是不用格外配置就可以成功实现 完整更新 和 增量更新,所以没有代理服务器要求的,使用 nginx 方便一些。

        1. nginx 配置

        2. apache 配置

        bash 复制代码
        # 映射本地目录到URL路径
        Alias "/electron-updater" "D:/xxx/electron-updater"
        ...

总结:

  1. 注意我在配置更新的时候,禁用了退出程序后自动更新,当然也可以打开这个配置哦。用户打开程序再次退出关闭后,自动更新程序,这个功能还是挺不错的。

  2. 保存路径:

    1. 程序更新日志保存路径: C:\Users\Administrator\AppData\Roaming\你的程序名\logs
    2. 程序更新下载后的保存路径: C:\Users\Administrator\AppData\Local\xxxxx_electron-updater\pending
  3. 一定要注意有新版本后,要提高程序的版本号,再 build 打包构建哦~

  4. 此外我还设置了一个小功能,就是不仅在程序刚打开的时候去检测是否有更新。用户在使用的过程中也加了按钮可以让用户点击查看是否需要更新,如果不需要更新,会提示用户此版本为最新版本,多么贴心的功能....... (前面的代码里面有写到)

此时Electron的更新功能,或者说Electron的自动更新就算圆满结束!

相关推荐
To_OC6 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
To_OC6 小时前
LC 17 电话号码的字母组合:我的回溯算法,就是从这道题开窍的
javascript·算法·leetcode
vipbic6 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy6 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志7 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble8 小时前
c端系统,其实更像一个信息展示平台
前端
你怎么知道我是队长8 小时前
JavaScript的变量和数据类型介绍
开发语言·javascript·ecmascript
李姆斯8 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜9 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司9 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能