| ## Annotations {#annotation} |
| |
| ### Annotation processors {#annotation-processor} |
| |
| 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](https://docs.gradle.org/current/userguide/java_plugin.html#sec:incremental_annotation_processing) |
| documentation for information on how to opt-in. |
| |
| ### `@RequiresOptIn` APIs {#experimental-api} |
| |
| Jetpack libraries may choose to annotate API surfaces as unstable using either |
| Kotlin's |
| [`@RequiresOptIn` meta-annotation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-requires-opt-in/) |
| for APIs written in Kotlin or Jetpack's |
| [`@RequiresOptIn` meta-annotation](https://developer.android.com/reference/kotlin/androidx/annotation/RequiresOptIn) |
| 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](#same-version-atomic-groups) and *may not* use the `@OptIn` |
| annotation except in the following cases: |
| |
| * A library within a same-version group *may* call an experimental API exposed |
| by another library **within its same-version group**. In this case, API |
| compatibility guarantees are covered under the same-version group policies |
| and the library *may* use the `@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.** |
| * An `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`. |
| |
| #### When to mark an API surface as experimental |
| |
| *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`. |
| |
| #### How to mark an API surface as experimental |
| |
| 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. |
| |
| ```java |
| dependencies { |
| implementation(project(":annotation:annotation-experimental")) |
| } |
| ``` |
| |
| See Kotlin's |
| [opt-in requirements documentation](https://kotlinlang.org/docs/reference/opt-in-requirements.html) |
| for general usage information. If you are writing experimental Java APIs, you |
| will use the Jetpack |
| [`@RequiresOptIn` annotation](https://developer.android.com/reference/kotlin/androidx/annotation/RequiresOptIn) |
| rather than the Kotlin compiler's annotation. |
| |
| #### How to transition an API out of experimental |
| |
| 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` APIs {#restricted-api} |
| |
| Jetpack'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: |
| |
| * There are no runtime restrictions on calling hidden APIs |
| * Android Studio will not warn if hidden APIs are called using reflection |
| * Hidden APIs will still show in Android Studio's auto-complete |
| |
| 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 surfaces {#private-api-types} |
| |
| To 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: |
| |
| <table> |
| <tr> |
| <td><code>RestrictTo.Scope</code></td> |
| <td>Visibility by Maven coordinate</td> |
| <td>Versioning</td> |
| <td>Note</td> |
| </tr> |
| <tr> |
| <td><code>LIBRARY</code></td> |
| <td><code>androidx.concurrent:concurrent</code></td> |
| <td>No compatibility guarantees (same as private)</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td><code>LIBRARY_GROUP</code></td> |
| <td><code>androidx.concurrent:*</code></td> |
| <td>Semantic versioning (including deprecation)</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td><code>LIBRARY_GROUP_PREFIX</code></td> |
| <td><code>androidx.*:*</code></td> |
| <td>Semantic versioning (including deprecation)</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td><code>TEST</code></td> |
| <td><code>*</code></td> |
| <td>No compatibility guarantees (same as private)</td> |
| <td>Not allowed in Jetpack, use `@VisibleForTesting`</td> |
| </tr> |
| </table> |
| |
| #### Test APIs and `@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 visibility |
| |
| All `@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. |
| |
| * Libraries *must* `@RestrictTo` all `@IntDef`, `@StringDef`, and `@LongDef` |
| declarations to create a warning when the type is used incorrectly. |
| * Libraries *must* expose constants used to define the `@IntDef` etc at the |
| same Java visibility as the hidden `@IntDef` |
| |
| Here is a complete example of an `@IntDef` |
| |
| ```java |
| // 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](https://android.googlesource.com/platform/developers/docs/+/refs/heads/main/api-guidelines/framework.md#framework-hide-typedefs) |
| |
| #### `*current.txt` File Explanation {#currenttxt} |
| |
| In this example, `1.3.0-beta02.txt` is just used for an example. This will match |
| the current library version. |
| |
| <table> |
| <tr> |
| <td><code>api/current.txt</code></td> |
| <td>All public APIs.</td> |
| </tr> |
| <tr> |
| <td><code>api/1.3.0-beta02.txt</code></td> |
| <td>All public APIs available in version <code>1.3.0-beta02</code>. |
| Used to enforce compatibility in later versions. This file is only |
| generated during Beta.</td> |
| </tr> |
| <tr> |
| <td><code>api/public_plus_experimental_current.txt </code></td> |
| <td>Superset of all public APIs (<code>api/current.txt</code>) and all |
| experimental/<code>RequiresOptIn</code> APIs. |
| </td> |
| </tr> |
| <tr> |
| <td><code>api/public_plus_experimental_1.3.0-beta03.txt</code></td> |
| <td>Superset of all public APIs (<code>api/1.3.0-beta02.txt.txt</code>) and all |
| experimental/RequiresOptIn APIs, as available in version |
| <code>1.3.0-beta02.txt</code>. Only generated during Beta.</td> |
| <tr> |
| <td><code>api/restricted_current.txt</code></td> |
| <td>Superset of all public APIs (<code>api/current.txt</code>) and |
| all <code>RestrictTo</code> APIs that require compatibility across |
| versions. |
| <p/>Specifically, includes <code>@RestrictTo(LIBRARY_GROUP)</code> |
| (for non-atomically versioned groups) and |
| <code>@RestrictTo(LIBRARY_GROUP_PREFIX)</code> (for all libraries).</td> |
| </tr> |
| <tr> |
| <td><code>api/restricted_1.3.0-beta02.txt.txt</code></td> |
| <td>Superset of all public APIs (<code>api/current.txt</code>) and |
| all <code>RestrictTo</code> APIs that require compatibility across |
| versions, as available in version <code>1.3.0-beta02.txt</code>. |
| <p/> |
| Specifically, includes <code>@RestrictTo(LIBRARY_GROUP)</code> |
| (for non-atomically versioned groups) and |
| <code>@RestrictTo(LIBRARY_GROUP_PREFIX)</code> (for all libraries). |
| This file is only generated during Beta.</td> |
| </tr> |
| </table> |