将 winapp CLI 与 .NET 配合使用

本指南适用于大多数.NET项目类型。 这些步骤已使用基于控制台和基于 UI 的项目(如 WPF)进行测试。 有关工作示例,请查看 samples 文件夹中的 dotnet-app(控制台)和 wpf-app(WPF) 示例。

本指南演示如何将 winapp CLI 与 .NET 应用程序配合使用来调试包标识并将应用程序打包为 MSIX。

包标识是Windows app模型中的核心概念。 它允许应用程序访问特定的Windows API(例如通知、安全、AI API 等),具有干净的安装/卸载体验等。

标准可执行文件(如使用 dotnet build创建的可执行文件)没有包标识。 本指南演示如何添加它进行调试,然后将其打包以供分发。

先决条件

  1. .NET SDK:安装.NET SDK(安装后需要重启):

    winget install Microsoft.DotNet.SDK.10 --source winget
    
  2. winapp CLI:通过 winget 安装或更新 winapp 工具(如果已安装)。

    winget install Microsoft.winappcli --source winget
    

1.创建新的.NET应用

首先创建简单的.NET控制台应用程序:

dotnet new console -n dotnet-app
cd dotnet-app

运行它以确保一切正常工作:

dotnet run

输出应为“Hello, World!”

2. 更新代码以检查标识

我们将更新应用,以检查它是否使用包标识运行。 我们将使用Windows 运行时 API 访问包 API。

首先,将项目文件更新为面向特定 Windows SDK 版本。 打开 dotnet-app.csproj,并更改 TargetFramework以包含 Windows SDK 版本:

  <TargetFramework>net10.0-windows10.0.26100.0</TargetFramework>

这样就可以访问Windows 运行时 API,而无需其他包。

现在,请将 Program.cs 以下内容的内容替换为以下代码。 此代码尝试使用 Windows 运行时 API 检索当前包标识。 如果成功,则会打印包系列名称;否则,它将打印“未打包”。

using Windows.ApplicationModel;

try
{
    var package = Package.Current;
    var familyName = package.Id.FamilyName;
    Console.WriteLine($"Package Family Name: {familyName}");
}
catch (InvalidOperationException)
{
    // Thrown when app doesn't have package identity
    Console.WriteLine("Not packaged");
}

3.在没有标识的情况下运行

现在,像往常一样运行应用:

dotnet run

应会看到输出“未打包”。 这确认标准可执行文件在没有任何包标识的情况下正在运行。

4.使用 winapp CLI 初始化Project

winapp init 命令自动检测 .csproj 文件,并运行特定于.NET的设置。 它一次性设置所需的一切:验证 TargetFramework、添加所需的 NuGet 包、生成应用清单和资产。

运行以下命令并按照提示操作:

winapp init

出现提示时:

  • 包名称:按 Enter 接受默认 (dotnet-app)
  • 发布者名称:按 Enter 接受默认值或输入名称
  • 版本:按 Enter 接受 1.0.0.0
  • Description:按 Enter 接受默认(Windows应用程序)或输入说明
  • Windows 应用 SDK 安装程序:选择“稳定”、“预览”或“实验”(确定添加哪个Windows 应用 SDK版本)
  • TargetFramework update:如果 TargetFramework不包含受支持的Windows SDK 版本,系统会提示更新它(例如,将更新为 net10.0-windows10.0.26100.0
  • 开发人员模式:如果系统提示“开发人员模式”,可以根据需要打开它,但请注意,它需要管理权限

此命令将:

  • TargetFramework 中的 .csproj 更新为受支持的 Windows TFM(如果需要)
  • Microsoft.WindowsAppSDKMicrosoft.Windows.SDK.BuildToolsMicrosoft.Windows.SDK.BuildTools.WinApp NuGet 包引用添加到 .csproj
  • 为应用标识创建 Package.appxmanifestAssets 文件夹

注释

与本机/C++ 项目不同,.NET 流程创建 winapp.yaml 文件。 NuGet 包直接通过你的 .csproj管理。 使用 dotnet restore 在克隆后还原包。

可以打开 Package.appxmanifest 以进一步自定义属性,如显示名称、发布者和功能。

要验证包是否已添加到您的项目中:

dotnet list package

输出中应会显示 Microsoft.WindowsAppSDKMicrosoft.Windows.SDK.BuildTools

添加执行别名(适用于控制台应用)

由于我们正在生成控制台应用,因此需要确保 dotnet run 控制台输出在当前终端中保持。 默认情况下, dotnet run 通过 AUMID 激活启动打包的应用,这会打开一个新窗口,当控制台应用完成时,窗口会立即关闭,吞下任何输出。

若要解决此问题,需要向清单添加执行别名,并告知运行集成通过该别名启动。

如果您正在构建 UI 应用程序(WPF、WinForms、WinUI),请跳过此步骤。 这些应用呈现自己的窗口,因此默认的 AUMID 启动是你想要的。

  1. 将执行别名添加到清单文件中:

    winapp manifest add-alias
    

    这会向 uap5:ExecutionAlias 添加一个 Package.appxmanifest(默认为您项目的 exe 名称),以便可以通过终端按名称启动应用程序。

  2. 告诉dotnet run集成使用别名。 请打开dotnet-app.csproj,然后在任何<PropertyGroup>中添加以下内容(或根据需要创建新的<PropertyGroup>):

    <WinAppRunUseExecutionAlias>true</WinAppRunUseExecutionAlias>
    

    设置此属性后, dotnet run 通过其执行别名启动应用,并继承当前终端的 stdin/stdout/stderr,以便你看到控制台输出内联。

使用身份进行调试

由于 winapp init向项目添加了 Microsoft.Windows.SDK.BuildTools.WinApp NuGet 包,因此只需运行:

dotnet run

这会自动在后台调用 winapp run — 创建松散的布局包,将其注册到Windows,并使用完整的包标识启动应用。

注释

你可能会看到有关包源的 NuGet 漏洞警告(NU1900)。 这些可以忽略不计,它们不会影响你的构建。

此时会看到与下面类似的输出:

Package Family Name: dotnet-app_12345abcde

这确认你的应用正在运行,并具有有效的包标识!

替代方法:手动 winapp run

如果未使用 winapp init (或删除 NuGet 包),可以手动生成和运行:

dotnet build -c Debug
winapp run .\bin\Debug\net10.0-windows10.0.26100.0

若要将 NuGet 包添加回:dotnet add package Microsoft.Windows.SDK.BuildTools.WinApp --prerelease

小窍门

若要禁用自动 dotnet run 集成,请将 <EnableWinAppRunSupport>false</EnableWinAppRunSupport> 添加到您的 .csproj。 有关自定义选项 ,请参阅 dotnet run 支持文档

替代方法:稀疏包标识

如果您需要特定的稀疏包行为(标识而不复制文件),可以改用 create-debug-identity 。 这会注册一个稀疏包,该包指向您的 exe,而不是创建松散布局。

winapp create-debug-identity .\bin\Debug\net10.0-windows10.0.26100.0\dotnet-app.exe

然后直接运行可执行文件(不要使用 dotnet run,因为它可能会重新生成或覆盖文件):

.\bin\Debug\net10.0-windows10.0.26100.0\dotnet-app.exe

替代方法:手动 MSBuild 目标

如果不想使用 NuGet 包,可以添加一个自定义 MSBuild 目标,使其在调试生成后运行 create-debug-identity。 请将此添加到你的 .csproj 文件末尾,就在关闭的 </Project> 标记之前:

  <!-- Automatically apply debug identity after Debug builds -->
  <Target Name="ApplyDebugIdentity" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
    <Exec Command="winapp create-debug-identity &quot;$(TargetDir)$(TargetName).exe&quot;" 
          WorkingDirectory="$(ProjectDir)" 
          IgnoreExitCode="false" />
  </Target>

使用此配置, dotnet build 应用调试标识,可以直接运行可执行文件。 请注意,dotnet run 可能会重新生成并覆盖身份,因此在生成后需手动运行 exe。

小窍门

有关高级调试工作流(附加调试器、IDE 设置、启动调试),请参阅 调试指南

何时跳过此策略:如果你更喜欢显式控制何时应用标识,或者如果你正在处理在开发周期的大部分时间不需要标识的代码,则上述手动方法可能更简单。

6. 使用 Windows 应用 SDK (可选)

Windows 应用 SDK允许您访问超出基础Windows SDK提供的新型Windows API,包括通知系统、窗口 API、应用生命周期管理以及设备端 AI。 如果你的应用需要这些功能中的任何一项,则此步骤适合你。 如果您只需要分发包标识,可以跳到步骤 7。

如果运行了 winapp init (步骤 4),Microsoft.WindowsAppSDK已添加为对 .csproj 的 NuGet 包引用。 可以验证 dotnet list package。 如果在 init 期间跳过了 SDK 设置,或者需要手动添加它,请运行:

dotnet add package Microsoft.WindowsAppSDK

更新 Program.cs

Program.cs 的全部内容替换为以下代码,这将添加Windows 应用运行时版本检查:

using Windows.ApplicationModel;

class Program
{
    static void Main(string[] args)
    {
        try
        {
            var package = Package.Current;
            var familyName = package.Id.FamilyName;
            Console.WriteLine($"Package Family Name: {familyName}");
            
            // Get Windows App Runtime version using the API
            var runtimeVersion = Microsoft.Windows.ApplicationModel.WindowsAppRuntime.RuntimeInfo.AsString;
            Console.WriteLine($"Windows App Runtime Version: {runtimeVersion}");
        }
        catch (InvalidOperationException)
        {
            // Thrown when app doesn't have package identity
            Console.WriteLine("Not packaged");
        }
    }
}

构建和运行

使用Windows 应用 SDK重新生成并运行应用程序。 由于我们添加了 WinAppSDK,因此需要重新注册身份,以便 winapp 可以添加运行时依赖项。 如果添加了 WinApp NuGet 包(建议),只需运行 dotnet run。 否则(将 dotnet-app 替换为您的项目名称):

dotnet build -c Debug
winapp run .\bin\Debug\net10.0-windows10.0.26100.0

现在应会看到如下所示的输出:

Package Family Name: dotnet-app.debug_12345abcde
Windows App Runtime Version: 8000.770.947.0

Windows 应用 SDK NuGet 包包括访问新式Windows API 所需的所有程序集,包括:

  • 通知和动态磁贴
  • 窗口化和应用生命周期
  • 推送通知
  • 以及更多的 Windows 应用 SDK 组件

有关更高级Windows 应用 SDK用法,请查看 Windows 应用 SDK 文档

7. 使用 MSIX 打包

准备好分发应用后,可以使用同一清单将其打包为 MSIX。

为发布构建

首先,在发布模式下生成应用程序以实现最佳性能:

dotnet build -c Release

注释

你可能会看到 NuGet 漏洞警告(NU1900)。 可以放心地忽略这些内容,并且不会影响生成输出。

生成开发证书

在打包之前,您需要一个用于签名的开发证书。 如果尚未生成一个:

winapp cert generate --if-exists skip

签名和打包

现在可以打包和签名。 将 pack 命令指向构建输出文件夹(将dotnet-app 和 TFM 路径替换为项目的值):

# package and sign the app with the generated certificate
winapp pack .\bin\Release\net10.0-windows10.0.26100.0 --manifest .\Package.appxmanifest --cert .\devcert.pfx 

注意:此命令 pack 会自动使用当前目录中的 Package.appxmanifest,并在打包之前将其复制到目标文件夹。 生成的 .msix 文件将位于当前目录中。

安装证书

在安装 MSIX 包之前,需要安装开发证书。 以管理员身份运行以下命令:

winapp cert install .\devcert.pfx

安装和运行

双击生成的 *.msix 文件安装包。

现在,可以通过键入以下内容从终端中的任意位置运行应用:

dotnet-app

应该看到“程序包系列名称”输出,以确认它已安装并以标识运行。

小窍门

如果需要重新打包应用(例如代码更改后),请在再次运行winapp pack之前,在Package.appxmanifest中递增Version。 Windows需要更高的版本号才能更新已安装的包。

提示

  1. 准备好分发后,可以使用证书颁发机构的代码签名证书对 MSIX 进行签名,以便用户无需安装自签名证书。
  2. Microsoft Store将为你签名 MSIX,无需在提交之前进行签名。
  3. 您可能需要为每个支持的体系结构(x64, Arm64)分别创建一个 MSIX 包。 使用 -r 标志结合 dotnet build 针对特定的体系结构:dotnet build -c Release -r win-x64dotnet build -c Release -r win-arm64

自动化 MSIX 打包(可选)

若要在发布版本中自动执行 MSIX 打包,请将此目标添加到 .csproj 文件(可以将其与调试标识目标一起添加):

  <!-- Automatically package as MSIX after Release builds -->
  <Target Name="PackageMsix" AfterTargets="Build" Condition="'$(Configuration)' == 'Release'">
    <!-- Package and sign directly from build output -->
    <Exec Command="winapp pack &quot;$(TargetDir.TrimEnd('\'))&quot; --cert &quot;$(ProjectDir)devcert.pfx&quot;" 
          WorkingDirectory="$(ProjectDir)" 
          IgnoreExitCode="false" />
  </Target>

使用此配置时:

  • 在“发布模式”下进行构建(dotnet build -c Release)时,将自动创建 MSIX 包
  • MSIX 已打包并使用开发证书进行签名
  • 最终 .msix 文件将位于项目的根目录中

还可以通过将条件修改为PackagedRelease创建自定义配置(例如'$(Configuration)' == 'PackagedRelease')。

后续步骤

  • 通过 winget 分发:将 MSIX 提交到 Windows 程序包管理器 社区存储库
  • 发布到 Microsoft Store:使用 winapp store 提交包
  • 设置 CI/CD:使用 GitHub Action 在流水线中自动打包
  • 探索 Windows APIs:使用包标识,现在可以使用通知设备端 AI和其他身份依赖的 API