本指南适用于大多数.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) - 开发人员模式:如果系统提示“开发人员模式”,可以根据需要打开它,但请注意,它需要管理权限
此命令将:
- 将
TargetFramework中的.csproj更新为受支持的 Windows TFM(如果需要) - 将
Microsoft.WindowsAppSDK、Microsoft.Windows.SDK.BuildTools和Microsoft.Windows.SDK.BuildTools.WinAppNuGet 包引用添加到.csproj - 为应用标识创建
Package.appxmanifest和Assets文件夹
注释
与本机/C++ 项目不同,.NET 流程不创建 winapp.yaml 文件。 NuGet 包直接通过你的 .csproj管理。 使用 dotnet restore 在克隆后还原包。
可以打开 Package.appxmanifest 以进一步自定义属性,如显示名称、发布者和功能。
要验证包是否已添加到您的项目中:
dotnet list package
输出中应会显示 Microsoft.WindowsAppSDK 和 Microsoft.Windows.SDK.BuildTools。
添加执行别名(适用于控制台应用)
由于我们正在生成控制台应用,因此需要确保 dotnet run 控制台输出在当前终端中保持。 默认情况下, dotnet run 通过 AUMID 激活启动打包的应用,这会打开一个新窗口,当控制台应用完成时,窗口会立即关闭,吞下任何输出。
若要解决此问题,需要向清单添加执行别名,并告知运行集成通过该别名启动。
如果您正在构建 UI 应用程序(WPF、WinForms、WinUI),请跳过此步骤。 这些应用呈现自己的窗口,因此默认的 AUMID 启动是你想要的。
将执行别名添加到清单文件中:
winapp manifest add-alias这会向
uap5:ExecutionAlias添加一个Package.appxmanifest(默认为您项目的 exe 名称),以便可以通过终端按名称启动应用程序。告诉
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 "$(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 文件将位于当前目录中。
安装证书
在安装 MSIX 包之前,需要安装开发证书。 以管理员身份运行以下命令:
winapp cert install .\devcert.pfx
安装和运行
双击生成的 *.msix 文件安装包。
现在,可以通过键入以下内容从终端中的任意位置运行应用:
dotnet-app
应该看到“程序包系列名称”输出,以确认它已安装并以标识运行。
小窍门
如果需要重新打包应用(例如代码更改后),请在再次运行winapp pack之前,在Package.appxmanifest中递增Version。 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')。