The Android SDK provides a new tool for packaging called `aapt2`.
`aapt2` works slightly differently from the normal `aapt` process.
When `aapt2` is used, the build process is split into two parts: an
`aapt compile` step and an `aapt link` step.
The `aapt2 compile` step produces a `.flata` zip file which contains
the compiled "flat" resources. The format is internal to android
tooling:
aapt2 compile -o obj/Debug/res/compiled.flata -dir obj/Debug/res
`aapt2 compile` is separately run for every `res` directory that the
project contains, such as those from referenced assemblies or NuGet
packages, and will store the `.flata` file into the various
`$(IntermediateOutputPath)lp\*` directories.
The intended benefit here is that when a resource is changed, only
the `compiled.flata` for the project/assembly associated with that
resource need be regenerated, not *everything*.
The `aapt2 link` step consumes all the `.flata` archives and combines
them into a single archive for use by the `.apk`:
aapt2 link -o resources.apk.bk --manifest Foo.xml --java . --custom-package com.infinitespace_studios.blankforms -R foo2.flata -R foo.flata -v --auto-add-overlay --output-text-symbols obj/Debug/R.txt
Note the `.flata` archives are passed using the `-R` option. The
order is important just like it was for `aapt`. The last item will
be the application resources. This allows developers to override
resource values if needed. We also generate the `R.txt` file at this
point, which is used to generate the design time
`Resource.designer.cs` for IntelliSense.
Use of the new `aapt2` model doesn't improve initial `.apk` build
times, but it significantly helps with *rebuild* times:
Tool | Clean Build | Build Touching only C# | Build Touching only Resource |
------|-------------|------------------------|------------------------------|
Aapt | 00:00:51.74 | 00:00:08.91 | 00:00:25.26 |
Aapt2 | 00:00:50.70 | 00:00:08.64 | 00:00:08.44 |
The above are the build resources for a Blank Xamarin Forms App.
Note that the initial build is roughly the same between both `aapt`
and `aapt2`. `aapt2` really shines when a resource in a dependency
is modified and the `.apk` is rebuilt, rebuilding the `.apk` in
roughly a third of the time as `aapt` required. This happens because
only the `.flata` file for that directory is re-compiled, then ALL
the `.flata` archives were re-linked again to produce the `.apk`.
Use of `aapt2` also disables using `R.java` files to generate the
`Resource.designer.cs` file. Instead, the `R.txt` file which the
`aapt2 link` command generates is instead parsed by the
`ManagedResourceParse` to determine the Resource ID values. Using
`R.txt` should be faster, as it's an easier format to process.
`R.java` files are still *generated* as they are needed by `javac`
and needed at runtime on-device.
`aapt2` use is *disabled* by default, until more testing can be
performed. To enable `aapt2` use, set the `$(AndroidUseAapt2)`
MSBuild property to True by including the following XML fragment
in your `.csproj`:
<AndroidUseAapt2>True</AndroidUseAapt2>
or by overriding on the `msbuild` command-line:
msbuild /p:AndroidUseAapt2=True ...
Note: if `$(AndroidUseAapt2)`=True but `aapt2` isn't present, the
build will *fail* as we attempt to execute the (non-existent) `aapt2`.
This will be improved in a future commit.