基于Electron开发了桌面应用程序,最后免不了要做安装包,还少不了“在线升级”功能。Electron号称支持自动升级,但真到动手做的时候,才发现并没有官方文档上说得那么简单。最近在网上看了不少文章,反复尝试,千头万绪,其中不乏过时信息的干扰,搞得我晕头转向。正当灰头土脸之际,看到这篇文章,思路逐渐清晰。
我也来总结一下吧,先梳理一个脑图:
再考虑两个关键约束:
最后我的选择是脑图中用绿色标出来的路径。实际上,我跑通了两套方案(注:仅在Windows上试验,因为买不起苹果电脑……),不管是electron-forge打出来的包还是electron-builder打出来的包,都能走通自动升级流程。下面就来分别介绍一下,大家各取所需吧。
方案一:electron-forge + electron自带autoUpdater + 自己部署服务器
electron-forge是Electron官方推荐的打包工具,如果不预先了解它的缺陷(比如不能自定义安装路径、安装过程只有一个简陋的GIF动画——这种“免安装过程”的简易安装方式居然被解说成“优势”,见仁见智吧……),很容易被带坑里。但如果你不介意这些缺陷,electron-forge倒也是一种不错的选择,很容易上手。依据官网的“快速入门”搭建Electron演示程序,并且按照文档最后一节“打包并分发您的应用程序”的步骤,为应用项目加入必要的electron-forge配置。
执行npm run make打出安装包,输出在项目文件夹的out子目录。接下来,怎么自己搭建服务器来测试呢?如前文所述,我们不想依赖GitHub来发布。官网推荐了electron-release-server这个开源服务,它还提供了一个后台Web系统来管理版本发布,用起来很方便。
说白了,为了让electron-forge打包的程序能走通自动升级,服务端需要部署两个文件:新版本程序的.nupkg文件和RELEASES文件。这两个文件可以在安装包exe的相同路径下找到。在electron-release-server上部署时,只需要上传.nupkg文件,系统会自动生成匹配的RELEASES文件。然而,实际的测试结果并不愉快 系统自动生成的RELEASES文件内容为:
0dbe26b8ef3b8b910a8705bc3e554c3ac3383660 /download/flavor/default/1.5.1/windows_32/autoupdatertester-1.5.1-full.nupkg 343892329
在客户端解析这个文件时抛出了异常:
fatal: Finished with unhandled exception: System.AggregateException: 发生一个或多个错误。 ---> System.Exception: Filename can either be an absolute HTTP[s] URL, *or* a file name
在 Squirrel.ReleaseEntry.ParseReleaseEntry(String entry)
对比本地打包时生成的RELEASES文件内容(如下),差异是升级包文件名前有多余的路径:
0DBE26B8EF3B8B910A8705BC3E554C3AC3383660 autoupdatertester-1.5.1-full.nupkg 343892329
尝试过几次修改electron-release-server的服务端配置(据说修改config/local.js 里的appUrl指向一个具体的http地址即可),均未成功!不想浪费太多时间!不就是在服务器上部署两个文件嘛,换成Minio来做吧(灵感来自于这篇文章)。
Minio是实现了S3协议(S3:Simple Storage Service,简单存储服务)的简易服务器,用起来非常方便!搭建步骤如下:
minio server ./minio-data
4. 在浏览器里打开http://127.0.0.1:9000,用户名和密码都输入为minioadmin,登录成功后,点击“test-bucket1”右侧的Manage按钮,然后将Access Policy从Private改成Public
5. 可以在D:\minio-home\minio-data\test-bucket1下放一个index.html,然后尝试在浏览器里访问http://127.0.0.1:9000/test-bucket1/index.html,如果打开成功,恭喜你,Minio服务搭建成功了!
终于来到了激动人心的时刻!我们开始测试自动升级:
GitHub完整演示代码:
https://github.com/luqiming666/AutoUpdater-forge
补充几点说明:
if (require('electron-squirrel-startup')) return;
方案二:electron-builder + electron-updater的autoUpdater + 自己部署服务器
electron-builder是另一种非常强大的打包工具,它支持Windows、macOS和Linux,以及很多种打包格式,在Windows上支持NSIS安装包——允许各种定制。总之,它的官方文档值得仔细一读。
我们还是可以依据Electron官网的“快速入门”来搭建演示程序,只是不再执行electron-forge的打包步骤。接下来,我们侧重介绍“自动升级”相关的package.json配置。package.json中的"build": {}节点是专门为electron-builder服务的,在这里可以为各个平台配置目标的打包格式,比如我们希望Windows上是nsis,Mac上是dmg,等等。另外可以用一个“nsis”节点定制安装包的各种行为(更多配置选项参见官方文档):
"nsis": {
"oneClick": false,
"perMachine": true,
"allowElevation": true,
"allowToChangeInstallationDirectory": true,
"uninstallDisplayName": "${productName}",
"deleteAppDataOnUninstall": true
}
另外一个非常重要的节点是"publish"。有了这个节点,打包时才会生成自动升级必要的latest.yml文件:
"publish": [
{
"provider": "generic",
"url": "http://localhost:9000/test-bucket2"
}
],
注:正式部署时,上述url需要修改为线上环境的地址。
说白了,为了让electron-builder打包的程序能走通自动升级,服务端需要部署两个文件:新版本安装包.exe文件和latest.yml文件。(如果要支持增量升级,还需要同时部署.blockmap文件。老版本的.blockmap文件也要部署在线。)这些文件可以在打包输出目录、安装包exe的相同路径下找到。
演示程序准备好了,就可以开始测试了。还是使用“方案一”中搭建的Minio服务。这次在minio-data下创建一个新的子文件夹test-bucket2,并且将它的Access Policy改成Public。然后,执行如下步骤:
GitHub完整演示代码:
https://github.com/luqiming666/AutoUpdater-nsis
补充几点说明:
两个方案介绍完了。最后再总结一下:
希望大家读了我这篇文章(以及文中链接的少量扩展阅读),就能把Electron客户端软件的自动升级跑通。不必经历我之前艰难的探索之路。如果还有问题,欢迎私信我。