Generally, follow the official Android guidelines for app resources. Special guidelines for library resources are noted below.
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.
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
.
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
<resources> <attr name="fontProviderPackage" format="string" /> <declare-styleable name="FontFamily"> <attr name="fontProviderPackage" /> </declare-styleable> </resources>
Translatable strings must be contained within files named strings.xml
to be picked up for translation.
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.
All public resource definitions should be documented, including top-level definitions and re-uses inside <styleable>
elements:
src/main/res/attrs.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
<resources> <!-- Color for Material Blue-Grey 900. --> <color name="material_blue_grey_900">#ff263238</color> </resources>
Resources are declared public by providing a separate <public />
element with a matching type:
src/main/res/public.xml
<resources> <public name="fontProviderPackage" type="attr" /> <public name="material_blue_grey_900" type="color" /> </resources>
See also the official Android Gradle Plugin documentation for Private Resources.
AndroidManifest.xml
)<meta-data>
)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.
<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.
<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.