Merge "Document how resources are built with and without resource processor" into main
This commit is contained in:
89
docs/resources.md
Normal file
89
docs/resources.md
Normal file
@@ -0,0 +1,89 @@
|
||||
## Soong Android Resource Compilation
|
||||
|
||||
The Android build process involves several steps to compile resources into a format that the Android app can use
|
||||
efficiently in android_library, android_app and android_test modules. See the
|
||||
[resources documentation](https://developer.android.com/guide/topics/resources/providing-resources) for general
|
||||
information on resources (with a focus on building with Gradle).
|
||||
|
||||
For all modules, AAPT2 compiles resources provided by directories listed in the resource_dirs directory (which is
|
||||
implicitly set to `["res"]` if unset, but can be overridden by setting the `resource_dirs` property).
|
||||
|
||||
## android_library with resource processor
|
||||
For an android_library with resource processor enabled (currently by setting `use_resource_processor: true`, but will be
|
||||
enabled by default in the future):
|
||||
- AAPT2 generates the `package-res.apk` file with a resource table that contains all resources from the current
|
||||
android_library module. `package-res.apk` files from transitive dependencies are passed to AAPT2 with the `-I` flag to
|
||||
resolve references to resources from dependencies.
|
||||
- AAPT2 generates an R.txt file that lists all the resources provided by the current android_library module.
|
||||
- ResourceProcessorBusyBox reads the `R.txt` file for the current android_library and produces an `R.jar` with an
|
||||
`R.class` in the package listed in the android_library's `AndroidManifest.xml` file that contains java fields for each
|
||||
resource ID. The resource IDs are non-final, as the final IDs will not be known until the resource table of the final
|
||||
android_app or android_test module is built.
|
||||
- The android_library's java and/or kotlin code is compiled with the generated `R.jar` in the classpath, along with the
|
||||
`R.jar` files from all transitive android_library dependencies.
|
||||
|
||||
## android_app or android_test with resource processor
|
||||
For an android_app or android_test with resource processor enabled (currently by setting `use_resource_processor: true`,
|
||||
but will be enabled by default in the future):
|
||||
- AAPT2 generates the `package-res.apk` file with a resource table that contains all resources from the current
|
||||
android_app or android_test, as well as all transitive android_library modules referenced via `static_libs`. The
|
||||
current module is overlaid on dependencies so that resources from the current module replace resources from dependencies
|
||||
in the case of conflicts.
|
||||
- AAPT2 generates an R.txt file that lists all the resources provided by the current android_app or android_test, as
|
||||
well as all transitive android_library modules referenced via `static_libs`. The R.txt file contains the final resource
|
||||
ID for each resource.
|
||||
- ResourceProcessorBusyBox reads the `R.txt` file for the current android_app or android_test, as well as all transitive
|
||||
android_library modules referenced via `static_libs`, and produces an `R.jar` with an `R.class` in the package listed in
|
||||
the android_app or android_test's `AndroidManifest.xml` file that contains java fields for all local or transitive
|
||||
resource IDs. In addition, it creates an `R.class` in the package listed in each android_library dependency's
|
||||
`AndroidManifest.xml` file that contains final resource IDs for the resources that were found in that library.
|
||||
- The android_app or android_test's java and/or kotlin code is compiled with the current module's `R.jar` in the
|
||||
classpath, but not the `R.jar` files from transitive android_library dependencies. The `R.jar` file is also merged into
|
||||
the program classes that are dexed and placed in the final APK.
|
||||
|
||||
## android_app, android_test or android_library without resource processor
|
||||
For an android_app, android_test or android_library without resource processor enabled (current the default, or
|
||||
explicitly set with `use_resource_processor: false`):
|
||||
- AAPT2 generates the `package-res.apk` file with a resource table that contains all resources from the current
|
||||
android_app, android_test or android_library module, as well as all transitive android_library modules referenced via
|
||||
`static_libs`. The current module is overlaid on dependencies so that resources from the current module replace
|
||||
resources from dependencies in the case of conflicts.
|
||||
- AAPT2 generates an `R.java` file in the package listed in each the current module's `AndroidManifest.xml` file that
|
||||
contains resource IDs for all resources from the current module as well as all transitive android_library modules
|
||||
referenced via `static_libs`. The same `R.java` containing all local and transitive resources is also duplicated into
|
||||
every package listed in an `AndroidManifest.xml` file in any static `android_library` dependency.
|
||||
- The module's java and/or kotlin code is compiled along with all the generated `R.java` files.
|
||||
|
||||
|
||||
## Downsides of legacy resource compilation without resource processor
|
||||
|
||||
Compiling resources without using the resource processor results in a generated R.java source file for every transitive
|
||||
package that contains every transitive resource. For modules with large transitive dependency trees this can be tens of
|
||||
thousands of resource IDs duplicated in tens to a hundred java sources. These java sources all have to be compiled in
|
||||
every successive module in the dependency tree, and then the final R8 step has to drop hundreds of thousands of
|
||||
unreferenced fields. This results in significant build time and disk usage increases over building with resource
|
||||
processor.
|
||||
|
||||
## Converting to compilation with resource processor
|
||||
|
||||
### Reference resources using the package name of the module that includes them.
|
||||
Converting an android_library module to build with resource processor requires fixing any references to resources
|
||||
provided by android_library dependencies to reference the R classes using the package name found in the
|
||||
`AndroidManifest.xml` file of the dependency. For example, when referencing an androidx resource:
|
||||
```java
|
||||
View.inflate(mContext, R.layout.preference, null));
|
||||
```
|
||||
must be replaced with:
|
||||
```java
|
||||
View.inflate(mContext, androidx.preference.R.layout.preference, null));
|
||||
```
|
||||
|
||||
### Use unique package names for each module in `AndroidManifest.xml`
|
||||
|
||||
Each module will produce an `R.jar` containing an `R.class` in the package specified in it's `AndroidManifest.xml`.
|
||||
If multiple modules use the same package name they will produce conflicting `R.class` files, which can cause some
|
||||
resource IDs to appear to be missing.
|
||||
|
||||
If existing code has multiple modules that contribute resources to the same package, one option is to move all the
|
||||
resources into a single resources-only `android_library` module with no code, and then depend on that from all the other
|
||||
modules.
|
Reference in New Issue
Block a user