Annotation processors should opt-in to incremental annotation processing to avoid triggering a full recompilation on every client source code change. See Gradle's Incremental annotation processing documentation for information on how to opt-in.
@RequiresOptIn
APIsJetpack libraries may choose to annotate API surfaces as unstable using either Kotlin‘s @RequiresOptIn
meta-annotation for APIs written in Kotlin or Jetpack’s @RequiresOptIn
meta-annotation for APIs written in Java.
@RequiresOptIn
at-a-glance:
- Use for unstable API surfaces
- Can be called by anyone
- Documented in public documentation
- Does not maintain compatibility
For either annotation, API surfaces marked as opt-in are considered alpha and will be excluded from API compatibility guarantees. Due to the lack of compatibility guarantees, stable libraries must never call experimental APIs exposed by other libraries outside of their same-version group and may not use the @OptIn
annotation except in the following cases:
@OptIn
annotation to prevent propagation of the experimental property. Library owners must exercise care to ensure that post-alpha APIs backed by experimental APIs actually meet the release criteria for post-alpha APIs.alpha
library may use experimental APIs from outside its same-version group. These usages must be removed when the library moves to beta
.NOTE JetBrains's own usage of @RequiresOptIn
in Kotlin language libraries varies and may indicate binary instability, functional instability, or simply that an API is really difficult to use. Jetpack libraries should treat instances of @RequiresOptIn
in JetBrains libraries as indicating binary instability and avoid using them outside of alpha
; however, teams are welcome to obtain written assurance from JetBrains regarding binary stability of specific APIs. @RequiresOptIn
APIs that are guaranteed to remain binary compatible may be used in beta
, but usages must be removed when the library moves to rc
.
Do not use @RequiresOptIn
for a stable API surface that is difficult to use. It is not a substitute for a properly-designed API surface.
Do not use @RequiresOptIn
for an API surface that is unreliable or unstable because it is missing tests. It is not a substitute for a properly-tested API surface, and all APIs -- including those in alpha
-- are expected to be functionally stable.
Do not use @RequiresOptIn
for an internal-facing API surface. Use either the appropriate language visibility (ex. private
or internal
) or @RestrictTo
.
Do not use @RequiresOptIn
for an API that you expect library developers to call. Experimental APIs do not maintain binary compatibility guarantees, and you will put external clients in a difficult situation.
Do use @RequiresOptIn
for API surfaces that must be publicly available and documented but need the flexibility to stay in alpha
during the rest of the library's beta
, rc
, or stable cycles, and continue to break compatibility in beta
.
All libraries using @RequiresOptIn
annotations must depend on the androidx.annotation:annotation-experimental
artifact regardless of whether they are using the androidx
or Kotlin annotation. This artifact provides Lint enforcement of experimental usage restrictions for Kotlin callers as well as Java (which the Kotlin annotation doesn‘t handle on its own, since it’s a Kotlin compiler feature). Libraries may include the dependency as api
-type to make @OptIn
available to Java clients; however, this will also unnecessarily expose the @RequiresOptIn
annotation.
dependencies { implementation(project(":annotation:annotation-experimental")) }
See Kotlin‘s opt-in requirements documentation for general usage information. If you are writing experimental Java APIs, you will use the Jetpack @RequiresOptIn
annotation rather than the Kotlin compiler’s annotation.
When an API surface is ready to transition out of experimental, the annotation may only be removed during an alpha pre-release stage. Removing the experimental marker from an API is equivalent to adding the API to the current API surface.
When transitioning an entire feature surface out of experimental, you should remove the definition for the associated experimental marker annotation.
When making any change to the experimental API surface, you must run ./gradlew updateApi
prior to uploading your change.
NOTE Experimental marker annotation are themselves experimental, meaning that it's considered binary compatible to refactor or remove an experimental marker annotation.
Note: Experimental APIs are reviewed by API Council both when the APIs are first introduced, and when they are stabilized. API Council may have additional feedback during stabilization.
@RestrictTo
APIsJetpack's library tooling supports hiding JVM-visible (ex. public
and protected
) APIs from developers using a combination of the @RestrictTo
source annotation.
@RestrictTo
at-a-glance:
- Use for internal-facing API surfaces
- Can be called within the specified
Scope
- Does not appear in public documentation
- Does not maintain compatibility in most scopes
While restricted APIs do not appear in documentation and Android Studio will warn against calling them, hiding an API does not provide strong guarantees about usage:
These annotations indicate that developers should not call an API that is technically public from a JVM visibility perspective. Hiding APIs is often a sign of a poorly-abstracted API surface, and priority should be given to creating public, maintainable APIs and using Java visibility modifiers.
Do not use @RestrictTo
to bypass API tracking and review for production APIs; instead, rely on API+1 and API Council review to ensure APIs are reviewed on a timely basis.
Do not use @RestrictTo
for implementation detail APIs that are used between libraries and could reasonably be made public.
Do use @RestrictTo(LIBRARY)
for implementation detail APIs used within a single library (but prefer Java language private
or default
visibility).
RestrictTo.Scope
and inter- versus intra-library API surfacesTo maintain binary compatibility between different versions of libraries, restricted API surfaces that are used between libraries within Jetpack (inter-library APIs) must follow the same Semantic Versioning rules as public APIs. Inter-library APIs should be annotated with the @RestrictTo(LIBRARY_GROUP)
source annotation.
Restricted API surfaces used within a single library (intra-library APIs), on the other hand, may be added or removed without any compatibility considerations. It is safe to assume that developers never call these APIs, even though it is technically feasible. Intra-library APIs should be annotated with the @RestrictTo(LIBRARY)
source annotation.
In all cases, correctness and compatibility tracking are handled by AndroidX's build system and lint checks.
The following table shows the visibility of a hypothetical API within Maven coordinate androidx.concurrent:concurrent
when annotated with a variety of scopes:
@VisibleForTesting
For library APIs that should only be used from test code -- including the library‘s own tests, integration test apps, app developers’ tests, or third-party testing libraries -- use the @VisibleForTesting
annotation to ensure that the API is only called from test source sets.
Libraries targeted at multi-platform usage in IntelliJ may use @TestOnly
to ensure that the IDE enforces usage restrictions.
Jetpack prefers that libraries expose test APIs as public API and maintain binary compatibility. This ensures that whatever a library needs in its own integration test app is available to app developers and may be safely called in third-party testing libraries.
In cases where a test API needs restricted visibility or flexibility around binary compatibility, the @VisibleForTesting
annotation may be combined with a @RestrictTo
scope or @RequiresOptIn
feature group.
@IntDef
@StringDef
and @LongDef
and visibilityAll @IntDef
, @StringDef
, and @LongDef
will be stripped from resulting artifacts to avoid issues where compiler inlining constants removes information as to which @IntDef
defined the value of 1
. The annotations are extracted and packaged separately to be read by Android Studio and lint which enforces the types in application code.
@RestrictTo
all @IntDef
, @StringDef
, and @LongDef
declarations to create a warning when the type is used incorrectly.@IntDef
etc at the same Java visibility as the hidden @IntDef
Here is a complete example of an @IntDef
// constants match Java visibility of ExifStreamType // code outside this module interacting with ExifStreamType uses these constants public static final int STREAM_TYPE_FULL_IMAGE_DATA = 1; public static final int STREAM_TYPE_EXIF_DATA_ONLY = 2; @RestrictTo(RestrictTo.Scope.LIBRARY) // Don't export ExifStreamType outside module @Retention(RetentionPolicy.SOURCE) @IntDef({ STREAM_TYPE_FULL_IMAGE_DATA, STREAM_TYPE_EXIF_DATA_ONLY, }) public @interface ExifStreamType {}
Java visibility should be set as appropriate for the code in question (private
, package
, or public
) and is unrelated to hiding.
For more, read the section in Android API Council Guidelines
*current.txt
File ExplanationIn this example, 1.3.0-beta02.txt
is just used for an example. This will match the current library version.