大家好,我是杨成功。
在上一篇文章《手撸 Electron 自动更新,再繁琐也要搞懂它》中,我们详细介绍了 Electron 自动更新的全流程。
简单来说,就是打包生成 latest.yml 文件和安装包,并上传到服务器。客户端打开时访问服务端的 latest.yml 地址,判断是否有新版本,有则自动下载新包并更新。
对于以上的更新流程,很多朋友在评论区留言表示不够灵活,比如:
下面我们一一解答这些问题,并手撸一个更灵活的自动更新接口。
在开发阶段想测试一下检测更新的流程走没走通,可能不太好测试,因为 Electron 默认在开发环境下会绕过更新检测。
开发环境下 Electron 启动后,如果接入了自动更新,主进程控制台会打印下面的信息:
Skip checkForUpdates because application is not packed and dev update config is not forced
意思是当前是开发环境,未打包,所以绕过检测。Electron 通过 app.isPackaged
的值来判断是否打包,那么在开发环境下,我们可以修改一下这个值:
import { app } from 'electron';// 未打包时是开发环境if (!app.isPackaged) { Object.defineProperty(app, 'isPackaged', { get: () => true, });}
重新运行,大概率会看到第二个错误:
Error: ENOENT: no such file or directory /xxxx/app-update.yml
因为没有打包嘛,所以找不到 app-update.yml
这个文件,索性我们就创建一个。
在根目录下创建一个 dev-update.yml
文件(文件名可自定义),写入配置:
provider: genericupdaterCacheDirName: demo-updater # 下载目录
然后在开发环境指定这个配置文件地址:
import { app } from 'electron';import path from "path";if(!app.isPackaged) { ... autoUpdater.updateConfigPath = path.join(__dirname, "../../dev-update.yml");}
重新运行项目,会发现检测更新的逻辑可以正常执行了。
可能大家希望的检查更新流程是这样:
调用后端的 API 接口,接口返回 JSON 格式数据,包含最新的版本号和安装包下载地址。将该版本号与本地版本号做对比,如果不一样则表示有更新,并执行下载。
然而 electron-updater
是通过 latest.yml
文件来获取版本号等信息。latest.yml 是一个配置文件,内容如下:
version: 1.0.2files: - url: elapp_1.0.2.exe sha512: xxxxxx size: 72716511path: elapp_1.0.2.exesha512: xxxxxxreleaseDate: '2023-11-29T02:28:28.032Z'
大家想绕过它,可能是因为 YAML 文件的内容看不太懂,或者与接口格式不匹配。其实它就是一个普通的配置文件,转换成 JSON 格式如下:
{ "version": "1.0.2", "files": [ { "url": "elapp_1.0.2.exe", "sha512": "xxxxxx", "size": "72716511" } ], "path": "elapp_1.0.2.exe"}
可能有人会问:配置文件可以改成latest.json
吗,这样后端就可以动态返回了。
我仔细查阅过文档,目前只支持 YAML 文件,不支持 JSON,所以 latest.yml 无法绕开。但这只是官方说法,咱还是有办法滴。
经过大量测试,我发现把 latest.yml 文件的内容手动改成 JSON 格式也是可以的。这样的话,就可以写一个接口来模拟 latest.yml 的地址。
假设 latest.yml 的访问路由是/ele-app/latest.yml
,那么写一个接口如下:
const app = require('express')()app.get('/ele-app/latest.yml', (req, res, next) => { let resinfo = { version: "1.0.25", path: "xxx_1.0.25.exe" sha512: "xxxxxx" } res.send(resinfo)})
该接口就是自定义的检测更新接口。接口返回值中至少要包含version、path、sha512
三个属性(与 latest.yml 中的配置保持一致)。这样我们不需要上传 latest.yml 文件了,用该接口替代即可。
基于该检测更新接口,接下来我们逐步实现自定义更新流程。
对于 Windows 和 Mac 两个系统的更新,electron-updater 使用不同的配置文件,分别是 latest.yml
和 latest-mac.yml
。
从上一步的检测更新接口来看,不同的配置文件就是不同的路由,我们改造接口如下:
app.get('/ele-app/:platform', (req, res, next) => { let { platform } = req.params let resinfo = null // 返回 Windows 配置 if(platform == 'latest.yml') { resinfo = { version: "1.0.2", path: "xxx_1.0.2.exe" sha512: "xxxxxx" } } // 返回 Mac 配置 if(platform == 'latest-mac.yml') { resinfo = { version: "1.0.3", path: "xxx_1.0.3.dmg" sha512: "xxxxxx" } } if(!resinfo) { resinfo = { code: 400, msg: '参数错误' } } res.send(resinfo)})
上面代码中,使用动态路由返回 Windows 和 Mac 的配置,同时兼容了两个平台的更新检测。
经过上面的介绍,自定义检测更新的关键思路已经讲清楚了。完整的更新流程如下:
(1)打包各个平台的安装包,上传服务器。
如何打包在上一篇介绍过,就不展开说了。注意的是:现在你只需要上传安装包,不需要上传 latest.yml 文件。
(2)在主进程中设置更新地址,并手动控制更新。
假设我们编写的检测更新接口已经部署,设置方法如下:
import { autoUpdater } from 'electron-updater';// 设置检测更新的地址autoUpdater.setFeedURL('http://[xxx]/ele-app');// 不自动下载autoUpdater.autoDownload = false;// 触发检测autoUpdater.checkForUpdatesAndNotify().catch();// 监听到可更新autoUpdater.on('update-available', (info) => { // info 是检测更新接口返回的数据 if (info.can_download) { // can_download 是自定义属性 autoUpdater.downloadUpdate(); }});
(3)编写检测更新接口,返回配置。
返回的配置我们可以自定义,假设返回结果如下:
{ "version": "1.0.2", "path": "http://xxx/xxx_1.0.2.exe", "sha512": "xxxxxx", "can_download": false}
上述示例中,接口返回了自定义属性 can_download
,我们在第(2)步中使用了该属性,用于判断是否执行下载更新。
通过这种方式,即便我们更新了安装包,也可以自由决定是否要下载安装。
这里有一个小惊喜:path
属性的值可以是一个完整的安装包地址,这样可以把安装包上传到任意地方。如果值是一个文件名,那么会以第(2)步中 setFeedURL()
方法设置的地址为前缀。
提醒:sha512 属性的值必须从打包生成的 latest.yml 中获取,不可以随意写,否则在安装时不能通过检验,会报这个错:
Error: sha512 checksum mismatch
Mac 系统有两种软件包,分别对应 M1 芯片和 Intel 芯片,两者不兼容。一般打包时我们也会构建两种安装包。
那么在检测更新时,我们就需要返回适配当前系统的安装包。但不管是 M1 还是 Intel 都使用 latest-mac.yml
这一个配置文件,该如何区分呢?
这个时候就要从主进程中获取参数,然后传给接口了。步骤如下:
(1)在主进程中,获取系统架构,并通过请求头传给检测更新接口。
import { autoUpdater } from 'electron-updater';// 添加请求头autoUpdater.requestHeaders = { elearch: process.arch,};
(2)在接口中接收参数,并在返回 Mac 配置中判断:
app.get('/ele-app/:platform', (req, res, next) => { let { platform } = req.params let { elearch } = req.headers if(platform == 'latest-mac.yml') { if(elearch == 'arm64') { // M1 return {...} } else { // Intel return {...} } }})
有了上面的逻辑,我们在打包时就可以单独打两个包,分别上传,然后在检测时返回不同的下载地址。
本文使用自定义接口的方式,绕过了 latest.yml 配置文件,使自动更新的灵活性更高,也更符合我们的常规习惯,但是需要维护一个更新接口。
如果不想维护接口,那么上传 latest.yml 文件的方式更适合你。
本文链接:http://www.28at.com/showinfo-26-37267-0.htmlElectron 自动更新,绕过 latest.yml 使用自定义接口
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: Go中的switch的六种使用:没有你想象中那么简单
下一篇: Python的函数递归与调用,你会吗?