Streaming Install Part 3: Content Group Maps Deep Dive

Content Group Map Requirements and Details

General Content Group Map Requirements

From the previous post, you might have noticed other differences between the SourceAppxContentGroupMap.xml and the AppxContentGroupMap.xml besides the wildcards. But before we dive into the differences, let’s first go over the similarities, the rules that apply to content group maps in general:

  • Files are defined relative to the root of the package.
  • Footprint files (AppxBlockMap.xml, AppxContentGroupMap.xml, AppxManifest.xml, AppxSignature.p7x,, resources.pri) should not be part of the map. You don’t need to worry about how these files will be streamed since these files will be downloaded even before the required group.
    • exe will fail if one of them is in an automatic group
    • Conversion will ignore footprint files during wildcard expansion. So if one of your wildcards includes a footprint file, you are fine since it will be ignored.
  • Visual assets such as the SplashScreen.png and Square44x44Logo.png that are declared in the manifest cannot be in an automatic content group. This is because these images are needed for the app to be installed and launched.
  • A file can be in multiple automatic content groups. This is because often times a file might be required for multiple scenarios, for example common textures across different levels. If these files are not needed in the required content group, then defining it in multiple automatic content groups will allow the file to be downloaded with the first automatic content group that needs it, all subsequent content groups that also need this file will not redownload it.
  • All files that are in the map must also be in the package
  • There can be multiple automatic content groups
  • Content group names must be unique (this is case sensitive)
  • No automatic content group can be named “Required”

SourceAppxContentGroupMap.xml Requirements

Some additional rules just for the SourceAppxContentGroupMap.xml:

  • There can only be 1 required content group in the required section
  • The required content group must be named “Required”
  • A file cannot be in both the required content group and an automatic content group
  • Visual assets mentioned above must be declared in the required content group
  • All files that are in the package layout must also be in the map at least once
  • Specific wildcard usages are supported

SourceAppxContentGroupMap.xml Wildcard Rules

For using wildcards, in general, simple uses of * and ** are supported no matter how deep the directories are (you cannot use * and ** together). * will only match files within a directory, and not its subdirectories. ** is the recursive wildcard, which will include all files in the current directory and in all subdirectories, and so forth. However, ** cannot be used in the root of the package, since this would break the 3rd rule for SourceAppxContentGroupMap.xml listed above because doing this would include all files in the package within a content group.

If you really want to understand more advanced wildcard usage, here are the detailed examples:

CGM Entry          File Layout (relative to project root) Result
* Assets\…
Succeed conversion with System.Core.dll, System.Runtime.dll, Microsoft.CSharp.dll, and App.exe in the content group
** N/A Fail conversion, cannot double wildcard at the root of the project to include every file in the project.
*CSharp* Assets\…
Succeed conversion with Microsoft.CSharp.dll and RandomCSharpfile.txt in the content group
Assets\*Level2* Assets\Level2title.png
Succeed conversion with Assets\Level2title.png in the content group
Assets\* Assets\Hammer.png
Succeed conversion with Hammer.png in the content group
Assets\** Assets\Hammer.png
Succeed conversion with Hammer.png and Gun.png in the content group
*.dll Assets\…
Succeed conversion with System.Core.dll and System.Runtime.dll in the content group
*.dll Assets\…
Conversion succeeds but warning will appear alerting that no file matched the wildcard specification
System.*.dll Assets\…
Succeed conversion with System.Core.dll and System.Runtime.dll in the content group
System.Core.dll* System.Core.dll Succeed conversion with System.Core.dll in the content group

If you used the SourceAppxContentGroupMap.xml template from the previous post, you will notice that the visual asset files created by Visual Studio by default are being selected through the “*SplashScreen*” and “*Logo*” wildcards to be included in the required content group.

*If you are developing with Visual Studio, we recommend that you always have in your required group a single wildcard in the root to account for the additional files (System.*.dlls) that Visual Studio adds to the root of debug packages.*

AppxContentGroupMap.xml Requirements

Here are the additional rules for the AppxContentGroupMap.xml:

  • Wildcards cannot be used
  • The required section cannot exist

From the above SourceAppxContentGroupMap.xml and AppxContentGroupMap.xml examples, you would have also noticed that the AppxContentGroupMap.xml does not contain a required section or the required content group. This is part of the design of the AppxContentGroupMap.xml. The platform will read this file and interpret all files that are not defined in an automatic content group as required. This is why if you have a fixed group of automatic content group files that will never change, then directly authoring the AppxContentGroupMap.xml is easier and allows you to bypass the conversion step during deployment and packaging.

Converting SourceAppxContentGroupMap.xml to AppxContentGroupMap.xml

So what exactly happens during conversion? And how can you do it if you’re not using Visual Studio?

Well, once you have finished crafting the SourceAppxContentGroupMap.xml and are ready to deploy or package the app, you can use MakeAppx.exe (part of the Windows 10 SDK) or Visual Studio to convert the map to the AppxContentGroupMap.xml. If you are using Visual Studio, as described in the above example, simply right click on the project -> Store -> “Convert Content Group Map File”.

Using MakeApp.exe for Conversion

If you choose to use MakeAppx.exe directly to convert, the command should look something like:

MakeAppx convertCGM /s SourceAppxContentGroupMap.xml /f MyApp\AppxContentGroupMap.xml /d MyApp\

Where “MyApp” is the folder from which you will package your app.

Conversion Workflow

What happens during conversion is that first, all wildcards used in the SourceAppxContentGroupMap.xml will be expanded based on the files in the provided directory or layout. Then, conversion validation happens, where all files in the expanded SourceAppxContentGroupMap.xml will be verified to also be in the directory, and all files in the directory will be verified to be defined at least once in the expanded SourceAppxContentGroupMap.xml. If you are worried about accidently missing a file or adding a file to your content group map, then authoring the SourceAppxContentGroupMap.xml will allow you to take advantage of this validation during conversion to check for you. As the last step of conversion, the required content group will be removed, and this map will then become the AppxContentGroupMap.xml.

Lastly, note that conversion must be done whenever the SourceAppxContentGroupMap.xml has changed or files (that are included using wildcards) have been added or removed. This is because the AppxContentGroupMap.xml must be up to date with the current files of the app in order for deployment and packaging to succeed.

In Depth into Creating Stream-able Resource Packages

If you are using language or scale specific resources and are generating resource packages for your app, then this section will be important to help you also get streaming install working for your resource packages.

For a bundle that contains stream-able main packages and stream-able resource packages, when being installed on a user’s system, the platform will install the required content group from all of the packages first, then install the automatic content groups. You must use the content group prioritization API (StageContentGroupAsync in the next post) to specify which automatic content group you want to download from which package (main pack or a resource pack).

In general, each .appx must have an AppxContentGroupMap.xml in order for it to be stream-able, and the AppxContentGroupMap.xml must list out explicitly the file paths for files that are in the automatic groups for that package.

However, for stream-able resource packages, you will still author only 1 SourceAppxContentGroupMap.xml for your project. In the map, you will reference your resources using their logical names (meaning without any resource qualifiers), and thus a file that has multiple versions (depending on language or scale) will only be listed once in the map. So for example, if you have a different logo depending on the language, your logo image paths could look like “Assets\fr-fr\logo.png” and “Assets\es-es\logo.png”. However, to include this logo.png in a content group, you would just have “Assets\logo.png” instead of listing the logo.png in each language folder.

Using MakeAppx.exe for Creating Stream-able Resource Packages

During conversion, the appropriate resources.pri file (for the entire app) must be provided to MakeAppx.exe in order for it to correctly interpret the logical names for resource files. (We will not go into creating the appropriate resources.pri files here, for more information on this please refer to this article.) The command should look something like:

MakeAppx convertCGM /s SourceAppxContentGroupMap.xml /f AppxContentGroupMap.xml /r MyApp\resources.pri /d MyApp

Once conversion is done, for packaging, you will use the AppxContentGroupMap.xml generated from conversion with the /cgm switch in MakeAppx.exe, and you will do this for every resource pack that needs to be created and the main packs. This is so that MakeAppx.exe can create the appropriate AppxContentGroupMap.xml for that particular package (the package specific AppxContentGroupMap.xml will be a subset of the overall AppxContentGroupMap.xml generated from conversion based on the files in the directory to be packed). So the command should look something like:

MakeAppx pack /d MyApp\MyApp_language-fr /p MyApp\MyApp_language-fr.appx /cgm AppxContentGroupMap.xml

Using the /cgm option will also disable the check that all files in the AppxContentGroupMap.xml is in the package. This is because the provided AppxContentGroupMap.xml contains files for all the resource packs and main pack, so doing this check is impossible.

Finally, after you have created all of your .appx’s, you will then package them up into the .appxbundle with:

MakeAppx bundle /d MyApp /p MyApp.appxbundle /bv <package version>

Using Visual Studio for Creating Stream-able Resource Packages

If you are using Visual Studio for development, Visual Studio should take care of all of the nuances with conversion and package creation for you so that you will always have the correct AppxContentGroupMap.xml’s for your packages in the .appxbundle that it creates.

If you have the streaming demo app downloaded, you can see that it has some French specific assets in the “Assets\fr-fr” folder. These assets referenced in the SourceAppxContentGroupMap.xml without the “fr-fr”, but after conversion, the AppxContentGroupMap.xml will expand these references out to their correct paths. If you create a bundle with the project (and change the packages’ extensions to .zip to open them), then you will see that the main pack does not have the “fr-fr” folder nor the French resources, and its AppxContentGroupMap.xml will also have the references to these resources removed. Vice versa, the French resource pack will only contain files from the “fr-fr” folder under assets, and its AppxContentGroupMap.xml will only have references to these resources, and not to any of the files in the main pack. So if you are using Visual Studio and resource packs, just author the SourceAppxContentGroupMap.xml with all of your resources defined also, and Visual Studio can take care of the hard parts for you.

And lastly, to reprioritize (in depth in the next post) to a content group in a resource pack, you can use Package.Current.Dependencies to see all of your app’s dependency packages, then calling StageContentGroupsAsync once you have found the resource pack that you are looking for. You can find the code related to streaming resource packs in the streaming demo app (here) also.


Follow the links below for more detailed information on building apps with streaming installation:

<more links coming soon>

Questions?  Ask in the comments section below.

Andy Liu, Program Manager, Windows Developer Platform

Comments (0)

Skip to main content