自动更新功能设计与实现
前言
“自动更新”功能通常包含在各类软件中,操作系统类例如 Windows;应用软件类例如 Google Chrome。通过“自动更新”功能,可以使用最新的更新和增强功能来自动使软件保持最新。用户不必再主动搜索重要的更新和信息,软件通常可以识别网络情况,并使用 Internet 连接从指定网站获取更新内容,每当有新的更新可用时,软件可以提示用户进行升级或进行自动升级。


当然也有其他情况,例如在 iOS 中,软件的更新由 App Store 接管,并且对于热更新有着严格的使用限制,详见 知乎:如何看待苹果禁止 JSPatch 等 iOS APP 热更新方案?。
参考
设计
简单来说,自动更新功能流程如下:
graph LR A([启动更新]) --> B[查询新版本] B --> C{是否有新版本} C --否--> D([结束更新]) C --是--> E[下载更新内容] E --> F[应用更新内容] F --> G([结束更新])
版本定义
参考 iOS,铁路12306 的版本记录有版本号、更新说明及一些其他信息(例如发布日期)。

版本号(Version)
关于版本号的定义,借鉴 .NET的版本控制。
遵循语义版本控制 (SemVer),也就是采用 MAJOR.MINOR.PATCH
版本控制。
MAJOR 在下列情况时递增:
- 产品或新产品方向发生重大更改。
- 发生了中断性变更。 接受中断性变更存在较大障碍。
- 旧版本不再受支持。
- 采用了现有依赖项的较新 MAJOR 版本。
MINOR 在下列情况时递增:
- 添加了公共 API 外围应用。
- 添加了新行为。
- 采用了现有依赖项的较新 MINOR 版本。
- 引入了新依赖项。
PATCH 在下列情况时递增:
- 进行了 Bug 修复。
- 添加了对较新平台的支持。
- 采用了现有依赖项的较新 PATCH 版本。
- 任何其他不符合上述情况的更改。
更新说明(Changelog)
描述本次更新修改的内容,参考以下格式:
1
2
3
4
5
6
7
8
9 YYYY-MM-DD John Doe <johndoe@example.com>
* myfile.ext (myfunction): my changes made
additional changes
* myfile.ext (unrelated_change): my changes made
to myfile.ext but completely unrelated to the above
* anotherfile.ext (somefunction): more changes
安装程序(Installer)
提供 安装程序 的文件名及 Hash,例如 MD5、SHA-1、CRC32。

其他的 Hash 可以参考下图:

版本存档(Archive)
将指定版本添加存档属性后,该版本拒绝提供下载,只能进入服务端查看信息。
强制更新(Mandatory)
将指定版本设置为强制更新,则客户端程序检测到该版本为新版本时,会进行后台自动更新,更新完成后提示用户重启程序后生效。
最新版本(LastestVersion)
将指定版本设置为最新版本,即该版本可以不是实际上最新的版本,则客户端在检测更新时,只会截止到该版本,如果客户端版本高于该版本,可以进行降级更新。
这项设置的意义是,当发布某个新版本后,发现该版本有严重 BUG ,在解决 BUG 之前可以将上个版本设置为最新版本,并同时设置强制更新,让客户端程序自动进行降级处理。
版本资源
对版本资源提供查询服务,提供某个版本所有文件的相对路径及 Hash 值。
服务端资源
假设应用程序的名称为APP
,则创建如下目录存放资源:
1 | C:\USERS\PUBLIC\DOCUMENTS\PUBLISH\APP |
版本信息记录:
1 | { |
客户端资源
1 | C:\Program Files\APP |
客户端更新逻辑
sequenceDiagram %% autonumber 客户端->>客户端: 程序启动 客户端->>客户端: 搜索本地最新版本(1),将老版本(2)删除 loop 客户端->>服务端: 定期查询新版本 alt 有新版本 服务端->>客户端: 提供新版本(3)及文件列表信息(4) 客户端->>客户端: 创建文件夹(3),并将(1)中的文件复制到(3) 客户端->>服务端: 根据(4)的信息,请求下载更新文件 服务端->>客户端: 传输有差异的文件(新增或替换) 客户端->>客户端: 删除本地不在(4)中的文件 else 服务端-->>客户端: 结束更新 end end
实现
留坑。
后记
本篇内容只粗略介绍了自动更新功能,但在真实的应用场景中,需要考虑更多因素,例如 Ubuntu 中更新源的设置,Windows 中的传递优化。


