本指南适用于大多数.NET项目类型。 这些步骤已使用基于控制台和基于 UI 的项目(如 WPF)进行测试。 有关工作示例,请查看 samples 文件夹中的 dotnet-app(控制台)和 wpf-app(WPF) 示例。
本指南演示如何将 winapp CLI 与 .NET 应用程序配合使用来调试包标识并将应用程序打包为 MSIX。
包标识是Windows app模型中的核心概念。 它允许应用程序访问特定的Windows API(例如通知、安全、AI API 等),具有干净的安装/卸载体验等。
标准可执行文件(如使用 dotnet build创建的可执行文件)没有包标识。 本指南演示如何添加它进行调试,然后将其打包以供分发。
先决条件
.NET SDK:安装.NET SDK(安装后需要重启):
winget install Microsoft.DotNet.SDK.10 --source wingetwinapp 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) - 开发人员模式:如果系统提示“开发人员模式”,可以根据需要打开它,但请注意,它需要管理权限
此命令将:
- 将
.csproj中的TargetFramework更新为受支持的 Windows TFM(如果需要) - 将
Microsoft.WindowsAppSDK、Microsoft.Windows.SDK.BuildTools和Microsoft.Windows.SDK.BuildTools.WinAppNuGet 包引用添加到.csproj - 为应用标识创建
Package.appxmanifest和Assets文件夹
注释
与本机/C++ 项目不同,.NET 流程不创建 winapp.yaml 文件。 NuGet 包直接通过你的 .csproj 管理。 克隆后,运行 winapp restore 或 dotnet restore。
可以打开 Package.appxmanifest 以进一步自定义属性,如显示名称、发布者和功能。
要验证包是否已添加到您的项目中:
dotnet list package
输出中应会显示 Microsoft.WindowsAppSDK 和 Microsoft.Windows.SDK.BuildTools。
控制台输出(不执行任何操作)
由于我们正在构建控制台应用,因此控制台输出需要保留在当前终端中。 AUMID 激活方式不会为打包应用分配控制台,因此控制台应用程序虽然可以正常运行,但不会输出任何内容。
winapp 会为你处理这一点:带有 OutputType=Exe 的应用程序会改为通过执行别名启动,并继承你的终端的 stdin/stdout/stderr。 它会将所需的 uap5:ExecutionAlias 添加到其暂存的清单中,因此无需进行任何配置。
UI 应用(WPF,WinForms,WinUI)呈现自己的窗口,以便保持 AUMID 激活。
若仍要为控制台应用强制设置 AUMID,请在 dotnet-app.csproj 中任意一个 <PropertyGroup> 内设置以下内容——随后,该应用将在没有控制台的情况下运行,并且不会向终端输出任何内容:
<WinAppRunUseExecutionAlias>false</WinAppRunUseExecutionAlias>
如果你想自己选择命令名称,请运行 winapp manifest add-alias,在 Package.appxmanifest 中声明一个命令名称;你创建的别名将按原样使用。
使用身份进行调试
由于 winapp init向项目添加了 Microsoft.Windows.SDK.BuildTools.WinApp NuGet 包,因此只需运行:
dotnet run
这会自动在后台调用 winapp run — 创建松散的布局包,将其注册到Windows,并使用完整的包标识启动应用。
在 之后编写的参数会传递给dotnet run,与项目未引用此包时完全相同:
dotnet run --devtools # your app receives --devtools
dotnet run -- --devtools # identical: the SDK consumes the -- before forwarding
使用 --framework,当你的应用的标记也是一个 --project 选项(-c、-f、-r、--、--configuration、dotnet run 等)时尤其如此——否则 SDK 会占用该令牌,你的应用将永远收不到它:
dotnet run -- --configuration Release # your app receives --configuration Release
使用 WinAppRun* MSBuild 属性配置 WinApp 启动器本身。 MSBuild 使用这些资源,因此它们永远不会访问应用程序:
dotnet run -p:WinAppRunDebugOutput=true --devtools
此处,该属性用于配置 WinApp,而 --devtools 会传递给你的应用。 请参阅dotnet run对完整属性列表的支持,包括无法组合哪些属性。
注释
你可能会看到有关包源的 NuGet 漏洞警告(NU1900)。 这些可以安全忽略 — 它们不影响你的构建。
此时会看到与下面类似的输出:
Package Family Name: dotnet-app_12345abcde
这确认你的应用正在运行,并具有有效的包标识!
替代方法:手动 winapp run
如果未使用 winapp init (或删除 NuGet 包),可以手动生成和运行。
winapp run 直接接受项目 (项目模式) - 它生成 .csproj 并启动它,因此不必指向生成输出文件夹或单独生成:
# Build and run the project in one step (project mode)
winapp run .
# ...or run a specific project / configuration / architecture
winapp run .\dotnet-app.csproj -c Debug --arch x64
若要运行项目的原生 AOT 配置,请在项目中启用 AOT并运行:
winapp run . --aot
winapp run . --aot -c Release
使用 x64 或 ARM64。 如需一次性覆盖,请附加 -p PublishAot=true。
如果你愿意,仍然可以将 winapp run 指向一个预先构建好的输出文件夹(文件夹模式):
dotnet build -c Debug
winapp run .\bin\Debug\net10.0-windows10.0.26100.0
项目模式同时支持 打包 和 未打包 的 WinUI 应用——它会根据项目的 WindowsPackageType 检测应用属于哪种类型,并自动安装与其架构匹配的 Windows 应用 Runtime。 若要强制解压缩运行打包的项目,请添加 -p WindowsPackageType=None。
多项目应用(引用类库的应用)可正确生成:winapp 会在其兼容的平台上保留 AnyCPU/netstandard2.0 引用,而不是将应用的体系结构强加到整个依赖关系图中。 仅 RID 保留默认值;如果有效配置需要自包含配置文件(例如,经过剪裁的发布版本),winapp 会选择匹配的配置文件,而不会更改所引用库的平台。
dotnet build 输出流是实时的,首先打印确切的调用。 添加 --verbose 以用于 winapp 自身的构建决策跟踪信息。 需要.NET SDK 8.0.100 或更高版本。 有关完整选项列表,请参阅winapp run使用参考。
未安装Windows SDK? C#/WinRT 创作项目通常需要注册的Windows SDK 才能生成。 当项目模式检测不到任何项目(洁净 CI、容器、无 SDK 的开发箱)时,它会将 cswinrt 指向自动还原的
Microsoft.Windows.SDK.NET.Ref包中的 winmds,因此构建仍然成功 – 不需要任何操作。 在安装 SDK 或自行设置-p CsWinRTWindowsMetadata=…时,它不执行任何操作。
要重新添加 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 "$(TargetDir)$(TargetName).exe""
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 文件将位于当前目录中。
提示:还可以跳过直接从项目查找生成输出文件夹和包 —
winapp package .\dotnet-app.csproj --cert .\devcert.pfx在一个步骤中发布项目并打包其输出(项目模式默认为发布配置)。 项目模式支持以下构建选项:-c、--arch、-f、--no-build、--no-restore、-p;添加--no-build可在不重新构建的情况下打包现有构建。
安装证书
在安装 MSIX 包之前,需要安装开发证书。 以管理员身份运行以下命令:
winapp cert install .\devcert.pfx
安装和运行
双击生成的 *.msix 文件安装包。
现在,可以通过键入以下内容从终端中的任意位置运行应用:
dotnet-app
你应该看到“Package Family Name”输出,确认它已安装并使用标识运行。
小窍门
如果需要重新打包应用(例如代码更改后),请在再次运行Version之前,在Package.appxmanifest中递增winapp pack。 Windows需要更高的版本号才能更新已安装的包。
提示
- 准备好分发后,可以使用证书颁发机构的代码签名证书对 MSIX 进行签名,以便用户无需安装自签名证书。
- Microsoft Store将为你签名 MSIX,无需在提交之前进行签名。
- 您可能需要为每个支持的体系结构(x64, Arm64)分别创建一个 MSIX 包。 将
-r标志与dotnet build一起使用以面向特定体系结构:dotnet build -c Release -r win-x64或dotnet 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 "$(TargetDir.TrimEnd('\'))" --cert "$(ProjectDir)devcert.pfx""
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 API:具有包标识,你现在可以使用通知、设备端 AI 和其他依赖标识的 API