.NET 程序自动更新的回忆总结
文章目录
- 前言
- 一、 设计
- 二、核心设计模块
- 三、多客户端兼容实现
- 四、前端交互实现
- 五、安全机制
- 六、实践案例
- 七、实践补充
前言
不管BS的还是CS 的程序,或者APP,程序更新都是比较痛苦的。
如果要设计出自动更新,那思考的就多了。
代码可维护、性能高效、用户体验好、异步避免UI阻塞、增量更新减少下载量、签名验证保障安全,以及回滚机制处理失败场景
一、 设计
如果有这样的一个议题,设计当前程序的自动更新,那应该怎样处理呢?
- 客户端 配置表记录当前版本号。
- 管理员 使用客户端上传更新的dll、或者其他文件,更新版本号
- 用户 登录的时候检查本地配置、数据库 的版本是否匹配,触发更新。
从逻辑上: 增量更新减少下载量
从数据上:
- A表 记录当前版本号及更新日期。
- B表 记录版本号对应的文件
如果不用本地配置记录版本号,还可以将 用户 或 设备MAC 跟版本号在数据库里绑定,作为更新检查依据。
二、核心设计模块
-
版本控制机制
- 采用语义化版本规则:
主版本.次版本.修订号
(如2.1.3
) - 兼容性管理:通过
VersionCompatibility
类处理新旧版本兼容性
public class VersionCompatibility {public bool IsBackwardCompatible(Version oldVer, Version newVer) {return (newVer.Major == oldVer.Major) && (newVer.Minor >= oldVer.Minor);} }
- 采用语义化版本规则:
-
增量更新策略
- 差分算法生成增量包(如 BSDiff)
- 减少 60%-80% 的下载体积
# 生成增量包示例 import bsdiff4 bsdiff4.file_diff("v1.0.exe", "v1.1.exe", "patch.diff")
三、多客户端兼容实现
客户端类型 | 更新方案 | 关键技术点 |
---|---|---|
WinForm | 独立更新服务进程 | Windows Installer (MSI) |
Web 前端 | AJAX 异步更新 | Service Worker 缓存控制 |
跨平台应用 | 容器化更新包 | Docker 镜像分层更新 |
跨平台更新检测逻辑
// 统一版本检测接口
async function checkUpdate() {const res = await fetch("/api/version/latest");const { version, url, minRequiredOS } = await res.json();if (compareVersions(currentVer, version) < 0) {if (checkOSCompatibility(minRequiredOS)) {startDownload(url);}}
}
四、前端交互实现
不管winfrom 还是 vue支持的各种UI。progress进度条都是成熟的控件,能呈现更新状态:
-
AJAX 进度监控
const xhr = new XMLHttpRequest(); xhr.upload.addEventListener("progress", e => {const percent = Math.round((e.loaded / e.total) * 100);updateProgressBar(percent); // 更新进度条组件 }); xhr.open("POST", "/upload-update"); xhr.send(formData);
-
可视化进度组件
<div class="progress-container"><div class="progress-bar" id="update-progress"></div><div class="progress-text">0%</div> </div> <script> function updateProgressBar(percent) {document.getElementById("update-progress").style.width = `${percent}%`;document.querySelector(".progress-text").innerText = `${percent}%`; } </script>
五、安全机制
-
沙盒验证流程
-
关键安全措施:
- SHA256 文件校验
- 代码签名证书验证
- 更新通道 HTTPS 加密
当然,在BS中我已经习惯使用WebApi作为数据接口,JWT 的签名验证,真的很方便。这在前面的文章里我也有提到过:
WebApi验证JWT爬坑记录
六、实践案例
C# 自动更新服务
public class AutoUpdateService {public void CheckAndApplyUpdate() {var latest = VersionAPI.GetLatest(); // 调用版本APIif (latest > CurrentVersion) {var downloader = new FileDownloader();downloader.ProgressChanged += (p) => UpdateUI(p);byte[] updateData = downloader.Download(latest.Url);if (VerifySignature(updateData)) { // 签名验证InstallUpdate(updateData);}}}
}
七、实践补充
作为客户端,分4种情况:
- 64位 桌面程序
- 32位 桌面程序
- 网页
- APP应用
在桌面程序中,32、64位客户端首先肯定是需要分开上传不同路径,
检测客户端情况再更新的:
///判断是否64位
public static Architecture GetCurrentArchitecture()
{return Environment.Is64BitProcess ? Architecture.X64 : Architecture.X86;
}
网页不用考虑,APP却不可增量更新。因为APP的APK包,其实只有一个文件,
不过HBuilder X倒是集成了wgt包的制作,补丁式增量更新,我看了下感觉有点便秘,整不来。