首页/文章/electron

Electron自动更新实践

2024-07-30
22418 分钟
...

前言

自动更新检测是指在应用启动或运行过程中,自动检查服务器上的最新版本,并下载和安装更新的功能。这一功能保证了应用始终处于最新状态,减少了用户因手动更新而产生的麻烦。在构建基于 Electron 的桌面应用时,自动更新功能是提升用户体验的重要环节之一。通过实现自动更新,应用可以自动下载和安装最新版本,用户无需手动更新,保持应用的最新状态和安全性。

自动更新的好处:

  • 提升用户体验:自动更新减少了用户的操作步骤,确保用户始终使用最新版本的应用,避免了因版本过旧导致的功能不兼容。

  • 增强安全性:及时更新到最新版本可以修复已知的安全漏洞,降低因应用漏洞导致的安全风险。

  • 简化维护流程:自动更新可以减少开发者手动推送更新的工作量,降低维护成本,确保应用持续稳定运行。

如何实现Electron的自动更新检测?

electron官方提供了一个autoUpdater来进行自动更新,不过要搭建专门的更新服务(如 Hazel、Nuts 等),而第三方的更新服务包electron-updater可以选择通用的软件更新服务器,更利于学习,所以本文采用的是electron-updater实现自动更新服务。如何从零创建一个electron项目,请参考此文Electron桌面应用开发实践。假设项目已经有了,要添加自动更新功能。该如何做?

第一步 安装electron-updater

要安装在dependencies依赖下,否则打包安装之后的应用软件,打开时会提示can't find module electron-updater

pnpm add electron-updater

第二步 编写应用更新检测逻辑

在主窗口加载完毕之后,检查是否有新的发布包,判断是否要进行更新。

import { app, BrowserWindow, ipcMain, Tray, Menu, screen } from "electron";
import checkUpdate from "./checkUpdate.js";


let mainWindow;

app.on("ready", async () => {
  

  const { width, height } = screen.getPrimaryDisplay().workAreaSize;

  mainWindow = new BrowserWindow({
    
  });

  
  

  mainWindow.webContents.on("did-finish-load", () => {
    checkUpdate();
  });
  
});

checkUpdate函数的执行流程是:设置更新包的检测url地址,执行更新检测。监听更新包下载出错,是否有高版本的更新包,下载进度,下载完成事件。当软件更新包下载完成时,提示更新。

import { app, dialog } from "electron";
import { autoUpdater } from "electron-updater";


export default function checkUpdate( mainWindow) {
 
  autoUpdater.setFeedURL("http://localhost:9000"); 

  const isDevelopment = process.env.NODE_ENV === "development";
  if (isDevelopment) {
    
    autoUpdater.forceDevUpdateConfig = true;
  }

  
  autoUpdater.checkForUpdates();

  
  autoUpdater.on("error", (err) => {
    console.log("出错:", err);
  });

  
  autoUpdater.on("update-available", () => {
    console.log("found new version");
  });

  
  autoUpdater.on("download-progress", (progressObj) => {
    console.log(`Download speed: ${progressObj.bytesPerSecond}`);
    console.log(`Downloaded ${progressObj.percent}%`);
    console.log(`Transferred ${progressObj.transferred}/${progressObj.total}`);
  });
  
  
  autoUpdater.on("update-downloaded", () => {
    dialog
      .showMessageBox({
        type: "info",
        title: "应用更新",
        message: "发现新版本,是否更新?",
        buttons: ["是", "否"],
      })
      .then((buttonIndex) => {
        if (buttonIndex.response == 0) {
          
          autoUpdater.quitAndInstall();
          app.quit();
        }
      });
  });
}

如果要在开发环境调试升级功能的话,需要开启强制在开发环境进行更新检查开关,然后手动在package.json中修改version字段,对版本号进行增加。比如当前项目的版本是v0.0.1, 要把package.json中的version版本修改成大于v0.0.1的版本,这里我们修改为v0.0.2

{
  "version": "0.0.2",
}

第三步 创建静态文件服务器

网上许多文章提到可以把软件更新包发布到github releases, 这个方案在国内没有全局梯子的情况下行不通,下载更新包时会报网络错误。所以本文采用本地静态服务器来进行演示。

前面我们把软件更新包检测地址配置成了http://localhost:9000, 现在需要部署一个这样的静态文件服务器。npm serve包可以用来快速地启动一个本地服务器,我们就用它生成一个静态文件服务器,存放Electron应用的更新包。执行下面的命令,生成访问端口号为9000的静态文件服务器。

npm install -g serve
serve -p 9000 ./static-server

另外在electron-builder.json5中添加publish的配置项,不然Mac系统上无法生成相应的latest-mac.yml文件。

{
  publish: [
    {
      provider: "generic",
      url: "http://localhost:9000",
    },
  ],
}  

第四步 测试

现在万事俱备,只差一个高版本的软件更新包。我们先在开发环境测试一下更新流程。运行Electron应用打包命令,先打一个v0.0.2的应用包,防止将打包之后的exe和yml文件手动上传到static-server静态服务器根目录下。

接着把package.json中的version字段修改成0.0.1, 然后在开发环境运行项目,弹出发现新版本,是否更新的问询框。说明开发环境更新检测没问题。

我们再打一个v0.0.1的Electron应用包,进行安装。安装完之后打开,看看是否有上面的弹窗,我验证了一下,也是OK的。至此,自动更新的功能已经实现。

踩坑记录

1. 开启DevTools功能后,开发环境会报这样的警告

[8328:0727/175659.432:ERROR:CONSOLE(1)] "Request Autofill.enable failed. {"code":-32601,"message":"'Autofill.enable' wasn't found"}", source: devtools://devtools/bundled/core/protocol_client/protocol_client.js (1)

这个警告说的是在调用 Autofill.enable 时失败了,因为在开发工具的协议客户端中未找到 Autofill.enable 方法。通常意味着使用的 Chrome DevTools 协议版本不支持该方法,或者该方法被弃用或未实现。由于不影响使用,不用处理。

2. 警告 updaterCacheDirName is not specified in app-update.yml Was app build using at least electron-builder 20.34.0?

这个错误提示表明 app-update.yml 文件中没有指定 updaterCacheDirName,还需要确认是否使用了 electron-builder v20.34.0以上版本。我创建了一个app-update.yml,填充了这个字段,仍旧有这样的警告,也是不影响使用,就没有去管。

cache:
  updaterCacheDirName: ReleaseCache

3. 报错 Skip checkForUpdates because application is not packed and dev update config is not forced

这个错误说的是在开发环境中尝试执行更新检查,但应用未打包,且未强制启用开发更新配置。开启开发更新配置之后报错消失。

 autoUpdater.forceDevUpdateConfig = true;

4.应用安装之后,界面显示正常,但是无更新提示弹窗弹出。

通过使用electron-log加日志进行调试,发现是icon图标设置的地址在生产环境找不到,造成后续的逻辑没有被执行导致。

5. 将应用包上传到git releases之后, 未见更新提示弹窗显示

发现使用浏览器插件代理,只有在浏览器上访问github速度是比较流畅的,如果未使用全局代理的话,在Electron应用中,下载git releases中的更新包会报网络错误,导致更新流程出错。

6. webContents的did-finish-load事件不触发

刚开始把 checkUpdate()放在webContents的did-finish-load事件中执行,结果发现未被调用。后面发现是写法有问题,要移除mainWindow.loadURL前面的await,想想也是,加上await之后,渲染进程页面已经加载好了,肯定不会再触发did-finish-load事件了。

if (VITE_DEV_SERVER_URL) {
    
    await mainWindow.loadURL(VITE_DEV_SERVER_URL + "/main.html");
  } else {
    
    const url = path.join(__dirname, "../");
    await mainWindow.loadURL(`file://${url}/dist/main.html`);
  }


  mainWindow.webContents.on("did-finish-load", () => {
    checkUpdate();
  });

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
electron2025-03-05
不依赖第三方库自己实现 Electron 的主与渲染进程的国际化功能
正文 直接贴出代码: 主进程实现 首先需要在 文件中获取当前系统的语言,然后初始化国际化相关: 文件: 文件 然后在主进程中就可以通过 来实现国际化了。 渲染进程的实现 App 在启动的时候渲染进程已经执行了国际化的初始化,所以在主进程已经保存了一份当前语言的 信息,所以渲染进程就不需要进程这一步,直接从主进程获取即可。 主进程进程添加一个 事件,供渲染进程获取国际化相关数据: 首先我们要在 preload 中提前将国际化相关的信息写入...
学习
electron2025-03-05
应用多开,限制只启动一个应用,防止多个实例
通过app.requestSingleInstanceLock来控制应用的多开,返回值为boolean。 此方法的返回值表示你的应用程序实例是否成功取得了锁。如果它取得锁失败,你可以假设另一个应用实例已经取得了锁并且仍旧在运行,并立即退出。 即:如果当前进程是应用程序的主要实例,则此方法返回true,同时你的应用会继续运行。如果当它返回false,如果你的程序没有取得锁,它应该立刻退出,并且将参数发送给那个已经取到锁的进程。 在macO...
学习
electron2024-09-23
Electron实现文件缓存背景
背景 基于Electron研发的一款IM企业通信桌面端应用,会存在非常多文件、图片、视频类型回话消息。在Electron应用(桌面客户端软件)中,快速加载并显示图片是提升用户体验的关键。然而,传统的图片加载方式往往存在加载速度慢、资源占用高等问题,影响了用户的使用体验。 解决的问题 1. 支持自定义配置存储的磁盘位置 2. 支持长期存储 3. 支持自定义存储大小 4. 支持自定义存储类型(如图片、视频、文件,或者更细致化到MIME) 5...
学习
electron2024-09-23
我的 Electron 客户端也可以全量和增量更新了
前言 本文主要介绍 客户端应用的自动更新,包括全量和增量这两种方式。 全量更新: 运行新的安装包,安装目录所有资源覆盖式更新。 增量更新: 只更新修改的部分,通常是渲染进程和主进程文件。 本文并没有拿真实项目来举例子,而是起一个 新的项目 从 0 到 1 来实现自动更新。 如果已有的项目需要支持该功能,借鉴本文的主要步骤即可。 前置说明: 1. 由于业务场景的限制,本文介绍的更新仅支持 操作系统,其余操作系统未作兼容处理。 2. 更新流...
学习
electron2024-09-20
我的 Electron 客户端被第三方页面入侵了
问题描述 公司有个内部项目是用 来开发的,有个功能需要像浏览器一样加载第三方站点。 本来一切安好,但是某天打开某个站点的链接,导致 整个客户端直接变成了该站点的页面 。 这一看就是该站点做了特殊的处理,经排查网页源码后,果然发现了有这么一句代码。 翻译一下就是:如果当前窗口不是顶级窗口的话,将当前窗口设置为顶级窗口。 奇怪的是两者不是 跨域 了吗,为什么 还可以影响顶级窗口。 先说一下我当时的一些解决办法: 1. 用 替换 2. 给 添...
学习
electron2024-09-13
Electron+WebRTC实现局域网内的远程控制软件
我的工位上有一台笔记本(windows),一个显示器,一台服务器(linux)。显示器同时连接笔记本和服务器,当需要用到服务器的时候:1.使用todesk等软件进行连接;2.直接把显示器切换到服务器桌面,然后给服务器插上鼠标键盘。在这种场景下,屏幕画面的传输对我来说并不是必要的,这种场景下能不能用一套键鼠控制两个电脑呢?边做边学便有了这个小工具。记录下来,其中遇到的问题和解决方案。 通过electron + Vue + primevue...
学习

评论

请登录后发表评论

去登录
加载评论中...

目录