blob: cad5351157f04c87a3c8b0b6c3394cc531379414 [file] [log] [blame] [view]
## 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.