随着资产包的引入,开发人员现在拥有除了更多包类型之外,还具有生成更多包的工具。 随着应用变得越来越复杂,它通常由更多包组成,管理这些包的难度将增加(尤其是在 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(可在此处阅读详细信息),以及经典捆绑包的 false。 ResourceManager 属性用于指定此捆绑包中的资源包是否将使用 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.mp3
C:\MyGame\Videos\intro.mp4
,但不能选择C:\MyGame\Audios\Level1\warp.mp3
。 双通配符(**
)还可以用于代替文件夹或文件名以递归方式匹配任何内容(但它不能位于部分名称旁边)。 例如, C:\MyGame\**\Level1\**
可以选择 C:\MyGame\Audios\Level1\warp.mp3
和 C:\MyGame\Videos\Bonus\Level1\DLC1\intro.mp4
。 如果源路径与目标路径中的通配符位置不一致,则还可以在打包过程中直接使用通配符来更改文件名。 例如,对于 C:\MyGame\Audios\*
SourcePath 和 Sound\copy_*
DestinationPath,可以选择 C:\MyGame\Audios\UI.mp3
并使其在包中显示为 Sound\copy_UI.mp3
。 通常,单个通配符和双通配符的数量对于单个 File 元素的 SourcePath 和 DestinationPath 必须相同。
高级打包布局示例
下面是更复杂的打包布局的示例:
<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>
此示例与添加 ResourcePackage 和 Optional 元素的简单示例不同。
可以使用 ResourcePackage 元素指定资源包。 在 ResourcePackage 中, Resources 元素必须用于指定资源包的资源限定符。 资源限定符是资源包支持的资源,此处可以看到定义了两个资源包,每个资源包都包含英语和法语特定文件。 资源包可以有多个限定符,这可以通过在 Resources 中添加另一个 Resource 元素来完成。 如果维度存在(维度是语言、缩放、dxfl),则还必须指定资源维度的默认资源。 在这里,我们可以看到英语是默认语言,这意味着对于系统语言没有设置为法语的用户,他们将回退到下载英语资源包,并以英语显示。
可选包各自具有其不同的包系列名称,并且必须使用 PackageFamily 元素定义,同时指定要为 true 的 Optional 属性。 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。 通常,对于一个相关集合中的可选包,必须构建主应用捆绑包,以便可选包能够安装,因为,当可选包位于相关集合中时,它会在主应用捆绑包中被引用,从而确保主包和可选包之间的版本控制。 下图展示了软件包之间的父子关系: