H.Test.Upgrade 教程:从零开始学习软件自动更新功能

一、项目概述

H.Test.Upgrade 是一个演示项目,用于展示 软件自动更新 的完整实现。该项目展示了如何实现版本检查、更新提示、下载安装等功能,是构建桌面应用自动更新系统的基础框架。

项目结构

H.Test.Upgrade/
├── App.xaml                     # 应用程序入口
├── App.xaml.cs
├── AssemblyInfo.cs
├── H.Test.Upgrade.csproj        # 项目文件
├── MainWindow.xaml              # 主窗口(核心演示)
└── MainWindow.xaml.cs

核心依赖

依赖项目 作用
H.Modules.Upgrade 更新模块核心
H.Services.Common 公共服务
H.Services.Message 消息服务

二、更新系统架构

2.1 架构层次

更新系统
├── IUpgradeService           # 更新服务接口
│     └── UpdateService       # 更新服务实现
├── IUpgradeOptions           # 更新配置接口
│     └── UpgradeOptions      # 配置实现
├── ShowUpgradeCommand        # 手动检查更新命令
└── UpgradePresenter          # 更新界面演示器

2.2 更新流程

应用启动
    └── ISplashLoadable (可选)
            └── CheckUpdateOnStart == true?
                    ├── 是 → 检查更新
                    │         ├── 有新版本 → 显示更新对话框
                    │         │             ├── 用户确认 → 下载安装
                    │         │             └── 用户取消 → 继续启动
                    │         └── 已是最新 → 继续启动
                    └── 否 → 直接启动

手动检查
    └── ShowUpgradeCommand
            └── 检查更新
                    └── 显示更新对话框

三、更新服务接口

3.1 IUpgradeService

public interface IUpgradeService
{
    bool CanUpgrade(out string message);  // 是否有可用更新
    bool Upgrade(out string message);     // 执行更新
    string UpgradeVersion { get; }        // 最新版本号
}

3.2 UpdateService 核心实现

internal class UpdateService : IUpgradeService, ISplashLoadable
{
    private readonly IOptions<UpgradeOptions> _options;
    private readonly IWebXmlSerializerService _webXmlService;
    
    public UpdateService(IOptions<UpgradeOptions> options, 
                        IWebXmlSerializerService webXmlService)
    {
        this._options = options;
        _webXmlService = webXmlService;
    }
    
    // 获取版本信息
    private VersionData GetVersion(out string message)
    {
        message = null;
        // 从服务器加载更新信息
        UpdateXmlInfo args = _webXmlService.Load<UpdateXmlInfo>(_options.Value.Uri, out message);
        if (args == null)
            return null;
        
        // 比较版本号
        bool isUpdate = new Version(args.Version) > Assembly.GetEntryAssembly().GetName().Version;
        if (!isUpdate)
        {
            message = "当前已经是最新版本";
            return null;
        }
        
        return new VersionData()
        {
            Version = args.Version.ToString(),
            Messages = args.Changelog?.Split(';').ToList(),  // 更新日志
            Uri = args.Url  // 下载地址
        };
    }
}

四、更新配置

4.1 UpgradeOptions

属性 类型 默认值 说明
Uri string - 检查更新的 XML 地址
SavePath string AppPaths.Instance.Version 更新文件保存位置
LoadFormat string “正在下载 {0}/{1}” 下载进度格式
UseIEDownload bool false 是否使用浏览器下载
CheckUpdateOnStart bool true 启动时是否检查更新
AutomaticUpgrade bool true 是否自动安装
NotifyUpgrade bool false 只提醒不自动安装

4.2 更新 XML 文件格式

服务器需要提供一个 XML 文件,格式如下:

<?xml version="1.0" encoding="utf-8"?>
<UpdateXmlInfo>
    <Version>1.0.1.0</Version>      <!-- 新版本号 -->
    <Url>https://example.com/setup.exe</Url>  <!-- 下载地址 -->
    <Changelog>修复bug1;新增功能A;优化性能</Changelog>  <!-- 更新日志 -->
</UpdateXmlInfo>

五、XAML 集成

5.1 主窗口布局

<Window x:Class="H.Test.Upgrade.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:h="https://github.com/HeBianGu"
        Title="MainWindow" Width="800" Height="450">
    <UniformGrid>
        <!-- 设置按钮 -->
        <Button Command="{ShowSettingCommand}"
                Content="设置" />
        
        <!-- 检查更新按钮 -->
        <Button Command="{ShowUpgradeCommand}"
                Content="检查更新" />
    </UniformGrid>
</Window>

5.2 可用命令

命令 说明
ShowSettingCommand 显示设置窗口(可配置更新选项)
ShowUpgradeCommand 手动检查更新

六、服务注册

6.1 扩展方法

public static class Extention
{
    public static void AddAutoUpgrade(this IServiceCollection services, 
                                     Action<IUpgradeOptions> setupAction = null)
    {
        services.AddOptions();
        services.TryAdd(ServiceDescriptor.Singleton<IUpgradeService, UpdateService>());
        services.TryAdd(ServiceDescriptor.Singleton<IWebXmlSerializerService, XmlWebSerializerService>());
        
        if (setupAction != null)
            services.Configure(new Action<UpgradeOptions>(setupAction));
    }
    
    public static void UseUpgrade(this IApplicationBuilder service, Action<UpgradeOptions> action = null)
    {
        action?.Invoke(UpgradeOptions.Instance);
        IocSetting.Instance.Add(UpgradeOptions.Instance);
    }
}

6.2 使用示例

// 在 App.xaml.cs 中
protected override void OnStartup(StartupEventArgs e)
{
    var services = new ServiceCollection();
    
    // 添加更新服务
    services.AddAutoUpgrade(options =>
    {
        options.Uri = "https://example.com/update.xml";  // 更新检查地址
        options.CheckUpdateOnStart = true;               // 启动时检查更新
        options.AutomaticUpgrade = true;                 // 自动安装更新
        options.SavePath = "Updates";                    // 更新文件保存目录
    });
    
    // 使用更新服务
    services.BuildServiceProvider();
}

七、更新流程详解

7.1 版本检查

public bool CanUpgrade(out string message)
{
    VersionData versionData = this.GetVersion(out message);
    return versionData != null;
}

7.2 执行更新

public bool Upgrade(out string message)
{
    message = null;
    VersionData data = this.GetVersion(out message);
    if (data == null)
        return false;
    
    // 显示更新对话框
    bool? r = Application.Current.Dispatcher.Invoke(() =>
    {
        return IocMessage.Dialog.Show(new UpgradePresenter(data), x =>
        {
            x.DialogButton = DialogButton.None;
            x.Width = 500;
            x.Height = 400;
        }).Result;
    });
    
    if (r == false)
    {
        message = "用户取消更新";
        return !data.Force;  // 如果是强制更新,则返回 false
    }
    return true;
}

7.3 启动时自动检查

public bool Load(out string message)
{
    // 如果配置为不检查,则跳过
    if (this._options.Value.CheckUpdateOnStart == false)
    {
        message = "已跳过程序启动时检查更新";
        return true;
    }
    
    // 执行更新检查
    return this.Upgrade(out message);
}

八、手动触发更新

8.1 ShowUpgradeCommand

[Icon("\xECC5")]
[Display(Name = "软件更新", Description = "应用此功能检查软件更新")]
public class ShowUpgradeCommand : DisplayMarkupCommandBase
{
    private IUpgradeService Service => Ioc<IUpgradeService>.Instance;
    
    public override bool CanExecute(object parameter)
    {
        return this.Service != null && base.CanExecute(parameter);
    }
    
    public override async Task ExecuteAsync(object parameter)
    {
        if (this.Service.Upgrade(out string message) == false)
            await IocMessage.ShowDialogMessage(message);
    }
}

8.2 在代码中调用

// 手动触发更新检查
IUpgradeService service = Ioc<IUpgradeService>.Instance;
if (service.CanUpgrade(out string message))
{
    bool success = service.Upgrade(out message);
    if (!success)
    {
        MessageBox.Show(message);
    }
}
else
{
    MessageBox.Show(message);  // "当前已经是最新版本"
}

九、更新界面

9.1 UpgradePresenter

更新对话框展示以下信息:

  • 新版本号
  • 更新日志列表
  • 下载进度
  • 安装按钮

9.2 进度格式

[DefaultValue("正在下载 {0}/{1}")]
public string LoadFormat { get; set; }

{0} - 当前下载字节数
{1} - 总字节数


十、项目运行

10.1 运行方式

  1. 打开解决方案
  2. 右键点击 H.Test.Upgrade 项目
  3. 选择 “设为启动项目”
  4. 按 F5 运行

10.2 界面效果

运行后会看到两个按钮:

  • 设置按钮:打开设置窗口配置更新选项
  • 检查更新按钮:手动触发更新检查

十一、注意事项

11.1 服务器配置

需要在服务器上放置一个 XML 文件,包含版本信息:

<UpdateXmlInfo>
    <Version>1.0.1.0</Version>
    <Url>https://your-server.com/setup.exe</Url>
    <Changelog>更新内容1;更新内容2;更新内容3</Changelog>
</UpdateXmlInfo>

11.2 版本号格式

版本号必须符合 .NET Version 格式:Major.Minor.Build.Revision

例如:1.0.0.0, 1.2.3.4

11.3 下载方式

方式 说明
内置下载 使用应用内置下载器
浏览器下载 使用系统默认浏览器下载 (UseIEDownload = true)

十二、总结

H.Test.Upgrade 展示了软件自动更新系统的完整功能:

  1. 版本检查:从服务器获取版本信息并比较
  2. 自动检查:支持启动时自动检查更新
  3. 手动检查:提供命令手动触发更新检查
  4. 更新对话框:展示更新日志和下载进度
  5. 配置灵活:支持多种配置选项

通过本教程,你应该已经掌握了如何在 WPF 应用中实现自动更新功能。这个框架非常适合构建需要定期更新的桌面应用程序。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐