Resources

Generally, follow the official Android guidelines for app 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 formats 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

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

<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>

Public declaration

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>

More information

See also the official Android Gradle Plugin documentation for Private Resources.

Manifest entries (AndroidManifest.xml)

Metadata tags (<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.

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>
package androidx.libraryname.featurename;

/**
 * A placeholder service to avoid adding application-level metadata. The service
 * is only used to expose metadata defined in the library's manifest. It is
 * never invoked.
 */
public final class MetadataHolderService {
  public MetadataHolderService() {}

  @Override
  public IBinder onBind(Intent intent) {
    throw new UnsupportedOperationException();
  }
}