xref: /aosp_15_r20/build/soong/docs/resources.md (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1## Soong Android Resource Compilation
2
3The Android build process involves several steps to compile resources into a format that the Android app can use
4efficiently in android_library, android_app and android_test modules.  See the
5[resources documentation](https://developer.android.com/guide/topics/resources/providing-resources) for general
6information on resources (with a focus on building with Gradle).
7
8For all modules, AAPT2 compiles resources provided by directories listed in the resource_dirs directory (which is
9implicitly set to `["res"]` if unset, but can be overridden by setting the `resource_dirs` property).
10
11## android_library with resource processor
12For an android_library with resource processor enabled (currently by setting `use_resource_processor: true`, but will be
13enabled by default in the future):
14- AAPT2 generates the `package-res.apk` file with a resource table that contains all resources from the current
15android_library module.  `package-res.apk` files from transitive dependencies are passed to AAPT2 with the `-I` flag to
16resolve references to resources from dependencies.
17- AAPT2 generates an R.txt file that lists all the resources provided by the current android_library module.
18- ResourceProcessorBusyBox reads the `R.txt` file for the current android_library and produces an `R.jar` with an
19`R.class` in the package listed in the android_library's `AndroidManifest.xml` file that contains java fields for each
20resource ID.  The resource IDs are non-final, as the final IDs will not be known until the resource table of the final
21android_app or android_test module is built.
22- The android_library's java and/or kotlin code is compiled with the generated `R.jar` in the classpath, along with the
23`R.jar` files from all transitive android_library dependencies.
24
25## android_app or android_test with resource processor
26For an android_app or android_test with resource processor enabled (currently by setting `use_resource_processor: true`,
27but will be enabled by default in the future):
28- AAPT2 generates the `package-res.apk` file with a resource table that contains all resources from the current
29android_app or android_test, as well as all transitive android_library modules referenced via `static_libs`.  The
30current module is overlaid on dependencies so that resources from the current module replace resources from dependencies
31in the case of conflicts.
32- AAPT2 generates an R.txt file that lists all the resources provided by the current android_app or android_test, as
33well as all transitive android_library modules referenced via `static_libs`.  The R.txt file contains the final resource
34ID for each resource.
35- ResourceProcessorBusyBox reads the `R.txt` file for the current android_app or android_test, as well as all transitive
36android_library modules referenced via `static_libs`, and produces an `R.jar` with an `R.class` in the package listed in
37the android_app or android_test's `AndroidManifest.xml` file that contains java fields for all local or transitive
38resource IDs.  In addition, it creates an `R.class` in the package listed in each android_library dependency's
39`AndroidManifest.xml` file that contains final resource IDs for the resources that were found in that library.
40- The android_app or android_test's java and/or kotlin code is compiled with the current module's `R.jar` in the
41classpath, but not the `R.jar` files from transitive android_library dependencies.  The `R.jar` file is also merged into
42the program  classes that are dexed and placed in the final APK.
43
44## android_app, android_test or android_library without resource processor
45For an android_app, android_test or android_library without resource processor enabled (current the default, or
46explicitly set with `use_resource_processor: false`):
47- AAPT2 generates the `package-res.apk` file with a resource table that contains all resources from the current
48android_app, android_test or android_library module, as well as all transitive android_library modules referenced via
49`static_libs`.  The current module is overlaid on dependencies so that resources from the current module replace
50resources from dependencies in the case of conflicts.
51- AAPT2 generates an `R.java` file in the package listed in each the current module's `AndroidManifest.xml` file that
52contains resource IDs for all resources from the current module as well as all transitive android_library modules
53referenced via `static_libs`.  The same `R.java` containing all local and transitive resources is also duplicated into
54every package listed in an `AndroidManifest.xml` file in any static `android_library` dependency.
55- The module's java and/or kotlin code is compiled along with all the generated `R.java` files.
56
57
58## Downsides of legacy resource compilation without resource processor
59
60Compiling resources without using the resource processor results in a generated R.java source file for every transitive
61package that contains every transitive resource.  For modules with large transitive dependency trees this can be tens of
62thousands of resource IDs duplicated in tens to a hundred java sources.  These java sources all have to be compiled in
63every successive module in the dependency tree, and then the final R8 step has to drop hundreds of thousands of
64unreferenced fields.  This results in significant build time and disk usage increases over building with resource
65processor.
66
67## Converting to compilation with resource processor
68
69### Reference resources using the package name of the module that includes them.
70Converting an android_library module to build with resource processor requires fixing any references to resources
71provided by android_library dependencies to reference the R classes using the package name found in the
72`AndroidManifest.xml` file of the dependency.  For example, when referencing an androidx resource:
73```java
74View.inflate(mContext, R.layout.preference, null));
75```
76must be replaced with:
77```java
78View.inflate(mContext, androidx.preference.R.layout.preference, null));
79```
80
81### Use unique package names for each module in `AndroidManifest.xml`
82
83Each module will produce an `R.jar` containing an `R.class` in the package specified in it's `AndroidManifest.xml`.
84If multiple modules use the same package name they will produce conflicting `R.class` files, which can cause some
85resource IDs to appear to be missing.
86
87If existing code has multiple modules that contribute resources to the same package, one option is to move all the
88resources into a single resources-only `android_library` module with no code, and then depend on that from all the other
89modules.