blob: 74de90631edcd2a3e99d1a97a805f5ff1b50ed29 [file] [log] [blame] [view]
## Dependencies {#dependencies}
Artifacts may depend on other artifacts within AndroidX as well as sanctioned
third-party libraries. Additionally, artifacts may have toolchain dependencies
that are not explicitly specified in their `dependencies` build configuration or
don't appear in their Maven publications (`pom` or `module` files).
### Versioned artifacts {#dependencies-versioned}
One of the most difficult aspects of independently-versioned releases is
maintaining compatibility with public artifacts. In a monorepo such as Google's
repository or Android Git at `main` revision, it's easy for an artifact to
accidentally gain a dependency on a feature that may not be released on the same
schedule.
To address this problem, library owners in AndroidX can choose from several
types of dependencies:
- Project `project(":core:core")` uses the tip-of-tree sources for the
`androidx.core:core` library and requires that they be loaded in the
workspace and released at the same time.
- Playground `projectOrArtifact(":core:core")` is used for the
[Playground](/docs/playground.md) workflow and will use
tip-of-tree sources, if present in the workspace, or `SNAPSHOT` prebuilt
artifacts from [androidx.dev](http://androidx.dev) otherwise.
- Pinned `"androidx.core:core:1.4.0"` uses the prebuilt AAR and requires that
it be checked in to the `prebuilts/androidx/internal` local Maven repository
or, when using the Playground workflow, the remote Google Maven repository.
Libraries should prefer pinned dependencies with the lowest possible versions
that include the APIs or behaviors required by the library, and should only use
project or Playground specs in cases where tip-of-tree APIs or behaviors are
required.
**Do not** upgrade the version of a library's dependency to artificially boost
adoption of that version.
#### Pre-release dependencies {#dependencies-pre-release}
Pre-release suffixes **must** propagate up the dependency tree. For example, if
your artifact has a dependency on an artifact versioned `1.1.0-alpha01` then
your artifact must also carry the `alpha` suffix.
NOTE This does not apply to test dependencies: suffixes of test dependencies do
*not* carry over to your artifact.
#### Pinned versions {#dependencies-prebuilt}
To avoid issues with dependency versioning, pin your dependencies to the oldest
stable version of an artifact that includes the necessary APIs. This will ensure
that the artifact's release schedule is not accidentally tied to that of another
artifact and will allow developers to use older libraries if desired.
```
dependencies {
api("androidx.collection:collection:1.0.0")
...
}
```
Artifacts are built and tested against both pinned and tip-of-tree versions of
their dependencies to ensure behavioral compatibility.
#### Tip-of-tree versions {#dependencies-project}
Below is an example of a project dependency, which uses tip-of-tree sources for
the dependency rather than a prebuilt `JAR` or `AAR`. It ties the artifact's
release schedule to that of the dependency artifact because the dependency will
need to be released at the same time.
```
dependencies {
api(project(":collection"))
...
}
```
### Non-public APIs {#dependencies-non-public-apis}
Artifacts may depend on non-public or restricted APIs exposed within their own
artifact or another artifact in the same `groupId`; however, cross-artifact
usages are subject to binary compatibility guarantees. See
[`@RestrictTo` APIs](/docs/api_guidelines#restricted-api) for
more details.
Dependency versioning policies are enforced at build time in the `createArchive`
task, which ensures that pre-release version suffixes are propagated
appropriately. Cross-artifact API usage policies are enforced by the `checkApi`
and `checkApiRelease` tasks.
### Third-party libraries {#dependencies-3p}
Artifacts may depend on libraries developed outside of AndroidX; however, they
must conform to the following guidelines:
* Prebuilt **must** be checked into Android Git
* `prebuilts/maven_repo` is recommended if this dependency is only
intended for use with AndroidX artifacts, otherwise please use
`external`
* Prebuilt directory **must** contains an `OWNERS` file identifying one or
more individual owners (e.g. NOT a group alias)
* Library **must** be approved by legal
Please see Jetpack's
[open-source policy page](/docs/open_source.md) for more
details on using third-party libraries.
### Platform extension (sidecar JAR) dependencies {#dependencies-sidecar}
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.
Examples include Camera OEM extensions (`androidx.camera.extensions.impl`) and
Window OEM extensions (`androidx.window.extensions`).
Extension libraries may be defined in AndroidX library projects (see
`androidx.window.extensions`) or externally, ex. in AOSP alongside the platform.
In either case, we recommend that libraries use extensions as pinned, rather
than project-type, dependencies to facilitate versioning across repositories.
*Do not* ship extension interfaces to Google Maven. Teams may choose to ship
stub JARs publicly, but that is not covered by AndroidX workflows.
Project dependencies on extension libraries **must** use `compileOnly`:
`build.gradle`:
```
dependencies {
// Extension interfaces defined in Jetpack
compileOnly(project(":window:extensions:extensions"))
// Extension interfaces defined in a stub JAR
compileOnly(
fileTree(
dir: "../wear_stubs",
include: ["com.google.android.wearable-stubs.jar"]
)
)
}
```
Documentation dependencies **must** use the `stubs` configuration:
`docs-public/build.gradle`:
```
dependencies {
stubs("androidx.window:window-extensions:1.0.0-alpha01")
stubs(
fileTree(
dir: "../wear/wear_stubs/",
include: ["com.google.android.wearable-stubs.jar"]
)
)
}
```
See [Packaging and naming](/docs/api_guidelines#module-naming)
for details about defining extension interfaces in Jetpack projects.
### Types of dependencies {#dependencies-types}
AndroidX allows dependencies to be specified as `api` or `implementation` with a
"pinned" Maven spec (ex. `androidx.core:core:1.0.0`) or a "tip-of-tree" project
spec (ex. `project(":core:core")`).
Projects used in Playground, the experimental GitHub workflow, should use a
"recent" project or artifact spec (ex. `projectOrArtifact(":core:core")`) which
will default to tip-of-tree when used outside of the Playground workflow or a
pinned `SNAPSHOT` artifact otherwise.
Regardless of which dependency spec is used, all projects are built against
tip-of-tree dependencies in CI to prevent regressions and enforce Jetpack's
compatible-at-head policy.
#### `api` versus `implementation` {#dependencies-api-vs-impl}
`api`-type dependencies will appear in clients' auto-complete as though they had
added the dependency directly to their project, and Studio will run any lint
checks bundled with `api`-type dependencies.
Dependencies whose APIs are exposed in a library's API surface **must** be
included as `api`-type. For example, if your library's API surface includes
`AccessibilityNodeInfoCompat` then you will use an `api`-type dependency on the
`androidx.core:core` library.
NOTE Libraries that provide client-facing lint checks, including
`annotation-experimental`, **must** be included as `api`-type to ensure that
lint checks are run in the clients' dependent projects.
`implementation`-type dependencies will be included in the classpath, but will
not be made available at design time (ex. in auto-complete) unless the client
explicitly adds them.
#### Constraints {#dependencies-constraints}
Dependency constraints ensure that when certain libraries are used together,
they meet certain requirements. Defining a constraint on a library *does not*
pull that library into the classpath.
In Jetpack, we use constraints to ensure that atomically-grouped libraries all
resolve to the same version
([example](https://android-review.googlesource.com/c/platform/frameworks/support/+/1973425))
and, in rare cases, to avoid conflicts resulting from classes being moved
between artifacts
([example](https://android-review.googlesource.com/c/platform/frameworks/support/+/2086029)).
`core/core-ktx/build.gradle`:
```
dependencies {
// Atomic group
constraints {
implementation(project(":core:core"))
}
}
```
In *extremely* rare cases, libraries may need to define a constraint on a
project that is not in its `studiow` project set, ex. a constraint between the
Paging and Compose libraries. As a workaround, libraries may hard-code the Maven
coordinate using a version variable
([example](https://android-review.googlesource.com/c/platform/frameworks/support/+/2160202))
to indicate the tip-of-tree version.
`paging/paging-common/build.gradle`:
```
dependencies {
// Atomic group
constraints {
implementation("androidx.paging:paging-compose:${LibraryVersions.PAGING_COMPOSE}")
}
}
```
### Dependency considerations {#dependencies-health}
Generally, Jetpack libraries should avoid dependencies that negatively impact
developers without providing substantial benefit. Libraries should consider the
implications of their dependencies, including:
- Large dependencies where only a small portion is needed (e.g. APK bloat)
- Dependencies that slow down build times through annotation processing or
compiler overhead
- Dependencies which do not maintain binary compatibility and conflict with
semantic versioning guarantees
- Dependencies that are intended for server environments and don't interact
well with the Android build toolchain (e.g. R8) or runtime (e.g. ART)
#### Kotlin {#dependencies-kotlin}
Kotlin is *strongly recommended* for new libraries and the Kotlin stdlib will
already be present in the transitive dependencies of any library that depends on
`androidx.annotations`.
```
plugins {
id("AndroidXPlugin")
id("kotlin-android")
}
dependencies {
implementation(libs.kotlinStdlib)
}
```
Java-based libraries *may* migrate to Kotlin, but they must be careful to
maintain binary compatibility during the migration. Metalava does not cover all
possible aspects of migration, so some manual work will be required.
#### Kotlin reflect {#dependencies-kotlin-reflect}
Reflection in libraries is
[only allowed for backwards compatibility support](/docs/api_guidelines#sdk-reflection)
and those users should use Java reflection. `kotlin-reflect` is very costly at
runtime and should never be used.
#### Kotlin coroutines {#dependencies-coroutines}
The Kotlin coroutines library adds around 100kB post-shrinking. New libraries
that are written in Kotlin should prefer coroutines over `ListenableFuture`, but
existing libraries must consider the size impact on their clients. See
[Asynchronous work with return values](/docs/api_guidelines#async-return)
for more details on using Kotlin coroutines in Jetpack libraries.
```
dependencies {
implementation(libs.kotlinCoroutinesAndroid)
}
```
#### GSON {#dependencies-gson}
GSON relies heavily on reflection and interacts poorly with app optimization
tools like R8. Instead, consider using `org.json` which is included in the
Android platform SDK.
#### Guava {#dependencies-guava}
The full Guava library is very large and should only be used in cases where
there is a reasonable assumption that clients already depend on full Guava.
For example, consider a library `androidx.foo:foo` implemented using Kotlin
`suspend fun`s and an optional `androidx.foo:foo-guava` library that provides
`ListenableFuture` interop wrappers with a direct dependency on
`kotlinx.coroutines:kotlinx-coroutines-guava` and a transitive dependency on
Guava.
Libraries that only need `ListenableFuture` may instead depend on the standalone
`com.google.guava:listenablefuture` artifact. See
[Asynchronous work with return values](/docs/api_guidelines#async-return)
for more details on using `ListenableFuture` in Jetpack libraries.
#### Protobuf {#dependencies-protobuf}
**Note**: It is preferred to use the [`wire`](https://github.com/square/wire)
library for handling protocol buffers in Android libraries as it has a binary
stable runtime. An example of its usage can be found
[here](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:benchmark/benchmark-common/build.gradle?q=wireRuntime%20file:gradle&ss=androidx%2Fplatform%2Fframeworks%2Fsupport).
[Protocol buffers](https://developers.google.com/protocol-buffers) provide a
language- and platform-neutral mechanism for serializing structured data. The
implementation enables developers to maintain protocol compatibility across
library versions, meaning that two clients can communicate regardless of the
library versions included in their APKs.
The Protobuf library itself, however, does not guarantee ABI compatibility
across minor versions and a specific version **must** be used with a library to
avoid conflict with other dependencies used by the developer. To do this, you
must first create a new project to repackage the protobuf runtime classes, and
then have it as a dependency in the project you generate protos in. In the
project that generates protos, you must also relocate any import statements
containing `com.google.protobuf` to your target package name. The
[AndroidXRepackagePlugin](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:buildSrc/private/src/main/kotlin/androidx/build/AndroidXRepackageImplPlugin.kt)
abstracts this for you. An example of its use to repackage the protobuf runtime
library can be found
[here](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:wear/protolayout/protolayout-external-protobuf/build.gradle)
and its associated use in the library that generates protos can be found
[here](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:wear/protolayout/protolayout-proto/build.gradle).
Additionally, the Java API surface generated by the Protobuf compiler is not
guaranteed to be stable and **must not** be exposed to developers. Library
owners should wrap the generated API surface with well-documented public APIs
that follow an appropriate language-specific paradigm for constructing data
classes, e.g. the Java `Builder` pattern.
### Open-source compatibility {#dependencies-aosp}
Jetpack's [open-source](/docs/open_source.md) guidelines
require that libraries consider the open-source compatibility implications of
their dependencies, including:
- Closed-source or proprietary libraries or services that may not be available
on AOSP devices
- Dependencies that may prevent developers from effectively isolating their
tests from third-party libraries or services
Primary artifacts, e.g. `workmanager`, **must not** depend on closed-source
components including libraries and hard-coded references to packages,
permissions, or IPC mechanisms that may only be fulfilled by closed-source
components.
Optional artifacts, e.g. `workmanager-gcm`, *may* depend on closed-source
components or configure a primary artifact to be backed by a closed-source
component via service discovery or initialization.
Some examples of safely depending on closed-source components include:
- WorkManager's GCM Network Manager integration, which uses
[manifest metadata](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:work/work-gcm/src/main/AndroidManifest.xml)
for service discovery and provides an optional artifact exposing the
service.
- Downloadable Fonts integration with Play Services, which plugs in via a
[`ContentProvider`](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core/src/androidTest/java/androidx/core/provider/MockFontProvider.java)
as a service discovery mechanism with developer-specified
[signature verification](https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts#adding-certificates)
for additional security.
Note that in all cases, the developer is not *required* to use GCM or Play
Services and may instead use another compatible service implementing the same
publicly-defined protocols.
### Toolchain dependencies
Toolchain dependencies are typically specified by the AndroidX build system and
are often limited, if any, configuration on behalf of library owners.
#### Kotlin language
Several projects within AndroidX depend on aspects of the Kotlin compiler that
do not guarantee binary compatibility, which means (1) Kotlin updates within
AndroidX may be more complicated and (2) Kotlin updates may be more complicated
for external clients.
For this reason, we try to separate (1) and (2) by pinning the Kotlin language
and API versions until the new compiler has been in use in AndroidX for at least
three months.
Library owners *may* in limited cases update their Kotlin language version early
by specifying the `kotlinVersion` DSL property:
```
androidx {
kotlinVersion KOTLIN_1_9
}
```
Note that this propagates the version requirement to all dependencies and is not
appropriate for low-level libraries.
#### Java language
The Java language level determines the minimum version of the Java runtime
required for lint checks and other host-side libraries like compilers.
To avoid causing issues for clients, we try to separate Java compiler or runtime
updates from language level by pinning the Java language level to the second
most-recent stable LTS version. In extreme cases, however, we may be required to
move to a more recent version because of a dependency like AGP or Gradle.
Library owners *may*, in cases where clients are unable to update their Java
version, temporarily pin their Java language version to a lower value by
specifying the compatibility DSL properties:
```
javaExtension.apply {
// TODO(b/12345678) Remove this once clients are able to update.
sourceCompatibility = VERSION_17
targetCompatibility = VERSION_17
}
```
When doing so, library owners **must** file a bug and establish a timeline to
un-pin and rejoin the rest of AndroidX.
#### Desugaring and R8/D8
Currently, the highest Java language level supported for Android libraries is
Java 1.8 (`VERSION_1_8``) via D8/R8 desugaring. See Use Java 8 language features
and APIs for more details.
AndroidX **does not** currently support library API desugaring, so the use of
Java 8 APIs requires increasing the library's `minSdk`.
#### Android SDK
The AndroidX Core & Tooling team automatically updates the `compileSdk` value
following the first public release of a stable SDK, e.g. following SDK
finalization during the Beta stage of platform SDK development.
Library owners **must not** attempt to pin their `compileSdk` to a lower value.
Libraries that are developed against extension SDKs *may* pin their `compileSdk`
to a higher value, e.g. `34-ext5` when the rest of AndroidX is using `34`.