| ## Resources {#resources} | |
| Generally, follow the official Android guidelines for | |
| [app resources](https://developer.android.com/guide/topics/resources/providing-resources). | |
| Special guidelines for library resources are noted below. | |
| ### Defining new resources | |
| Libraries may define new value and attribute resources using the standard | |
| application directory structure used by Android Gradle Plugin: | |
| ``` | |
| src/main/res/ | |
| values/ | |
| attrs.xml Theme attributes and styleables | |
| dimens.xml Dimensional values | |
| public.xml Public resource definitions | |
| ... | |
| ``` | |
| However, some libraries may still be using non-standard, legacy directory | |
| structures such as `res-public` for their public resource declarations or a | |
| top-level `res` directory and accompanying custom source set in `build.gradle`. | |
| These libraries will eventually be migrated to follow standard guidelines. | |
| #### Naming conventions | |
| Libraries follow the Android platform's resource naming conventions, which use | |
| `camelCase` for attributes and `underline_delimited` for values. For example, | |
| `R.attr.fontProviderPackage` and `R.dimen.material_blue_grey_900`. | |
| #### Attribute formats | |
| At build time, attribute definitions are pooled globally across all libraries | |
| used in an application, which means attribute `format`s *must* be identical for | |
| a given `name` to avoid a conflict. | |
| Within Jetpack, new attribute names *must* be globally unique. Libraries *may* | |
| reference existing public attributes from their dependencies. See below for more | |
| information on public attributes. | |
| When adding a new attribute, the format should be defined *once* in an `<attr | |
| />` element in the definitions block at the top of `src/main/res/attrs.xml`. | |
| Subsequent references in `<declare-styleable>` elements *must* not include a | |
| `format`: | |
| `src/main/res/attrs.xml` | |
| ```xml | |
| <resources> | |
| <attr name="fontProviderPackage" format="string" /> | |
| <declare-styleable name="FontFamily"> | |
| <attr name="fontProviderPackage" /> | |
| </declare-styleable> | |
| </resources> | |
| ``` | |
| #### Translatable strings | |
| Translatable strings *must* be contained within files named `strings.xml` to be | |
| picked up for translation. | |
| ### Public resources | |
| Library resources in Jetpack are private by default, which means developers are | |
| discouraged from referencing any defined attributes or values from XML or code; | |
| however, library resources may be declared public to make them available to | |
| developers. | |
| Public library resources are considered API surface and are thus subject to the | |
| same API consistency and documentation requirements as Java APIs. | |
| Libraries will typically only expose theme attributes, ex. `<attr />` elements, | |
| as public API so that developers can set and retrieve the values stored in | |
| styles and themes. Exposing values -- such as `<dimen />` and `<string />` -- or | |
| images -- such as drawable XML and PNGs -- locks the current state of those | |
| elements as public API that cannot be changed without a major version bump. That | |
| means changing a publicly-visible icon would be considered a breaking change. | |
| #### Documentation | |
| All public resource definitions should be documented, including top-level | |
| definitions and re-uses inside `<styleable>` elements: | |
| `src/main/res/attrs.xml` | |
| ```xml | |
| <resources> | |
| <!-- String specifying the application package for a Font Provider. --> | |
| <attr name="fontProviderPackage" format="string" /> | |
| <!-- Attributes that are read when parsing a <fontfamily> tag. --> | |
| <declare-styleable name="FontFamily"> | |
| <!-- The package for the Font Provider to be used for the request. This is | |
| used to verify the identity of the provider. --> | |
| <attr name="fontProviderPackage" /> | |
| </declare-styleable> | |
| </resources> | |
| ``` | |
| `src/main/res/colors.xml` | |
| ```xml | |
| <resources> | |
| <!-- Color for Material Blue-Grey 900. --> | |
| <color name="material_blue_grey_900">#ff263238</color> | |
| </resources> | |
| ``` | |
| #### Public declaration | |
| Resources are declared public by providing a separate `<public />` element with | |
| a matching type: | |
| `src/main/res/public.xml` | |
| ```xml | |
| <resources> | |
| <public name="fontProviderPackage" type="attr" /> | |
| <public name="material_blue_grey_900" type="color" /> | |
| </resources> | |
| ``` | |
| #### More information | |
| See also the official Android Gradle Plugin documentation for | |
| [Private Resources](https://developer.android.com/studio/projects/android-library#PrivateResources). | |
| ### Manifest entries (`AndroidManifest.xml`) {#resources-manifest} | |
| #### Metadata tags (`<meta-data>`) {#resources-manifest-metadata} | |
| Developers **must not** add `<application>`-level `<meta-data>` tags to library | |
| manifests or advise developers to add such tags to their application manifests. | |
| Doing so may *inadvertently cause denial-of-service attacks against other apps* | |
| (see b/194303997). | |
| Assume a library adds a single item of meta-data at the application level. When | |
| an app uses the library, that meta-data will be merged into the resulting app's | |
| application entry via manifest merger. | |
| If another app attempts to obtain a list of all activities associated with the | |
| primary app, that list will contain multiple copies of the `ApplicationInfo`, | |
| each of which in turn contains a copy of the library's meta-data. As a result, | |
| one `<metadata>` tag may become hundreds of KB on the binder call to obtain the | |
| list -- resulting in apps hitting transaction too large exceptions and crashing. | |
| ```xml {.bad} | |
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
| package="androidx.librarypackage"> | |
| <application> | |
| <meta-data | |
| android:name="keyName" | |
| android:value="@string/value" /> | |
| </application> | |
| </manifest> | |
| ``` | |
| Instead, developers may consider adding `<metadata>` nested inside of | |
| placeholder `<service>` tags. | |
| ```xml {.good} | |
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
| package="androidx.librarypackage"> | |
| <application> | |
| <service | |
| android:name="androidx.librarypackage.MetadataHolderService" | |
| android:enabled="false" | |
| android:exported="false"> | |
| <meta-data | |
| android:name="androidx.librarypackage.MetadataHolderService.KEY_NAME" | |
| android:resource="@string/value" /> | |
| </service> | |
| </application> | |
| ``` | |
| Note: there is no need to provide a definition for the `MetadataHolderService` | |
| class, as it is merely a placeholder and will never be called. |