mcpField
D
dotnet-msix

dotnet-msix

github.com/wshaddix开发8687 次安装35 周前更新
代码仓库

关于 dotnet-msix

dotnet-msix 是面向 .NET 桌面应用开发者的 MSIX 打包技能,涵盖创建、签名、分发、更新和 CI 构建,并说明单项目打包与 WAP 项目的做法。

主要功能

  1. 01从 csproj 或 WAP 创建 MSIX
  2. 02配置证书签名
  3. 03准备 Store 和旁加载分发
  4. 04设置 App Installer 更新
  5. 05构建多架构捆绑包
  6. 06将 MSIX 步骤加入 CI/CD

适用场景

  1. 01为 .NET 桌面应用创建发布包
  2. 02为部署配置证书签名
  3. 03设置带自动更新的直接分发
  4. 04构建多架构应用包

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-msix

安装后在 Claude Code 中输入/dotnet-msix确认已加载。

详细介绍

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+(当前稳定版)。使用 Windows App SDK 的 MSIX 最低要求为 Windows 10 build 19041+。App Installer 自动更新协议要求 Windows 10 build 1709+。基线为 .NET 8.0+。

**范围边界:**本技能负责 MSIX 打包流水线——创建、签名、分发、提交到 Store、自动更新和 CI 构建步骤。WinUI 3 项目设置、XAML 模式,以及打包与未打包部署模式的对比由 [skill:dotnet-winui] 负责。通用 Native AOT 编译(PublishAot、ILLink 描述符)由 [skill:dotnet-native-aot] 负责。通用 CI/CD 流水线模式由 [skill:dotnet-gha-patterns] 和 [skill:dotnet-ado-patterns] 负责。

**不在范围内:**WinUI 3 项目设置和 MSIX 与未打包模式的对比——参见 [skill:dotnet-winui]。Native AOT MSBuild 配置——参见 [skill:dotnet-native-aot]。通用 CI/CD 流水线模式——参见 [skill:dotnet-gha-patterns] 和 [skill:dotnet-ado-patterns]。通用 NuGet 打包——参见 [skill:dotnet-nuget-authoring]。基于容器的部署——参见 [skill:dotnet-containers]。

交叉引用:[skill:dotnet-winui](WinUI 项目设置和打包模式对比)、[skill:dotnet-native-aot](AOT + MSIX 场景)、[skill:dotnet-gha-patterns](CI 流水线结构)、[skill:dotnet-ado-patterns](ADO 流水线结构)、[skill:dotnet-nuget-authoring](NuGet 打包)。


MSIX 程序包创建

从 csproj 创建(单项目打包)

现代 WinUI 3 和 Windows App SDK 应用可以直接从应用 .csproj 生成 MSIX 程序包,无需单独的 Windows Application Packaging(WAP)项目。


<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
    <UseWinUI>true</UseWinUI>

    
    <WindowsPackageType>MSIX</WindowsPackageType>

    
    <AppxPackageDir>$(SolutionDir)AppPackages\</AppxPackageDir>
    <GenerateAppxPackageOnBuild>false</GenerateAppxPackageOnBuild>
  </PropertyGroup>
</Project>

构建 MSIX 程序包:

# Build MSIX package
dotnet publish --configuration Release --runtime win-x64 \
  /p:GenerateAppxPackageOnBuild=true \
  /p:AppxPackageSigningEnabled=false

# Output: AppPackages\MyApp_1.0.0.0_x64.msix
WAP 项目(Desktop Bridge)

对于非 WinUI 桌面应用(WPF、WinForms),请使用 Windows Application Packaging Project 将现有应用封装为 MSIX。WAP 项目(.wapproj)通过 Visual Studio 的“Windows Application Packaging Project”模板创建——它们使用专用的项目格式,而非标准的 Microsoft.NET.Sdk。

关键配置是引用桌面应用项目:



<ItemGroup>
  
  <ProjectReference Include="..\MyWpfApp\MyWpfApp.csproj" />
</ItemGroup>


<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 上安装。签名证书的 Subject 必须与程序包清单中的 Publisher 属性匹配。

自签名证书(开发)
# Create a self-signed certificate for development
$cert = New-SelfSignedCertificate `
  -Type Custom `
  -Subject "CN=My Company, O=My Company, L=Seattle, S=WA, C=US" `
  -KeyUsage DigitalSignature `
  -FriendlyName "MyApp Dev Signing" `
  -CertStoreLocation "Cert:\CurrentUser\My" `
  -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3", `
                    "2.5.29.19={text}")

# Export PFX for CI usage
$password = ConvertTo-SecureString -String "$env:CERT_PASSWORD" -Force -AsPlainText
Export-PfxCertificate -Cert $cert `
  -FilePath "MyApp_DevSigning.pfx" `
  -Password $password

# Find signtool.exe dynamically (SDK version varies by machine)
$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

# Sign the MSIX package
& $signtool sign /fd SHA256 /a /f "MyApp_DevSigning.pfx" `
  /p "$env:CERT_PASSWORD" `
  "AppPackages\MyApp_1.0.0.0_x64.msix"
可信 CA 证书(生产)

对于 Microsoft Store 之外的生产分发:

  1. 获取代码签名证书,由可信 CA(DigiCert、Sectigo、GlobalSign)颁发
  2. Subject 必须与 Package.appxmanifest 中的 Publisher 匹配
  3. 为签名添加时间戳,以确保长期有效
# Sign with a trusted CA certificate (from certificate store)
& signtool.exe sign /fd SHA256 /sha1 "THUMBPRINT_HERE" `
  /tr http://timestamp.digicert.com /td SHA256 `
  "AppPackages\MyApp_1.0.0.0_x64.msix"

# Sign with a PFX file
& 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 分发时,无需生产签名证书。


<PropertyGroup>
  <AppxPackageSigningEnabled>true</AppxPackageSigningEnabled>
  <PackageCertificateThumbprint>AUTO_GENERATED_BY_VS</PackageCertificateThumbprint>
</PropertyGroup>
证书要求摘要
分发方式证书类型是否需要受信任的 CA
开发/测试自签名否(手动安装证书)
企业旁加载自签名或内部 CA否(通过组策略部署证书)
直接下载受信任的 CA(DigiCert 等)是
Microsoft Store测试证书(由 MS 重新签名)否

分发渠道

提交至 Microsoft Store
  1. 在 Partner Center 注册为 Windows 开发者(https://partner.microsoft.com/dashboard)
  2. 创建应用预留以确保应用名称
  3. 构建 MSIX 包并关联 Store:
# Build for Store submission (creates .msixupload)
dotnet publish --configuration Release --runtime win-x64 \
  /p:GenerateAppxPackageOnBuild=true \
  /p:UapAppxPackageBuildMode=StoreUpload \
  /p:AppxBundle=Auto
  1. 通过 Partner Center 提交 .msixupload 文件
  2. Microsoft 验证、签名并发布应用
App Installer 旁加载

App Installer(.appinstaller)支持直接分发和自动更新。将文件托管在 Web 服务、网络共享或 CDN 上。


<?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 IntuneIntune 门户云管理设备
SCCM/MECMConfiguration Manager本地部署管理的设备
Group PolicyDISM / PowerShell已加入域的设备
PowerShellAdd-AppxPackage基于脚本的部署
# Enterprise deployment via PowerShell
Add-AppxPackage -Path "\\fileserver\apps\MyApp_1.0.0.0_x64.msix"

# Install for all users (requires admin)
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" />

  
  <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 Bundle 格式

MSIX Bundle(.msixbundle)将多个特定于架构的 MSIX 包打包为单个可下载文件。Windows 会自动安装适合的架构。

创建 Bundle
# Build for multiple architectures
dotnet publish -c Release -r win-x64 /p:GenerateAppxPackageOnBuild=true
dotnet publish -c Release -r win-arm64 /p:GenerateAppxPackageOnBuild=true

# Find MakeAppx.exe dynamically (SDK version varies by machine)
$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

# Create bundle
& $makeappx bundle /d "AppPackages" /p "MyApp_1.0.0.0.msixbundle"
MSBuild Bundle 生成
<PropertyGroup>
  
  <AppxBundle>Always</AppxBundle>
  <AppxBundlePlatforms>x64|arm64</AppxBundlePlatforms>
</PropertyGroup>
Bundle 布局
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-specific build steps (embed in your CI workflow)
# For pipeline structure, see [skill:dotnet-gha-patterns]
jobs:
  build-msix:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '8.0.x'

      - name: Decode signing certificate
        run: |
          $pfxBytes = [System.Convert]::FromBase64String("${{ secrets.SIGNING_CERT_BASE64 }}")
          [System.IO.File]::WriteAllBytes("signing-cert.pfx", $pfxBytes)
        shell: pwsh

      - name: Build MSIX package
        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: Upload MSIX artifact
        uses: actions/upload-artifact@v4
        with:
          name: msix-package
          path: AppPackages/**/*.msix

      - name: Clean up certificate
        if: always()
        run: Remove-Item -Path "signing-cert.pfx" -ErrorAction SilentlyContinue
        shell: pwsh
Azure DevOps MSIX 构建
# MSIX-specific build steps (embed in your ADO pipeline)
# For pipeline structure, see [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: 'Build 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 版本Build 号
搭配 Windows App SDK 的 MSIXWindows 10Build 19041 (2004)
App Installer 协议Windows 10Build 1709 (Fall Creators Update)
自动更新(OnLaunch)Windows 10Build 1709
后台自动更新Windows 10Build 1803 (April 2018 Update)
ForceUpdateFromAnyVersionWindows 10Build 1809
MSIX Bundle 格式Windows 10Build 1709
可选包Windows 10Build 1709
修改包Windows 10Build 1809
App Installer 文件托管Windows 10Build 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>

Agent 注意事项

  1. 清单中的 Publisher 必须与签名证书的 Subject 完全一致——不匹配会在构建或签名时导致 SignTool Error: SignerSign() failed。

  2. 自签名证书需要手动安装信任——用户必须先将证书安装到 Trusted People 或 Trusted Root Certification Authorities,才能安装 MSIX。

  3. 切勿将 PFX 文件或证书密码提交到源代码管理中——请将证书存储为 CI 机密(GitHub Secrets、Azure DevOps Secure Files),并在构建管道中解码。

  4. 只有在构建多个体系结构时,AppxBundle=Auto 才会生成捆绑包——对于单体系结构构建,它会生成普通的 .msix 文件,而不是捆绑包。

  5. MSIX 应用运行在类似容器的沙盒中——文件系统访问会被虚拟化。写入 AppData 的应用会被重定向到软件包专属位置。请使用 ApplicationData.Current API,而不要使用硬编码路径。

  6. 向 Store 提交时使用 .msixupload,而不是 .msix——设置 /p:UapAppxPackageBuildMode=StoreUpload 以生成正确的上传格式。

  7. 在 windows-latest 上进行的 CI 构建已包含 Windows SDK——无需为 signtool.exe 和 MakeAppx.exe 单独安装 SDK。

  8. 不要在 CI 示例中硬编码 TFM 路径——请使用变量引用(例如 ${{ github.workspace }}),确保示例适用于不同的 .NET 版本。

评论

支持 Markdown