跳到主要内容

🚀 GeneralUpdate 集成完全指南

帮助开发者在任意 .NET 应用中集成 GeneralUpdate 自动更新。从零开始,不需要提前了解 GeneralUpdate 的内部细节。


先理解:为什么更新需要两个程序?

GeneralUpdate 采用双进程架构,这是理解一切配置的前提:

你的 App.exe (Client —— 主程序)

├── 平时:正常运行你的业务逻辑

├── 发现新版本时:
│ 1. 下载更新包
│ 2. 把下载信息写成 IPC 文件(一种临时文件)
│ 3. 启动 "升级程序"(UpgradeApp.exe)
│ 4. 自己退出(因为 Windows 不允许程序覆盖自己)


UpgradeApp.exe (Upgrade —— 升级程序)

├── 读取 IPC 文件
├── 解压/替换文件(此时主程序已退出,文件不占用)
├── 启动主程序
└── 自己退出

IPC 文件(Inter-Process Communication)= 临时通讯文件,Client 把下载好的更新信息写进去,Upgrade 读出来执行更新。

manifest.json = 更新清单文件,告诉 GeneralUpdate 你的主程序叫什么、升级程序在哪。

这种设计的原因很简单:Windows 不允许正在运行的程序覆盖自己的 .exe 文件,所以需要一个"替身"来完成替换工作。


你需要准备什么?

1. 你的 .NET 项目(WPF / WinForms / Avalonia / MAUI / 控制台 都可以)
2. .NET SDK(8.0+)
3. 一个后端服务(可选)—— 没有后端也可以用 OSS 对象存储

安装 NuGet

dotnet add package GeneralUpdate.Core --version 10.5.0-beta.7

如果要用崩溃守护(Bowl),再加一个包:dotnet add package GeneralUpdate.Bowl --version 10.5.0-beta.7
差分更新功能已经内置在 Core 里,不需要额外装 GeneralUpdate.Differential


最低配置:3 行代码跑起来

这是最简单的集成方式,适用于控制台应用或想先验证功能:

using GeneralUpdate.Core;
using GeneralUpdate.Core.Configuration;

var config = new UpdateRequest
{
UpdateUrl = "https://your-server.com/api", // 服务端地址
AppSecretKey = "your-secret-key", // 密钥(长度 ≥ 16 字符)
MainAppName = "MyApp.exe", // 你的主程序文件名
ClientVersion = "1.0.0.0", // 当前版本号
ProductId = "my-product-001", // 你的产品 ID
InstallPath = "." // 安装目录(. 表示当前目录)
};

await new GeneralUpdateBootstrap().SetConfig(config).LaunchAsync();

这 6 个字段是 UpdateRequest 的必填项,少一个都会报错:

字段填什么为什么需要
UpdateUrl服务端 API 地址程序从这里查询有没有新版本
AppSecretKey你设定的密钥用于 IPC 加密通讯,Client 和 Upgrade 必须一致
MainAppName"MyApp.exe"告诉升级程序"更新完要启动哪个 exe"
ClientVersion"1.0.0.0"服务端根据这个判断哪些版本需要更新给你
ProductId"my-app-001"区分不同产品(如果你有多个应用)
InstallPath"."更新包解压到哪个目录

完整配置:带事件监听

如果你想看到更新进度、处理错误、做日志,加上事件监听:

using GeneralUpdate.Core;
using GeneralUpdate.Core.Configuration;
using GeneralUpdate.Core.Download;

var config = new UpdateRequest
{
UpdateUrl = "https://your-server.com/Upgrade/Verification",
AppSecretKey = "your-secret-key",
MainAppName = "MyApp.exe",
ClientVersion = "1.0.0.0",
ProductId = "my-product-001",
InstallPath = AppDomain.CurrentDomain.BaseDirectory, // 生产环境用这个
};

await new GeneralUpdateBootstrap()
.SetConfig(config)
.AddListenerUpdateInfo((_, e) =>
{
// 有更新时触发
Console.WriteLine($"发现 {e.Info?.Body?.Count ?? 0} 个新版本");
})
.AddListenerMultiDownloadStatistics((_, e) =>
{
// 下载进度(可绑定到进度条)
Console.WriteLine($"进度: {e.ProgressPercentage}% | 速度: {e.Speed}");
})
.AddListenerMultiDownloadCompleted((_, e) =>
{
Console.WriteLine($"版本 {e.Version} 下载完成");
})
.AddListenerMultiDownloadError((_, e) =>
{
Console.WriteLine($"下载失败: {e.Exception?.Message}");
})
.AddListenerMultiAllDownloadCompleted((_, e) =>
{
Console.WriteLine("全部下载完成,即将开始更新");
})
.AddListenerException((_, e) =>
{
Console.WriteLine($"异常: {e.Message}");
})
.AddListenerProgress((_, e) =>
{
// v10.5.0-beta.7 新增的第 7 个事件
})
.LaunchAsync();

通常你只需要关注 3 个事件MultiDownloadStatistics(进度条)、MultiDownloadError(下载失败)、Exception(异常)。其他事件按需添加。


UpdateRequest 完整配置说明

除了 6 个必填字段,还有这些可选配置:

var config = new UpdateRequest
{
// === 必填(上面已经列出了) ===
UpdateUrl = "...", AppSecretKey = "...", MainAppName = "...",
ClientVersion = "1.0.0.0", ProductId = "...", InstallPath = ".",

// === 可选:认证方式 ===
AuthScheme = AuthScheme.Hmac, // Hmac / Bearer / ApiKey / Basic
Token = "your-token",
BasicUsername = "user",
BasicPassword = "pass",

// === 可选:备份时排除的文件 ===
Files = new List<string> { "*.log", "*.tmp" }, // 排除日志/临时文件
Formats = new List<string> { ".pdb" }, // 排除调试符号文件
Directories = new List<string> { "logs", "cache" }, // 排除整个目录
};

也可以使用建造者模式(效果一样,写法更流畅):

var config = UpdateRequestBuilder.Create()
.SetUpdateUrl("https://your-server.com/api")
.SetAppSecretKey("your-secret-key")
.SetMainAppName("MyApp.exe")
.SetClientVersion("1.0.0.0")
.SetProductId("my-product-001")
.SetInstallPath(".")
.Build();

或者零配置模式(从 manifest.json 自动发现,更简洁):

await new GeneralUpdateBootstrap()
.SetSource(
updateUrl: "https://your-server.com/api",
appSecretKey: "your-secret-key")
.AddListenerUpdateInfo(...)
.LaunchAsync();

4 大更新场景(服务端返回什么)

GeneralUpdate 根据服务端返回的更新包类型自动选择动作:

场景发生了什么
None无需更新 → 直接启动主程序
UpgradeOnly只更新升级程序自身 → 主程序原地解压覆盖升级程序
MainOnly只更新主程序 → Client 下载 → IPC → 启动 Upgrade 替换主程序
Both两者都更新

Upgrade 进程配置

Upgrade(升级程序)不需要填配置,它从 IPC 文件自动读取:

using GeneralUpdate.Core;

await new GeneralUpdateBootstrap()
.AddListenerException((_, e) =>
Console.WriteLine($"错误: {e.Message}"))
.LaunchAsync();

你的项目里需要两个独立的项目:一个 Client(主程序),一个 Upgrade(升级程序)。


部署结构检查清单

发布后你的目录应该长这样:

publish/
├── MyApp.exe ← 你的主程序
├── generalupdate.manifest.json ← 更新清单(告诉 GeneralUpdate 升级程序在哪)
└── update/
└── UpgradeApp.exe ← 升级程序(首个版本就必须有!)

首次部署时最常见的错误就是忘了放 UpgradeApp.exe,导致检测到更新后无法执行升级。


应用角色说明

AppType 区分两个进程的角色:

枚举谁在用
1AppType.Client主程序(你的业务代码)
2AppType.Upgrade升级程序(UpgradeApp.exe)
3AppType.OssClientOSS 模式的主程序
4AppType.OssUpgradeOSS 模式的升级程序

新手常见错误

#错误后果正确做法
1Client 和 Upgrade 用了不同版本的 NuGet 包运行时报 Method not found两个项目用完全一样的版本号
2忘了放 UpgradeApp.exe检测到更新但无法执行从第一个版本就放入 update/ 目录
3IPC 文件编码没设 UTF-8Linux/macOS 中文乱码设置 Encoding.UTF8
4版本号不是 4 段式(如 1.0版本比较出错始终用 1.0.0.0 格式
5manifest.json 写的 exe 名不对更新后找不到主程序和实际文件名完全一致

下一步