使用打包布局创建包

随着资产包的引入,开发人员现在拥有除了更多包类型之外,还具有生成更多包的工具。 随着应用变得越来越复杂,它通常由更多包组成,管理这些包的难度将增加(尤其是在 Visual Studio 外部生成并使用映射文件时)。 为了简化应用的打包结构的管理,可以使用 MakeAppx.exe支持的打包布局。

打包布局是描述应用的打包结构的单个 XML 文档。 它指定应用(主要和可选)的捆绑包、捆绑包中的包以及包中的文件。 可以从不同的文件夹、驱动器和网络位置选择文件。 通配符可用于选择或排除文件。

设置应用的打包布局后,它与 MakeAppx.exe 一起使用,以便在单个命令行调用中为应用创建所有包。 可以编辑打包布局以更改包结构以满足部署需求。

简单打包布局示例

下面是简单包装布局的示例:

<PackagingLayout xmlns="http://schemas.microsoft.com/appx/makeappx/2017">
  <PackageFamily ID="MyGame" FlatBundle="true" ManifestPath="C:\mygame\appxmanifest.xml" ResourceManager="false">
    
    <!-- x64 code package-->
    <Package ID="x64" ProcessorArchitecture="x64">
      <Files>
        <File DestinationPath="*" SourcePath="C:\mygame\*"/>
        <File ExcludePath="*C:\mygame\*.txt"/>
      </Files>
    </Package>
    
    <!-- Media asset package -->
    <AssetPackage ID="Media" AllowExecution="false">
      <Files>
        <File DestinationPath="Media\**" SourcePath="C:\mygame\media\**"/>
      </Files>
    </AssetPackage>

  </PackageFamily>
</PackagingLayout>

让我们将此示例分解为了解其工作原理。

PackageFamily

此打包布局将创建具有 x64 体系结构包和“媒体”资产包的单个平面应用捆绑文件。

PackageFamily 元素用于定义应用捆绑包。 必须使用ManifestPath属性为捆绑包提供AppxManifest,该AppxManifest应对应于捆绑包的体系结构包的AppxManifest。 还必须提供 ID 属性。 在创建包期间,该属性需与 MakeAppx.exe 配合使用,以便可选择性地单独生成此包,且其会成为所生成包的文件名。 FlatBundle 属性用于描述要创建的捆绑包的类型、平面捆绑包的 true(可在此处阅读详细信息),以及经典捆绑包的 falseResourceManager 属性用于指定此捆绑包中的资源包是否将使用 MRT 来访问文件。 这默认为 true,但从 Windows 10 版本 1803 开始,尚未准备就绪,因此此属性必须设置为 false

包和 AssetPackage

PackageFamily 中,定义了应用捆绑包包含的包或引用。 在这里,体系结构包(也称为主包)使用 Package 元素定义,资产包使用 AssetPackage 元素定义。 体系结构包必须指定包所针对的体系结构:“x64”、“x86”、“arm”或“neutral”。 还可以(可选)再次使用 ManifestPath 属性直接提供特定于此包的 AppxManifest。 如果未提供 AppxManifest,则会从为 PackageFamily 提供的 AppxManifest 自动生成一个 AppxManifest

默认情况下,将为捆绑包中的每个包生成 AppxManifest 。 对于资产包,还可以设置 AllowExecution 属性。 将此设置为 false(默认值),将有助于减少应用的发布时间,因为不需要执行的包不会因为病毒扫描而阻碍发布过程。您可以在 资产包简介中了解更多相关信息。

文件

在每个包定义中,可以使用 File 元素选择要包含在此包中的文件。 SourcePath 属性是文件在本地的位置。 你可以从不同的文件夹(通过提供相对路径)、不同的驱动器(通过提供绝对路径)或甚至网络共享(通过提供类似 \\myshare\myapp\* 的格式)选择文件。 DestinationPath 是文件在包中的最终存储路径,是相对于包根目录的路径。 ExcludePath 可用于选择要排除的文件,而不是使用其他两个属性,这些文件是由同一个包中的其他 File 元素的 SourcePath 属性选择的。

每个 File 元素都可用于使用通配符选择多个文件。 一般情况下,单个通配符 (*) 可以在路径中的任何位置使用任意次数。 但是,单个通配符将仅匹配文件夹中的文件,而不匹配任何子文件夹。 例如,C:\MyGame\*\*可以在 SourcePath 中使用来选择文件C:\MyGame\Audios\UI.mp3C:\MyGame\Videos\intro.mp4,但不能选择C:\MyGame\Audios\Level1\warp.mp3。 双通配符(**)还可以用于代替文件夹或文件名以递归方式匹配任何内容(但它不能位于部分名称旁边)。 例如, C:\MyGame\**\Level1\** 可以选择 C:\MyGame\Audios\Level1\warp.mp3C:\MyGame\Videos\Bonus\Level1\DLC1\intro.mp4。 如果源路径与目标路径中的通配符位置不一致,则还可以在打包过程中直接使用通配符来更改文件名。 例如,对于 C:\MyGame\Audios\*SourcePathSound\copy_*DestinationPath,可以选择 C:\MyGame\Audios\UI.mp3 并使其在包中显示为 Sound\copy_UI.mp3。 通常,单个通配符和双通配符的数量对于单个 File 元素的 SourcePathDestinationPath 必须相同。

高级打包布局示例

下面是更复杂的打包布局的示例:

<PackagingLayout xmlns="http://schemas.microsoft.com/appx/makeappx/2017">
  <!-- Main game -->
  <PackageFamily ID="MyGame" FlatBundle="true" ManifestPath="C:\mygame\appxmanifest.xml" ResourceManager="false">
    
    <!-- x64 code package-->
    <Package ID="x64" ProcessorArchitecture="x64">
      <Files>
        <File DestinationPath="*" SourcePath="C:\mygame\*"/>
        <File ExcludePath="*C:\mygame\*.txt"/>
      </Files>
    </Package>

    <!-- Media asset package -->
    <AssetPackage ID="Media" AllowExecution="false">
      <Files>
        <File DestinationPath="Media\**" SourcePath="C:\mygame\media\**"/>
      </Files>
    </AssetPackage>
    
    <!-- English resource package -->
    <ResourcePackage ID="en">
      <Files>
        <File DestinationPath="english\**" SourcePath="C:\mygame\english\**"/>
      </Files>
      <Resources Default="true">
        <Resource Language="en"/>
      </Resources>
    </ResourcePackage>

    <!-- French resource package -->
    <ResourcePackage ID="fr">
      <Files>
        <File DestinationPath="french\**" SourcePath="C:\mygame\french\**"/>
      </Files>
      <Resources>
        <Resource Language="fr"/>
      </Resources>
    </ResourcePackage>
  </PackageFamily>

  <!-- DLC in the related set -->
  <PackageFamily ID="DLC" Optional="true" ManifestPath="C:\DLC\appxmanifest.xml">
    <Package ID="DLC.x86" Architecture="x86">
      <Files>
        <File DestinationPath="**" SourcePath="C:\DLC\**"/>
      </Files>
    </Package>
  </PackageFamily>

  <!-- DLC not part of the related set -->
  <PackageFamily ID="Themes" Optional="true" RelatedSet="false" ManifestPath="C:\themes\appxmanifest.xml">
    <Package ID="Themes.main" Architecture="neutral">
      <Files>
        <File DestinationPath="**" SourcePath="C:\themes\**"/>
      </Files>
    </Package>
  </PackageFamily>

  <!-- Existing packages that need to be included/referenced in the bundle -->
  <PrebuiltPackage Path="C:\prebuilt\DLC2.appxbundle" />

</PackagingLayout>

此示例与添加 ResourcePackageOptional 元素的简单示例不同。

可以使用 ResourcePackage 元素指定资源包。 在 ResourcePackage 中, Resources 元素必须用于指定资源包的资源限定符。 资源限定符是资源包支持的资源,此处可以看到定义了两个资源包,每个资源包都包含英语和法语特定文件。 资源包可以有多个限定符,这可以通过在 Resources 中添加另一个 Resource 元素来完成。 如果维度存在(维度是语言、缩放、dxfl),则还必须指定资源维度的默认资源。 在这里,我们可以看到英语是默认语言,这意味着对于系统语言没有设置为法语的用户,他们将回退到下载英语资源包,并以英语显示。

可选包各自具有其不同的包系列名称,并且必须使用 PackageFamily 元素定义,同时指定要为 trueOptional 属性。 RelatedSet 属性用于指定可选包是否在相关集中(默认情况下为 true)- 是否应使用主包更新可选包。

PrebuiltPackage 元素用于添加未在打包布局中定义的包,以便在要构建的应用捆绑文件中包含或引用这些包。 在这种情况下,此处将包含另一个 DLC 可选包,以便主应用捆绑文件可以引用它,并将其作为相关集的一部分。

使用打包布局和 MakeAppx.exe 生成应用包

为应用设置打包布局后,可以开始使用 MakeAppx.exe 来生成应用的包。 若要生成打包布局中定义的所有包,请使用以下命令:

MakeAppx.exe build /f PackagingLayout.xml /op OutputPackages\

但是,如果要更新应用,并且某些包不包含任何已更改的文件,则只能生成已更改的包。 使用此页面上的简单打包布局示例来生成 x64 架构的软件包,命令应如下所示:

MakeAppx.exe build /f PackagingLayout.xml /id "x64" /ip PreviousVersion\ /op OutputPackages\ /iv

标志 /id 可用于从打包布局中选择要生成的包,这与布局中的 ID 属性相对应。 /ip用于指示以前版本的包在此示例中的位置。 必须提供以前的版本,因为应用捆绑文件仍需要引用旧版 媒体 包。 该 /iv 标志用于自动递增正在生成的包的版本(而不是更改 AppxManifest 中的版本)。 或者,开关 /pv/bv 可分别用于直接提供包版本(用于所有要创建的包)和捆绑包版本(用于所有要创建的捆绑包)。 如果您只想生成 Themes 可选捆绑包和它引用的 Themes.main 应用程序包,请使用本页上的高级打包布局示例中的此命令。

MakeAppx.exe build /f PackagingLayout.xml /id "Themes" /op OutputPackages\ /bc /nbp

/bc 标志用于表示还应生成主题捆绑包的子级(在本例中,将生成 Themes.main)。 /nbp 标志用于表示不应生成主题捆绑包的父级主题的父级(可选应用捆绑包)是主要应用捆绑包:MyGame。 通常,对于一个相关集合中的可选包,必须构建主应用捆绑包,以便可选包能够安装,因为,当可选包位于相关集合中时,它会在主应用捆绑包中被引用,从而确保主包和可选包之间的版本控制。 下图展示了软件包之间的父子关系:

打包布局图