Creación de paquetes con el diseño del empaquetado

Con la introducción de paquetes de activos, los desarrolladores ahora tienen las herramientas para compilar más paquetes y también más tipos de paquetes. A medida que una aplicación es más grande y más compleja, a menudo se compone de más paquetes y la dificultad de administrar estos paquetes aumentará (especialmente si compila fuera de Visual Studio y usa archivos de asignación). Para simplificar la administración de la estructura de empaquetado de una aplicación, puede usar el diseño de empaquetado compatible con MakeAppx.exe.

El diseño del empaquetado es un único documento XML que describe la estructura de empaquetado de la aplicación. Especifica los lotes de una aplicación (principal y opcional), los paquetes de los lotes y los archivos de los paquetes. Los archivos se pueden seleccionar desde diferentes carpetas, unidades y ubicaciones de red. Se pueden usar caracteres comodín para seleccionar o excluir archivos.

Una vez configurado el diseño de empaquetado de una aplicación, se usa con MakeAppx.exe para crear todos los paquetes de una aplicación en una sola llamada de línea de comandos. Se puede editar el diseño del empaquetado para modificar la estructura del paquete a fin de satisfacer las necesidades de implementación.

Ejemplo de diseño de empaquetado sencillo

Este es un ejemplo del aspecto que tiene un diseño de empaquetado sencillo:

<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>

Vamos a desglosar este ejemplo para comprender cómo funciona.

PackageFamily

Este diseño de empaquetado creará un único archivo de lote de aplicaciones plano con un paquete de arquitectura x64 y un paquete de recursos "Multimedia".

El elemento PackageFamily se usa para definir un lote de aplicaciones. Debe usar el atributo ManifestPath para proporcionar un elemento AppxManifest para el lote; AppxManifest debe corresponder al elemento AppxManifest para el paquete de arquitectura del lote. También se debe proporcionar el atributo Id. Esto se usa con MakeAppx.exe durante la creación del paquete para que pueda crear si quiere solo este paquete, y este será el nombre de archivo del paquete resultante. El atributo FlatBundle se usa para describir qué tipo de lote quiere crear, true para un lote plano (puede leer más información al respecto aquí) y false para un lote clásico. El atributo ResourceManager se usa para especificar si los paquetes de recursos de este lote usarán MRT para acceder a los archivos. Esto es true de manera predeterminada, pero a partir de Windows 10, versión 1803, esto aún no está listo, por lo que este atributo debe establecerse en false.

Elementos Package y AssetPackage

Dentro de PackageFamily, se definen los paquetes que contiene o a los que hace referencia el lote de aplicaciones. Aquí, el paquete de arquitectura (también denominado paquete principal) se define con el elemento Package y el paquete de activos se define con el elemento AssetPackage. El paquete de arquitectura debe especificar para qué arquitectura es el paquete, ya sea "x64", "x86", "arm" o "neutral". También puede proporcionar directamente un elemento AppxManifest específicamente para este paquete; para ello, use de nuevo el atributo ManifestPath. Si no se proporciona un elemento AppxManifest, se generará automáticamente uno a partir del elemento AppxManifest proporcionado para PackageFamily.

De manera predeterminada, se generará un elemento AppxManifest para cada paquete del lote. Para el paquete de activos, también puede establecer el atributo AllowExecution. Si establece esto en false (valor predeterminado), ayudará a reducir el tiempo de publicación de la aplicación, ya que los paquetes que no se necesitan ejecutar no tendrán bloqueado su análisis de virus en el proceso de publicación (puede obtener más información sobre esto en Introducción a los paquetes de activos).

Archivos

En cada definición de paquete, puede usar el elemento File para seleccionar los archivos que se incluirán en este paquete. El atributo SourcePath es donde se encuentran los archivos localmente. Puede seleccionar archivos de diferentes carpetas (mediante rutas de acceso relativas), diferentes unidades (mediante rutas de acceso absolutas) o incluso recursos compartidos de red (mediante algo parecido a \\myshare\myapp\*). DestinationPath es donde los archivos terminarán en el paquete, en relación con la raíz del paquete. ExcludePath se puede usar (en lugar de los otros dos atributos) para seleccionar los archivos que se excluirán de los seleccionados por otros atributos SourcePath de los elementos File dentro del mismo paquete.

Cada elemento File se puede usar para seleccionar varios archivos mediante caracteres comodín. En general, se puede usar un carácter comodín único (*) en cualquier parte de la ruta de acceso las veces que se quiera. Pero un solo carácter comodín solo coincidirá con los archivos de una carpeta y no con las subcarpetas. Por ejemplo, C:\MyGame\*\* se puede usar en SourcePath para seleccionar los archivos C:\MyGame\Audios\UI.mp3 y C:\MyGame\Videos\intro.mp4, pero no puede seleccionar C:\MyGame\Audios\Level1\warp.mp3. El carácter comodín doble (**) también se puede usar en lugar de nombres de carpeta o archivo para que coincidan con cualquier elemento recursivamente (pero no puede estar junto a nombres parciales). Por ejemplo, C:\MyGame\**\Level1\** puede seleccionar C:\MyGame\Audios\Level1\warp.mp3 y C:\MyGame\Videos\Bonus\Level1\DLC1\intro.mp4. Los caracteres comodín también se pueden usar para cambiar directamente los nombres de archivo como parte del proceso de empaquetado si los caracteres comodín se usan en diferentes lugares entre el origen y el destino. Por ejemplo, con C:\MyGame\Audios\* para SourcePath y Sound\copy_* para DestinationPath, se podrá seleccionar C:\MyGame\Audios\UI.mp3 y hacer que aparezca en el paquete como Sound\copy_UI.mp3. En general, el número de caracteres comodín únicos y caracteres comodín dobles debe ser el mismo para SourcePath y DestinationPath de un solo elemento File.

Ejemplo de diseño de empaquetado avanzado

Este es un ejemplo de un diseño de empaquetado más complicado:

<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>

Este ejemplo se diferencia del ejemplo sencillo por la incorporación de elementos ResourcePackage y Optional.

Los paquetes de recursos se pueden especificar con el elemento ResourcePackage. En ResourcePackage, el elemento Resources debe usarse para especificar los calificadores de recursos del paquete de recursos. Los calificadores de recursos son los recursos que admite el paquete de recursos. Aquí podemos ver que hay dos paquetes de recursos definidos y cada uno contiene los archivos específicos de inglés y francés. Un paquete de recursos puede tener más de un calificador; para ello, puede agregar otro elemento Resource dentro de Resources. También se debe especificar un recurso predeterminado para la dimensión de recurso si la dimensión existe (dimensiones que son lenguaje, escala, dxfl). Aquí podemos ver que el idioma predeterminado es el inglés, lo que significa que para los usuarios que no tienen un idioma del sistema de francés establecido, descargarán como plan b el paquete de recursos en inglés y estos se mostrarán en inglés.

Cada uno de los paquetes opcionales tiene su propio nombre de familia de paquete distinto y debe definirse con elementos PackageFamily, a la vez que se especifica el atributo Optional para que sea true. El atributo RelatedSet se usa para especificar si el paquete opcional está dentro del conjunto relacionado (de manera predeterminada es true): si el paquete opcional debe actualizarse con el paquete principal.

El elemento PrebuiltPackage se usa para agregar paquetes que no están definidos en el diseño de empaquetado que se va a incluir o al que se va a hacer referencia en los archivos del lote de aplicaciones que se van a compilar. En este caso, aquí se incluye otro paquete opcional DLC para que el archivo del lote de aplicaciones principal pueda hacer referencia a él y que forme parte del conjunto relacionado.

Compilación de paquetes de aplicaciones con un diseño de empaquetado y MakeAppx.exe

Una vez que tenga el diseño de empaquetado de la aplicación, puede empezar a usar MakeAppx.exe para compilar los paquetes de la aplicación. Para compilar todos los paquetes definidos en el diseño de empaquetado, use el comando :

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

Pero, si va a actualizar la aplicación y algunos paquetes no contienen archivos modificados, solo puede compilar los paquetes que han cambiado. Si se usa el ejemplo de diseño de empaquetado sencillo de esta página y la compilación del paquete de arquitectura x64, este es el aspecto que tendría nuestro comando:

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

La marca /id se puede usar para seleccionar los paquetes que se van a compilar a partir del diseño de empaquetado, correspondiente al atributo ID del diseño. /ip se usa para indicar dónde se encuentra la versión anterior de los paquetes en este caso. Se debe proporcionar la versión anterior porque el archivo del lote de aplicaciones todavía debe hacer referencia a la versión anterior del paquete Multimedia. La marca /iv se usa para incrementar automáticamente la versión de los paquetes que se están compilando (en lugar de cambiar la versión en AppxManifest). Como alternativa, se pueden usar los modificadores /pv y /bv a fin de proporcionar directamente una versión del paquete (para que se creen todos los paquetes) y una versión del lote (para que se creen todos los lotes), respectivamente. Con el ejemplo de diseño de empaquetado avanzado de esta página, si solo quiere compilar el lote opcional Themes y el paquete de la aplicación Themes.main al que hace referencia, usaría este comando:

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

La marca /bc se usa para indicar que los elementos secundarios del lote Themes también deben compilarse (en este caso se compilará Themes.main). La marca /nbp se usa para indicar que no se debe compilar el elemento primario del lote Themes. El elemento primario de Themes, que es un lote de aplicaciones opcional, es el lote de aplicaciones principal: MyGame. Normalmente, para un paquete opcional en un conjunto relacionado, el lote de aplicaciones principal también debe compilarse para que se pueda instalar el paquete opcional, ya que también se hace referencia al paquete opcional en el conjunto de aplicaciones principal cuando se encuentra en un conjunto relacionado (para garantizar el control de versiones entre el paquete principal y los opcionales). En el diagrama siguiente se muestra la relación de elementos secundarios y primarios entre paquetes:

Packaging Layout Diagram