name: dotnet-msix description: “打包 MSIX 应用程序。创建、签名、商店提交、App Installer 侧载、自动更新。” user-invocable: false
dotnet-msix
.NET 桌面应用程序的 MSIX 打包管道:从 csproj(WindowsPackageType)和 WAP 项目创建包,证书签名(开发用自签名,生产用受信任 CA,Microsoft Store 签名),分发渠道(Microsoft Store 提交、App Installer 侧载、通过 SCCM/Intune 进行企业部署),自动更新配置(App Installer XML、版本检查、差异更新),多架构的 MSIX 捆绑格式(.msixbundle),以及 CI/CD MSIX 构建步骤。
版本假设: Windows App SDK 1.6+(当前稳定版)。MSIX 与 Windows App SDK 要求 Windows 10 build 19041+ 最低。App Installer 自动更新协议要求 Windows 10 build 1709+。.NET 8.0+ 基线。
范围
- 从 csproj 和 WAP 项目创建包
- 证书签名(自签名、受信任 CA、Store 签名)
- Microsoft Store 提交工作流
- App Installer 侧载和自动更新配置
- 多架构的 MSIX 捆绑格式
- CI/CD MSIX 构建步骤
不在范围内
- WinUI 3 项目设置和 MSIX 与未打包比较 – 参见 [skill:dotnet-winui]
- 原生 AOT MSBuild 配置 – 参见 [skill:dotnet-native-aot]
- 通用 CI/CD 管道模式 – 参见 [skill:dotnet-gha-patterns] 和 [skill:dotnet-ado-patterns]
- 通用 NuGet 打包 – 参见 [skill:dotnet-nuget-authoring]
- 基于容器的部署 – 参见 [skill:dotnet-containers]
交叉引用:WinUI 项目设置和打包模式比较参见 [skill:dotnet-winui],AOT + MSIX 场景参见 [skill:dotnet-native-aot],CI 管道结构参见 [skill:dotnet-gha-patterns],ADO 管道结构参见 [skill:dotnet-ado-patterns],NuGet 打包参见 [skill:dotnet-nuget-authoring]。
MSIX 包创建
从 csproj(单项目打包)
现代 WinUI 3 和 Windows App SDK 应用可以直接从应用程序 .csproj 生成 MSIX 包,无需单独的 Windows Application Packaging(WAP)项目。
<!-- MyApp.csproj -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<UseWinUI>true</UseWinUI>
<!-- MSIX 打包模式 -->
<WindowsPackageType>MSIX</WindowsPackageType>
<!-- 包身份 -->
<AppxPackageDir>$(SolutionDir)AppPackages\</AppxPackageDir>
<GenerateAppxPackageOnBuild>false</GenerateAppxPackageOnBuild>
</PropertyGroup>
</Project>
构建 MSIX 包:
# 构建 MSIX 包
dotnet publish --configuration Release --runtime win-x64 \
/p:GenerateAppxPackageOnBuild=true \
/p:AppxPackageSigningEnabled=false
# 输出:AppPackages\MyApp_1.0.0.0_x64.msix
WAP 项目(桌面桥)
对于非 WinUI 桌面应用(WPF、WinForms),使用 Windows Application Packaging Project 将现有应用包装为 MSIX。WAP 项目(.wapproj)通过 Visual Studio “Windows Application Packaging Project” 模板创建 – 它们使用专门的项目格式,而非标准 Microsoft.NET.Sdk。
关键配置是引用桌面应用项目:
<!-- MyApp.Package.wapproj(通过 VS 模板创建) -->
<!-- 生成的 .wapproj 文件中的关键元素: -->
<ItemGroup>
<!-- 引用桌面应用项目以包含在 MSIX 中 -->
<ProjectReference Include="..\MyWpfApp\MyWpfApp.csproj" />
</ItemGroup>
<!-- 在 .wapproj PropertyGroup 中设置目标平台版本 -->
<PropertyGroup>
<TargetPlatformVersion>10.0.22621.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<DefaultLanguage>en-US</DefaultLanguage>
<AppxPackageDir>$(SolutionDir)AppPackages\</AppxPackageDir>
</PropertyGroup>
Package.appxmanifest
清单定义身份、能力和视觉资产:
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
<Identity Name="MyCompany.MyApp"
Publisher="CN=My Company, O=My Company, L=Seattle, S=WA, C=US"
Version="1.0.0.0"
ProcessorArchitecture="x64" />
<Properties>
<DisplayName>My App</DisplayName>
<PublisherDisplayName>My Company</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop"
MinVersion="10.0.19041.0"
MaxVersionTested="10.0.22621.0" />
</Dependencies>
<Resources>
<Resource Language="en-us" />
</Resources>
<Applications>
<Application Id="App"
Executable="MyApp.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements DisplayName="My App"
Description="My application description"
BackgroundColor="transparent"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>
证书签名
所有 MSIX 包必须在 Windows 上签名才能安装。签名证书的主题必须与包清单中的 Publisher 属性匹配。
自签名证书(开发)
# 为开发创建自签名证书
$cert = New-SelfSignedCertificate `
-Type Custom `
-Subject "CN=My Company, O=My Company, L=Seattle, S=WA, C=US" `
-KeyUsage DigitalSignature `
-FriendlyName "MyApp 开发签名" `
-CertStoreLocation "Cert:\CurrentUser\My" `
-TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3", `
"2.5.29.19={text}")
# 导出 PFX 供 CI 使用
$password = ConvertTo-SecureString -String "$env:CERT_PASSWORD" -Force -AsPlainText
Export-PfxCertificate -Cert $cert `
-FilePath "MyApp_DevSigning.pfx" `
-Password $password
# 动态查找 signtool.exe(SDK 版本因机器而异)
$signtool = Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\bin\*\x64\signtool.exe" |
Sort-Object { [version]($_.Directory.Parent.Name) } -Descending |
Select-Object -First 1 -ExpandProperty FullName
# 签名 MSIX 包
& $signtool sign /fd SHA256 /a /f "MyApp_DevSigning.pfx" `
/p "$env:CERT_PASSWORD" `
"AppPackages\MyApp_1.0.0.0_x64.msix"
受信任 CA 证书(生产)
对于 Microsoft Store 之外的生产分发:
- 从受信任 CA(DigiCert、Sectigo、GlobalSign)获取代码签名证书
- 主题必须匹配
Package.appxmanifest中的Publisher - 时间戳签名 以确保长期有效性
# 使用受信任 CA 证书签名(从证书存储)
& signtool.exe sign /fd SHA256 /sha1 "THUMBPRINT_HERE" `
/tr http://timestamp.digicert.com /td SHA256 `
"AppPackages\MyApp_1.0.0.0_x64.msix"
# 使用 PFX 文件签名
& signtool.exe sign /fd SHA256 /f "production-cert.pfx" `
/p "$env:CERT_PASSWORD" `
/tr http://timestamp.digicert.com /td SHA256 `
"AppPackages\MyApp_1.0.0.0_x64.msix"
Microsoft Store 签名
提交到 Microsoft Store 的应用在入库时由 Microsoft 重新签名。开发签名证书被 Microsoft 颁发的证书替换。仅限 Store 分发不需要生产签名证书。
<!-- 对于 Store 提交,在开发期间使用测试证书 -->
<PropertyGroup>
<AppxPackageSigningEnabled>true</AppxPackageSigningEnabled>
<PackageCertificateThumbprint>AUTO_GENERATED_BY_VS</PackageCertificateThumbprint>
</PropertyGroup>
证书要求摘要
| 分发 | 证书类型 | 需要受信任 CA |
|---|---|---|
| 开发/测试 | 自签名 | 否(手动安装证书) |
| 企业侧载 | 自签名或内部 CA | 否(通过组策略部署证书) |
| 直接下载 | 受信任 CA(如 DigiCert) | 是 |
| Microsoft Store | 测试证书(由 MS 重新签名) | 否 |
分发渠道
Microsoft Store 提交
- 在 Partner Center(https://partner.microsoft.com/dashboard)注册为 Windows 开发者
- 创建应用预订 以保留应用名称
- 构建与 Store 关联的 MSIX 包:
# 构建用于 Store 提交(创建 .msixupload)
dotnet publish --configuration Release --runtime win-x64 \
/p:GenerateAppxPackageOnBuild=true \
/p:UapAppxPackageBuildMode=StoreUpload \
/p:AppxBundle=Auto
- 通过 Partner Center 提交
.msixupload文件 - Microsoft 验证、签名并发布应用
App Installer 侧载
App Installer(.appinstaller)支持直接分发和自动更新。将文件托管在 Web 服务器、网络共享或 CDN 上。
<!-- MyApp.appinstaller -->
<?xml version="1.0" encoding="utf-8"?>
<AppInstaller Uri="https://mycompany.com/apps/MyApp.appinstaller"
Version="1.0.0.0"
xmlns="http://schemas.microsoft.com/appx/appinstaller/2021">
<MainPackage Name="MyCompany.MyApp"
Version="1.0.0.0"
Publisher="CN=My Company, O=My Company, L=Seattle, S=WA, C=US"
ProcessorArchitecture="x64"
Uri="https://mycompany.com/apps/MyApp_1.0.0.0_x64.msix" />
<UpdateSettings>
<OnLaunch HoursBetweenUpdateChecks="12"
ShowPrompt="true"
UpdateBlocksActivation="false" />
<AutomaticBackgroundTask />
<ForceUpdateFromAnyVersion>false</ForceUpdateFromAnyVersion>
</UpdateSettings>
</AppInstaller>
用户通过以下方式安装:
ms-appinstaller:?source=https://mycompany.com/apps/MyApp.appinstaller
企业部署
对于托管的企业环境:
| 方法 | 工具 | 最适合 |
|---|---|---|
| Microsoft Intune | Intune 门户 | 云管理设备 |
| SCCM/MECM | Configuration Manager | 本地管理设备 |
| 组策略 | DISM / PowerShell | 域加入设备 |
| PowerShell | Add-AppxPackage |
基于脚本的部署 |
# 通过 PowerShell 进行企业部署
Add-AppxPackage -Path "\\fileserver\apps\MyApp_1.0.0.0_x64.msix"
# 为所有用户安装(需要管理员权限)
Add-AppxProvisionedPackage -Online `
-PackagePath "MyApp_1.0.0.0_x64.msix" `
-SkipLicense
自动更新配置
App Installer 自动更新(Windows 10 1709+)
App Installer XML 文件控制自动更新行为:
<UpdateSettings>
<!-- 在应用启动时检查更新 -->
<OnLaunch HoursBetweenUpdateChecks="12"
ShowPrompt="true"
UpdateBlocksActivation="false" />
<!-- 后台更新检查(Windows 10 1803+) -->
<AutomaticBackgroundTask />
<!-- 允许降级(用于回滚场景) -->
<ForceUpdateFromAnyVersion>false</ForceUpdateFromAnyVersion>
</UpdateSettings>
| 设置 | 描述 |
|---|---|
HoursBetweenUpdateChecks |
更新检查之间的最小小时数(0 = 每次启动) |
ShowPrompt |
更新前向用户显示对话框 |
UpdateBlocksActivation |
阻止应用启动直到更新完成 |
AutomaticBackgroundTask |
在后台检查更新而不启动应用 |
ForceUpdateFromAnyVersion |
允许从任何版本更新(包括降级) |
编程式更新检查(Windows App SDK)
对于需要自定义更新 UI 或逻辑的应用,使用 Package.Current.CheckUpdateAvailabilityAsync():
using Windows.ApplicationModel;
public class AppUpdateService
{
public async Task<bool> CheckForUpdatesAsync()
{
var result = await Package.Current.CheckUpdateAvailabilityAsync();
return result.Availability == PackageUpdateAvailability.Available
|| result.Availability == PackageUpdateAvailability.Required;
}
}
差异更新
MSIX 支持差异更新 – 仅下载更改的块。这在以下情况下自动进行:
- 使用相同的
PackageName和Publisher Version递增- 新旧包托管在同一服务器上
差异更新无需额外配置。
MSIX 捆绑格式
MSIX 捆绑包(.msixbundle)将多个架构特定的 MSIX 包打包成单个可下载工件。Windows 自动安装正确的架构。
创建捆绑包
# 为多个架构构建
dotnet publish -c Release -r win-x64 /p:GenerateAppxPackageOnBuild=true
dotnet publish -c Release -r win-arm64 /p:GenerateAppxPackageOnBuild=true
# 动态查找 MakeAppx.exe(SDK 版本因机器而异)
$makeappx = Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\bin\*\x64\MakeAppx.exe" |
Sort-Object { [version]($_.Directory.Parent.Name) } -Descending |
Select-Object -First 1 -ExpandProperty FullName
# 创建捆绑包
& $makeappx bundle /d "AppPackages" /p "MyApp_1.0.0.0.msixbundle"
MSBuild 捆绑包生成
<PropertyGroup>
<!-- 在构建期间自动生成捆绑包 -->
<AppxBundle>Always</AppxBundle>
<AppxBundlePlatforms>x64|arm64</AppxBundlePlatforms>
</PropertyGroup>
捆绑包布局
MyApp_1.0.0.0.msixbundle
MyApp_1.0.0.0_x64.msix
MyApp_1.0.0.0_arm64.msix
CI/CD MSIX 构建步骤
GitHub Actions MSIX 构建
# MSIX 特定构建步骤(嵌入到你的 CI 工作流中)
# 管道结构参见 [skill:dotnet-gha-patterns]
jobs:
build-msix:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: 设置 .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: 解码签名证书
run: |
$pfxBytes = [System.Convert]::FromBase64String("${{ secrets.SIGNING_CERT_BASE64 }}")
[System.IO.File]::WriteAllBytes("signing-cert.pfx", $pfxBytes)
shell: pwsh
- name: 构建 MSIX 包
run: |
dotnet publish --configuration Release --runtime win-x64 `
/p:GenerateAppxPackageOnBuild=true `
/p:AppxPackageSigningEnabled=true `
/p:PackageCertificateKeyFile="${{ github.workspace }}\signing-cert.pfx" `
/p:PackageCertificatePassword="${{ secrets.CERT_PASSWORD }}"
shell: pwsh
- name: 上传 MSIX 工件
uses: actions/upload-artifact@v4
with:
name: msix-package
path: AppPackages/**/*.msix
- name: 清理证书
if: always()
run: Remove-Item -Path "signing-cert.pfx" -ErrorAction SilentlyContinue
shell: pwsh
Azure DevOps MSIX 构建
# MSIX 特定构建步骤(嵌入到你的 ADO 管道中)
# 管道结构参见 [skill:dotnet-ado-patterns]
steps:
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '8.0.x'
- task: DownloadSecureFile@1
name: signingCert
inputs:
secureFile: 'signing-cert.pfx'
- task: DotNetCoreCLI@2
displayName: '构建 MSIX'
inputs:
command: 'publish'
publishWebProjects: false
projects: '**/MyApp.csproj'
arguments: >-
--configuration Release
--runtime win-x64
/p:GenerateAppxPackageOnBuild=true
/p:AppxPackageSigningEnabled=true
/p:PackageCertificateKeyFile=$(signingCert.secureFilePath)
/p:PackageCertificatePassword=$(CERT_PASSWORD)
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: 'AppPackages'
artifactName: 'msix-package'
AOT + MSIX
MSIX 包可以包含 AOT 编译的二进制文件,以加快启动速度和减少运行时占用空间。结合 PublishAot 和 MSIX 打包:
<PropertyGroup>
<PublishAot>true</PublishAot>
<WindowsPackageType>MSIX</WindowsPackageType>
</PropertyGroup>
AOT MSBuild 配置详情(ILLink 描述符、修剪选项、平台考虑)参见 [skill:dotnet-native-aot]。
Windows SDK 版本要求
| 功能 | 最低 Windows 版本 | 构建号 |
|---|---|---|
| MSIX 与 Windows App SDK | Windows 10 | Build 19041 (2004) |
| App Installer 协议 | Windows 10 | Build 1709 (Fall Creators Update) |
| 自动更新(OnLaunch) | Windows 10 | Build 1709 |
| 后台自动更新 | Windows 10 | Build 1803 (April 2018 Update) |
| ForceUpdateFromAnyVersion | Windows 10 | Build 1809 |
| MSIX 捆绑格式 | Windows 10 | Build 1709 |
| 可选包 | Windows 10 | Build 1709 |
| 修改包 | Windows 10 | Build 1809 |
| App Installer 文件托管 | Windows 10 | Build 1709 |
| Microsoft Store 提交 | Windows App SDK 1.6+ | N/A |
目标平台版本配置
<PropertyGroup>
<!-- 最低支持版本(低于此版本的功能不可用) -->
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<!-- 最大测试版本(用于自适应版本检查) -->
<TargetPlatformVersion>10.0.22621.0</TargetPlatformVersion>
</PropertyGroup>
代理注意事项
-
清单中的
Publisher必须完全匹配签名证书的主题 – 不匹配会导致构建或签名时出现SignTool Error: SignerSign() failed。 -
自签名证书需要手动信任安装 – 用户必须在 MSIX 安装前将证书安装到
Trusted People或Trusted Root Certification Authorities。 -
切勿将 PFX 文件或证书密码提交到源代码控制 – 将证书存储为 CI 机密(GitHub Secrets、Azure DevOps Secure Files)并在构建管道期间解码。
-
AppxBundle=Auto仅在构建多个架构时生成捆绑包 – 对于单架构构建,它生成扁平.msix文件,而非捆绑包。 -
MSIX 应用在类似容器的沙箱中运行 – 文件系统访问被虚拟化。应用写入
AppData时会被重定向到包特定位置。使用ApplicationData.CurrentAPI,而非硬编码路径。 -
Store 提交使用
.msixupload而非.msix– 设置/p:UapAppxPackageBuildMode=StoreUpload以生成正确的上传格式。 -
CI 构建在
windows-latest上包含 Windows SDK – 无需单独安装 SDK 步骤以获取signtool.exe和MakeAppx.exe。 -
不要在 CI 示例中硬编码 TFM 路径 – 使用变量引用(例如,
${{ github.workspace }})以使示例跨 .NET 版本工作。