docs/api_guidelines/modules.md
Java packages within Jetpack follow the format androidx.<feature-name>. All
classes within a feature's artifact must reside within this package, and may
further subdivide into androidx.<feature-name>.<layer> using standard Android
layers (app, widget, etc.) or layers specific to the feature.
Maven specifications use the groupId format androidx.<feature-name> and
artifactId format <feature-name> to match the Java package. For example,
androidx.core.role uses the Maven spec androidx.core:core-role.
Sub-features that can be separated into their own artifact are recommended to use the following formats:
androidx.<feature-name>.<sub-feature>.<layer>androidx.<feature-name><feature-name>-<sub-feature>Gradle project names and directories follow the Maven spec format, substituting
the project name separator : or directory separator / for the Maven
separators . or :. For example, androidx.core:core-role would use project
name :core:core-role and directory /core/core-role.
Android namespaces should be unique and match the module's root Java package. If the root Java package is not unique, include the sub-feature name.
android {
namespace "androidx.core.role"
}
New modules in androidx can be created using the project creator script.
NOTE Modules for OEM-implemented shared libraries (also known as extensions or
sidecars) that ship on-device and are referenced via the <uses-library> tag
should follow the naming convention com.android.extensions.<feature-name> to
avoid placing androidx-packaged code in the platform's boot classpath.
The name and description fields of the androidx configuration block are
used to generate Maven artifact metadata, which is displayed on the artifact's
maven.google.com entry and d.android.com landing page.
androidx {
name = "WorkManager Kotlin Extensions"
description = "Kotlin-friendly extensions for WorkManager."
}
The name should be a human-readable, title-cased representation of the artifact's Maven coordinate. All components of the name must appear in the artifact's Maven group or artifact ID, with some exceptions:
work, "Android for Cars" as car, or "Kotlin
Extensions" as ktxviewDo not use the following terms in the name:
The description should be a single phrase that completes the sentence, "This library provides ...". This phrase should provide enough description that a developer can decide whether they might want to learn more about using your library. Do not simply repeat the name of the library.
Libraries developed in AndroidX follow a consistent project naming and directory structure.
Library groups should organize their projects into directories and project names (in brackets) as:
<feature-name>/
<feature-name>-<sub-feature>/ [<feature-name>:<feature-name>-<sub-feature>]
samples/ [<feature-name>:<feature-name>-<sub-feature>-samples]
integration-tests/
testapp/ [<feature-name>:testapp]
testlib/ [<feature-name>:testlib]
For example, the navigation library group's directory structure is:
navigation/
navigation-benchmark/ [navigation:navigation-benchmark]
...
navigation-ui/ [navigation:navigation-ui]
navigation-ui-ktx/ [navigation:navigation-ui-ktx]
integration-tests/
testapp/ [navigation:integration-tests:testapp]
Note: The terms project, module, and library are often used interchangeably within AndroidX, with project being the technical term used by Gradle to describe a build target, e.g. a library that maps to a single AAR.
New projects can be created using our project creation gradle task available in our repo.
It will create a new project with the proper structure and configuration based on your project needs!
To use it, run the task:
cd ~/androidx-main/frameworks/support && ./gradlew :createProject
You will be prompted to enter the project details.
If the module you are creating is an application (not a library), such as you
might want for integration-tests, edit the project's build.gradle file and
replace the plugin id("com.android.library") with
id("com.android.application"). This allows you to run activities in that
module from within Android Studio.
If you are creating an unpublished module such as an integration test app with
the project creator script, it may not make sense to follow the same naming
conventions as published libraries. In this situation it is safe to comment out
the artifact_id validation from the script or rename the module after it has
been created.
-testing for an artifact intended to be used while testing usages of your
library, e.g. androidx.room:room-testing-core for a low-level artifact that may contain public APIs but is
primarily intended for use by other libraries in the group-common for a low-level, platform-agnostic Kotlin multi-platform artifact
intended for both client use and use by other libraries in the group-ktx for a Kotlin artifact that exposes idiomatic Kotlin APIs as an
extension to a Java-only library. Note that new modules should be written in
Kotlin rather than using -ktx artifacts.-samples for sample code which can be inlined in documentation (see
Sample code in Kotlin modules-<third-party> for an artifact that integrates an optional third-party API
surface, e.g. -proto, -guava, or -rxjava2. This is common for Kotlin
libraries adapting their async APIs for Java clients. Note that a major
version is included in the sub-feature name (ex. rxjava3) for third-party
API surfaces where the major version indicates binary compatibility (only
needed for post-1.x).Artifacts should not use -impl or -base to indicate that a library is an
implementation detail shared within the group. Instead, use -core or -common
as appropriate.
Use caution when splitting existing modules into smaller modules; doing so creates the potential for class duplication issues when a developer depends on a new sub-module alongside the older top-level module. Consider the following scenario:
androidx.library:1.0.0
androidx.library.Aandroidx.library.util.BThis module is split, moving androidx.library.util.B to a new module:
androidx.library:1.1.0
androidx.library.Aandroidx.library.util:1.1.0androidx.library.util:1.1.0
androidx.library.util.BA developer writes an app that depends directly on androidx.library.util:1.1.0
and also transitively pulls in androidx.library:1.0.0. Their app will no
longer compile due to class duplication of androidx.library.util.B.
To avoid this issue make sure to define a
dependency constraint
onandroidx.library:1.1.0 from inside androidx.library.util:1.1.0. This
ensures that if a developer depends on androidx.library.util:1.1.0, the
minimum version of androidx.library will be 1.1.0, avoiding the class
duplication.
Same-version groups already have constraints defined, so existing modules that are already in a same-version group may be split into sub-modules provided that (a) the sub-modules are also in the same-version group and (b) the full API surface of the existing module is preserved through transitive dependencies, e.g. the sub-modules are added as dependencies of the existing module.
Library groups are encouraged to opt-in to a same-version policy whereby all libraries in the group use the same version and express exact-match dependencies on libraries within the group. Such groups must increment the version of every library at the same time and release all libraries at the same time.
Atomic groups are specified in libraryversions.toml:
// Non-atomic library group
APPCOMPAT = { group = "androidx.appcompat" }
// Atomic library group
APPSEARCH = { group = "androidx.appsearch", atomicGroupVersion = "versions.APPSEARCH" }
Libraries within an atomic group should not specify a version in their
build.gradle:
androidx {
name = 'AppSearch'
publish = Publish.SNAPSHOT_AND_RELEASE
inceptionYear = '2019'
description = 'Provides local and centralized app indexing'
}
The benefits of using an atomic group are:
@RestrictTo(LIBRARY_GROUP) APIs are treated as private APIs and not
tracked for binary compatibility@RequiresOptIn APIs defined within the group may be used without any
restrictions between libraries in the groupPotential drawbacks include:
There is one exception to the same-version policy: newly-added libraries within an atomic group may be "quarantined" from other libraries to allow for rapid iteration until they are API-stable. For example:
androidx {
name = "androidx.emoji2:emoji2-emojipicker"
mavenVersion = LibraryVersions.EMOJI2_QUARANTINE
}
EMOJI2_QUARANTINE = "1.0.0-alpha01"
A quarantined library must stay within the 1.0.0-alphaXX cycle until it is
ready to conform to the same-version policy. While in quarantime, a library is
treated at though it is in a separate group from its nomical same-version group:
1.0.0-alphaXX, e.g. same-version policy is not enforcedproject or pinned version dependencies, e.g. strict-match
dependencies are not enforcedLIBRARY-GROUP-scoped APIsWhen the library would like to leave quarantine, it must wait for its atomic
group to be within a beta cycle and then match the version. It is okay for a
library in this situation to skip versions, e.g. move directly from
1.0.0-alpha02 to 2.1.3-beta06.
When a library adds Kotlin Multiplatform support, it is permitted to have different versions for the multiplatform artifacts until they reach alpha quality.
To specify an atomic version group for the Kotlin Multiplatform artifacts, use
the multiplatformGroupVersion property in the libraryversions.toml file.
[versions]
DATASTORE = "1.2.3"
DATASTORE_KMP = "1.2.3-dev05"
[groups]
DATASTORE = { group = "androidx.datastore", atomicGroupVersion = "versions.DATASTORE", multiplatformGroupVersion = "versions.DATASTORE_KMP" }
Note that you can specify a multiplatformGroupVersion if and only if you are
also specifying a atomicGroupVersion.
If your Kotlin Multiplatform Library does not have atomic version groups, you
can specify a KMP specifc version in the build gradle file:
import androidx.build.KmpPlatformsKt
...
androidx {
name = "Collection"
type = LibraryType.KMP_LIBRARY
mavenVersion = KmpPlatformsKt.enableNative(project) ? LibraryVersions.COLLECTION_KMP : LibraryVersions.KMP
inceptionYear = "2018"
description = "Standalone efficient collections."
}
minSdkVersion {#module-minsdkversion}The recommended minimum SDK version for new Jetpack libraries is currently 24 (Android 7.0, Nougat). This SDK was chosen to represent 99% of active devices based on Play Store check-ins (see Android Studio distribution metadata for current statistics). This maximizes potential users for external developers while minimizing the amount of overhead necessary to support legacy versions.
However, if no explicit minimum SDK version is specified for a library, the default is 23 (Android 6.0, Marshmallow).
Note that a library must not depend on another library with a higher
minSdkVersion that its own, so it may be necessary for a new library to match
its dependent libraries' minSdkVersion.
Individual modules may choose a higher minimum SDK version for business or technical reasons. This is common for device-specific modules such as Auto or Wear.
Individual classes or methods may be annotated with the @RequiresApi annotation to indicate divergence from the overall module's minimum SDK version. Note that this pattern is not recommended because it leads to confusion for external developers and should be considered a last-resort when backporting behavior is not feasible.
Platform extension or "sidecar JAR" libraries ship as part of the Android system
image and are made available to developers through the <uses-library> manifest
tag.
Interfaces for platform extension libraries may be defined in Jetpack, like
androidx.window.extensions, but must be implemented in the Android platform
via AOSP or by device manufacturers. See
WindowManager Extensions
for more details on the platform-side implementation of extension libraries,
including motivations for their use.
See Platform extension (sidecar JAR) dependencies for guidelines on depending on extension libraries defined externally or within Jetpack.
-ktx, -guava, etc.) {#module-ktx}New libraries should prefer Kotlin sources with built-in Java compatibility via
@JvmName and other affordances of the Kotlin language. They may optionally
expose framework- or language-specific extension libraries like -guava or
-rxjava3.
Existing Java-sourced libraries may benefit from extending their API surface
with Kotlin-friendly APIs in a -ktx extension library.
Extension libraries may only provide extensions for a single base library's
API surface and its name must match the base library exactly. For example,
work:work-ktx may only provide extensions for APIs exposed by work:work.
Additionally, an extension library must specify an api-type dependency on
the base library and must be versioned and released identically to the base
library.
Extension libraries should not expose new functionality; they should only provide language- or framework-friendly versions of existing library functionality.