1. 为什么桌面应用的自动升级比 Web 应用难得多
先说一个我经常被问到的场景:产品做出来了,部署在 Windows 服务器上,跑得好好的,突然客户说需要支持 Linux。好,.NET 8 项目在 Linux 上跑起来了,一切顺利。然后产品经理提了一个听起来很合理的要求:“我们是不是可以做一个自动更新?客户端每次打开的时候检查一下版本,有新版本就提示用户升级。”
听起来很简单,对吧?但你真正动手做一次就会明白,桌面应用的自动升级根本不是“检查版本、下载新文件、覆盖替换”这么简单。它背后牵扯到:更新包怎么分发、增量还是全量、跨平台文件锁定策略、签名与校验、失败回滚、安装权限、静默升级还是交互式升级……每一环都有坑。更要命的是,我们用的 .NET 天然跨平台,意味着同一个升级组件要在 Windows、macOS、Linux 三个平台上表现一致,这基本等于把三个平台的坑全部踩一遍。
这篇文章会完整梳理自动升级组件的选型、原理、落地细节和真实踩坑记录。如果你是 .NET 开发者,正在给 WinForms、WPF、Avalonia 或 MAUI 应用接入自动升级,或者你想自己写一个轻量级升级器,这篇文章应该能帮你少走不少弯路。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 选型对比:Squirrel.Windows、Velopack、AutoUpdater.NET 到底选哪家
2.1 三款主流组件各自的应用边界
目前 .NET 社区里谈到自动升级,绕不开三个方案:Squirrel.Windows、AutoUpdater.NET 和 Velopack。我先把这三者的真实边界说清楚,免得你选错方向。
Squirrel.Windows 是老牌方案,封装了安装、升级、卸载三件套,专门针对 Windows 桌面应用。它的做法是生成一个 Setup.exe,安装时把应用释放到 %LocalAppData% 下的应用目录,然后通过 Update.exe 做差值更新。优点是成熟、坑基本都被踩过一遍;缺点是它只服务 Windows,macOS 和 Linux 不在考虑范围内。
AutoUpdater.NET 更像一个“带界面的检查更新库”,它把更新逻辑嵌入到你的主程序里,定时向服务器请求 XML 或 JSON 格式的版本信息,如果有新版本就下载文件然后关闭应用执行替换。它胜在集成简单,但更新策略相对偏“整包替换”,没有内置的增量机制,而且对非 Windows 平台的支持也比较弱。
Velopack 是后来崛起的新方案,可以理解为 Squirrel 的跨平台升级版。它支持 Windows、macOS、Linux,底层做了差分更新,还附带生成安装包、发布增量包的命令行工具。它保留了 Squirrel.Windows 的安装和更新体验,同时把平台覆盖面打开了,对 Avalonia、WPF、WinForms、MAUI 都有对应的集成示例。
2.2 我为什么最终倾向 Velopack 这类新方案
如果你只是做一个内部工具,只在 Windows 上跑,那 Squirrel.Windows 完全够用。但客户一旦说“我们需要在 Ubuntu 上跑”,你再用 Squirrel.Windows 就会欲哭无泪。我自己的项目就是用 Avalonia 做界面,目标平台是 Windows 和 Linux,最终选了 Velopack。
Velopack 的发布流程是这样的:先通过 CLI 命令打出一个“稳定版”目录,里面包含对应平台的安装器和更新清单,然后你只需要把整个目录传到 HTTP 服务器或者对象存储上,客户端会定期拉取这个目录下新生成的更新包并应用。它的 update 逻辑内置了差分操作,第一次全量下载,后续只下载二进制差异部分,对带宽紧张的局域网环境特别友好。
我特别在意的一点是:Velopack 的升级是“事务式”的。它会把新版本文件写到一个临时目录,等全部就绪后再切到正式目录。这种设计大幅降低了“升级到一半程序崩溃导致主程序损坏”的概率,这一点在无人值守的服务器环境里太关键了。
2.3 从零接入时的版本管理与渠道划分
选组件只是开始,真正决定体验的是版本管理和发布渠道设计。我在项目里维护了一个简单的三段式版本号:主版本.次版本.修订号。比如 2.4.1。组件会对比客户端当前版本和服务器最新版本,如果服务器版本号高于本地,就触
