패키징 레이아웃으로 패키지 만들기

자산 패키지가 도입되면서 개발자는 이제 더 많은 패키지 유형 외에도 더 많은 패키지를 빌드할 수 있는 도구를 갖게 되었습니다. 앱이 점점 더 커지고 복잡해지면 더 많은 패키지로 구성되는 경우가 많으며, 이러한 패키지를 관리하는 데 어려움이 증가합니다(특히 Visual Studio 외부에서 빌드하고 매핑 파일을 사용하는 경우). 앱의 패키징 구조 관리를 간소화하기 위해 MakeAppx.exe에서 지원하는 패키징 레이아웃을 사용할 수 있습니다.

패키징 레이아웃은 앱의 패키징 구조를 설명하는 단일 XML 문서입니다. 앱의 번들(기본 및 선택 사항), 번들의 패키지 및 패키지의 파일을 지정합니다. 파일은 다른 폴더, 드라이브 및 네트워크 위치에서 선택할 수 있습니다. Wild카드s를 사용하여 파일을 선택하거나 제외할 수 있습니다.

앱에 대한 패키징 레이아웃이 설정되면 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 요소는 앱 번들을 정의하는 데 사용됩니다. 매니페스트 경로 특성을 사용하여 번들에 AppxManifest를 제공해야 합니다. AppxManifest는 번들의 아키텍처 패키지에 대한 AppxManifest에 해당해야 합니다. ID 특성도 제공해야 합니다. 이 이름은 패키지를 만드는 동안 MakeAppx.exe와 함께 사용되므로 원하는 경우 이 패키지만 만들 수 있으며 결과 패키지의 파일 이름이 됩니다. FlatBundle 특성은 만들려는 번들 유형, 플랫 번들(여기서 자세히 읽을 수 있음) true, 클래식 번들에 대해 false를 설명하는 데 사용됩니다. ResourceManager 특성은 이 번들 내의 리소스 패키지가 파일에 액세스하기 위해 MRT를 사용할지 여부를 지정하는 데 사용됩니다. 기본적으로 true이지만 Windows 10 버전 1803을 기준으로 아직 준비되지 않았으므로 이 특성을 false설정해야 합니다.

Package 및 AssetPackage

PackageFamily 내에서 앱 번들에 포함되거나 참조가 포함된 패키지가 정의됩니다. 여기서 아키텍처 패키지(기본 패키지라고도 함)는 Package 요소로 정의되고 자산 패키지는 AssetPackage 요소로 정의됩니다. 아키텍처 패키지는 패키지의 아키텍처를 "x64", "x86", "arm" 또는 "neutral"으로 지정해야 합니다. 또한(선택적으로) ManifestPath 특성을 다시 사용하여 이 패키지에 대해 AppxManifest를 직접 제공할 수도 있습니다. AppxManifest가 제공되지 않으면 PackageFamily제공된 AppxManifest에서 자동으로 생성됩니다.

기본적으로 번들 내의 모든 패키지에 대해 AppxManifest 가 생성됩니다. 자산 패키지의 경우 AllowExecution 특성을 설정할 수도 있습니다. 이 값을 false(기본값)로 설정하면 실행할 필요가 없는 패키지에 바이러스 검색이 게시 프로세스를 차단하지 않으므로 앱의 게시 시간을 줄이는 데 도움이 됩니다(자산 패키지 소개에서 이에 대해 자세히 알아볼 수 있음).

Files

각 패키지 정의 내에서 File 요소를 사용하여 이 패키지에 포함할 파일을 선택할 수 있습니다. SourcePath 특성은 파일이 로컬에 있는 위치입니다. 다른 폴더(상대 경로 제공), 다른 드라이브(절대 경로 제공) 또는 네트워크 공유(예: \\myshare\myapp\*제공)에서 파일을 선택할 수 있습니다. DestinationPath는 패키지 루트를 기준으로 파일이 패키지 내에서 끝나는 위치입니다. ExcludePath를 사용하여(다른 두 특성 대신) 동일한 패키지 내의 다른 파일 요소의 SourcePath 특성에서 선택한 파일에서 제외할 파일을 선택할 수 있습니다.

File 요소는 wild카드를 사용하여 여러 파일을 선택하는 데 사용할 수 있습니다. 일반적으로 경로 내에서 여러 번 단일 wild카드(*)를 사용할 수 있습니다. 그러나 단일 wild카드 폴더 내의 파일만 일치하며 하위 폴더는 일치하지 않습니다. 예를 들어 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.mp3 수 있습니다.C:\MyGame\Videos\Bonus\Level1\DLC1\intro.mp4 wild카드는 원본과 대상 간의 다른 위치에서 야생 카드 사용되는 경우 패키징 프로세스의 일부로 파일 이름을 직접 변경하는 데 사용할 수도 있습니다. 예를 들어 SourcePath 및 Sound\copy_* DestinationPath에 대한 경우 C:\MyGame\Audios\* 이 옵션을 선택하여 C:\MyGame\Audios\UI.mp3 패키지에 다음과 같이 Sound\copy_UI.mp3표시할 수 있습니다. 일반적으로 단일 wild카드 및 double wild카드 수는 단일 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 및 선택적 요소를 추가하여 간단한 예제와 다릅니다.

ResourcePackage 요소를 사용하여 리소스 패키지를 지정할 수 있습니다. ResourcePackage 내에서 리소스 요소를 사용하여 리소스 팩의 리소스 한정자를 지정해야 합니다. 리소스 한정자는 리소스 팩에서 지원하는 리소스입니다. 여기서는 두 개의 리소스 팩이 정의되어 있으며 각각 영어 및 프랑스어 관련 파일을 포함하고 있음을 알 수 있습니다. 리소스 팩에는 둘 이상의 한정자를 가질 수 있습니다. 이 작업은 리소스 내에 다른 리소스 요소를 추가하여 수행할 수 있습니다. 차원이 존재하는 경우(언어, 크기 조정, dxfl인 차원) 리소스 차원에 대한 기본 리소스도 지정해야 합니다. 여기서는 영어가 기본 언어임을 알 수 있습니다. 즉, 프랑스어 집합의 시스템 언어가 없는 사용자의 경우 영어 리소스 팩을 다운로드하고 영어로 표시하는 것으로 대체됩니다.

선택적 패키지는 각각 고유한 패키지 패밀리 이름을 가지며 PackageFamily 요소로 정의해야 하며 선택적 특성을 true지정해야 합니다. 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 경우 이전 버전의 패키지가 있는 위치를 나타내는 데 사용됩니다. 앱 번들 파일은 여전히 이전 버전의 Media 패키지를 참조해야 하므로 이전 버전을 제공해야 합니다. 이 /iv 플래그는 AppxManifest에서 버전을 변경하는 대신 빌드 중인 패키지의 버전을 자동으로 증가하는 데 사용됩니다. 또는 스위치를 /pv/bv 사용하여 패키지 버전(만들 모든 패키지의 경우) 및 번들 버전(만들 모든 번들에 대해)을 직접 제공할 수 있습니다. 이 페이지의 고급 패키징 레이아웃 예제를 사용하여 테마 선택적 번들 및 참조하는 Themes.기본 앱 패키지만 빌드하려면 다음 명령을 사용합니다.

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

플래그는 /bc 테마 번들의 자식도 빌드해야 했음을 나타내는 데 사용됩니다(이 경우 Themes.기본 빌드됨). 플래그 /nbp 는 테마 번들의 부모가 빌드되어서는 안 됨을 나타내는 데 사용됩니다. 선택적 앱 번들인 테마부모는 기본 앱 번들인 MyGame입니다. 일반적으로 관련 집합의 선택적 패키지의 경우 선택적 패키지가 관련 집합에 있을 때(기본 패키지와 선택적 패키지 간의 버전 관리를 보장하기 위해) 기본 앱 번들에서도 참조되므로 선택적 패키지를 설치할 수 있도록 기본 앱 번들을 빌드해야 합니다. 패키지 간의 부모 자식 관계는 다음 다이어그램에 나와 있습니다.

Packaging Layout Diagram