blob: b4064398b28061a7c88d6c6e99cbb20a6f33e66b [file] [log] [blame] [view]
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001# Library API guidelines
2
3[TOC]
4
5## Introduction {#introduction}
6
alanv195c35f2021-06-10 14:29:40 -07007This guide is an addendum to
AndroidX Core Team2e416b22020-12-03 22:58:07 +00008s.android.com/api-guidelines,
9which covers standard and practices for designing platform APIs.
10
11All platform API design guidelines also apply to Jetpack libraries, with any
12additional guidelines or exceptions noted in this document. Jetpack libraries
13also follow
14[explicit API mode](https://kotlinlang.org/docs/reference/whatsnew14.html#explicit-api-mode-for-library-authors)
15for Kotlin libraries.
16
17## Modules {#module}
18
19### Packaging and naming {#module-naming}
20
21Java packages within Jetpack follow the format `androidx.<feature-name>`. All
22classes within a feature's artifact must reside within this package, and may
23further subdivide into `androidx.<feature-name>.<layer>` using standard Android
24layers (app, widget, etc.) or layers specific to the feature.
25
alanvb8659122021-06-14 08:55:32 -070026Maven specifications use the groupId format `androidx.<feature-name>` and
27artifactId format `<feature-name>` to match the Java package. For example,
28`androidx.core.role` uses the Maven spec `androidx.core:role`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +000029
alanvb8659122021-06-14 08:55:32 -070030Sub-features that can be separated into their own artifact are recommended to
31use the following formats:
AndroidX Core Team2e416b22020-12-03 22:58:07 +000032
alanvb8659122021-06-14 08:55:32 -070033- Java package: `androidx.<feature-name>.<sub-feature>.<layer>`
34- Maven groupId: `androidx.<feature-name>`
35- Maven artifactId: `<feature-name>-<sub-feature>`
AndroidX Core Team2e416b22020-12-03 22:58:07 +000036
alanvb8659122021-06-14 08:55:32 -070037Gradle project names and directories follow the Maven spec format, substituting
38the project name separator `:` or directory separator `/` for the Maven
39separators `.` or `:`. For example, `androidx.core:core-role` would use project
40name `:core:core-role` and directory `/core/core-role`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +000041
AndroidX Core Team9f9538a2021-06-07 12:03:58 -070042New modules in androidx can be created using the
alanv93da5db2021-08-11 13:05:51 -070043[project creator script](#module-creator).
44
AndroidX Core Teamf74ae232022-04-25 11:17:51 -040045NOTE Modules for OEM-implemented shared libraries (also known as extensions or
46sidecars) that ship on-device and are referenced via the `<uses-library>` tag
47should follow the naming convention `com.android.extensions.<feature-name>` to
48avoid placing `androidx`-packaged code in the platform's boot classpath.
49
alanv93da5db2021-08-11 13:05:51 -070050#### Project directory structure {#module-structure}
51
52Libraries developed in AndroidX follow a consistent project naming and directory
53structure.
54
55Library groups should organize their projects into directories and project names
56(in brackets) as:
57
58```
59<feature-name>/
60 <feature-name>-<sub-feature>/ [<feature-name>:<feature-name>-<sub-feature>]
AndroidX Core Team4cc85fa2021-11-23 15:58:34 +000061 samples/ [<feature-name>:<feature-name>-<sub-feature>-samples]
alanv93da5db2021-08-11 13:05:51 -070062 integration-tests/
63 testapp/ [<feature-name>:testapp]
64 testlib/ [<feature-name>:testlib]
65```
66
67For example, the `navigation` library group's directory structure is:
68
69```
70navigation/
71 navigation-benchmark/ [navigation:navigation-benchmark]
72 ...
73 navigation-ui/ [navigation:navigation-ui]
74 navigation-ui-ktx/ [navigation:navigation-ui-ktx]
75 integration-tests/
76 testapp/ [navigation:integration-tests:testapp]
77```
78
79#### Project creator script {#module-creation}
80
alanv1d2bee52021-09-13 08:49:27 -070081Note: The terms *project*, *module*, and *library* are often used
alanv93da5db2021-08-11 13:05:51 -070082interchangeably within AndroidX, with project being the technical term used by
83Gradle to describe a build target, e.g. a library that maps to a single AAR.
84
85New projects can be created using our
86[project creation script](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:development/project-creator/?q=project-creator&ss=androidx%2Fplatform%2Fframeworks%2Fsupport)
87available in our repo.
88
89It will create a new project with the proper structure and configuration based
90on your project needs!
91
92To use it:
93
94```sh
AndroidX Core Teamfa352702021-08-16 10:06:19 -070095cd ~/androidx-main/frameworks/support && \
alanv93da5db2021-08-11 13:05:51 -070096cd development/project-creator && \
97./create_project.py androidx.foo foo-bar
98```
AndroidX Core Team9f9538a2021-06-07 12:03:58 -070099
AndroidX Core Team21ccf652022-04-01 14:53:07 +0000100If you see an error message `No module named 'toml'` try the following steps.
101
102* Install necessary tools if they are not already installed
103 * (Linux) `sudo apt-get install virtualenv python3-venv`
104 * (Mac) `pip3 install virtualenv`
105* Create a virtual environment with `virtualenv androidx_project_creator` (you
106 can choose another name for your virtualenv if you wish).
107* Install the `toml` library in your virtual env with
108 `androidx_project_creator/bin/pip3 install toml`
109* Run the project creator script from your virtual env with
110 `androidx_project_creator/bin/python3
111 ./development/project-creator/create_project.py androidx.foo foo-bar`
112* Delete your virtual env with `rm -rf ./androidx-project_creator`
113 * virtualenv will automatically .gitignore itself, but you may want to to
114 remove it anyway.
115
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000116#### Common sub-feature names {#module-naming-subfeature}
117
118* `-testing` for an artifact intended to be used while testing usages of your
119 library, e.g. `androidx.room:room-testing`
120* `-core` for a low-level artifact that *may* contain public APIs but is
121 primarily intended for use by other libraries in the group
122* `-ktx` for an Kotlin artifact that exposes idiomatic Kotlin APIs as an
AndroidX Core Team0db91f02021-05-06 22:45:18 +0000123 extension to a Java-only library (see
124 [additional -ktx guidance](#module-ktx))
AndroidX Core Team4cc85fa2021-11-23 15:58:34 +0000125* `-samples` for sample code which can be inlined in documentation (see
126 [Sample code in Kotlin modules](#sample-code-in-kotlin-modules)
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000127* `-<third-party>` for an artifact that integrates an optional third-party API
128 surface, e.g. `-proto` or `-rxjava2`. Note that a major version is included
129 in the sub-feature name for third-party API surfaces where the major version
130 indicates binary compatibility (only needed for post-1.x).
131
132Artifacts **should not** use `-impl` or `-base` to indicate that a library is an
133implementation detail shared within the group. Instead, use `-core`.
134
135#### Splitting existing modules
136
alanv1d2bee52021-09-13 08:49:27 -0700137Existing modules *should not* be split into smaller modules; doing so creates
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000138the potential for class duplication issues when a developer depends on a new
139sub-module alongside the older top-level module. Consider the following
140scenario:
141
142* `androidx.library:1.0.0`
AndroidX Core Team43201242021-01-26 21:38:01 +0000143 * contains class `androidx.library.A`
144 * contains class `androidx.library.util.B`
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000145
146This module is split, moving `androidx.library.util.B` to a new module:
147
148* `androidx.library:1.1.0`
149 * contains class `androidx.library.A`
AndroidX Core Team43201242021-01-26 21:38:01 +0000150 * depends on `androidx.library.util:1.1.0`
151* `androidx.library.util:1.1.0`
152 * contains class `androidx.library.util.B`
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000153
AndroidX Core Team43201242021-01-26 21:38:01 +0000154A developer writes an app that depends directly on `androidx.library.util:1.1.0`
155and also transitively pulls in `androidx.library:1.0.0`. Their app will no
156longer compile due to class duplication of `androidx.library.util.B`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000157
158While it is possible for the developer to fix this by manually specifying a
159dependency on `androidx.library:1.1.0`, there is no easy way for the developer
160to discover this solution from the class duplication error raised at compile
161time.
162
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +0000163Same-version groups are a special case for this rule. Existing modules that are
164already in a same-version group may be split into sub-modules provided that (a)
165the sub-modules are also in the same-version group and (b) the full API surface
166of the existing module is preserved through transitive dependencies, e.g. the
167sub-modules are added as dependencies of the existing module.
168
AndroidX Core Teamee1457a2021-02-25 16:13:10 +0000169#### Same-version (atomic) groups {#modules-atomic}
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000170
171Library groups are encouraged to opt-in to a same-version policy whereby all
172libraries in the group use the same version and express exact-match dependencies
173on libraries within the group. Such groups must increment the version of every
174library at the same time and release all libraries at the same time.
175
176Atomic groups are specified in
AndroidX Core Team179f25b2022-02-04 15:20:48 -0800177[libraryversions.toml](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:libraryversions.toml):
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000178
AndroidX Core Team179f25b2022-02-04 15:20:48 -0800179```
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000180// Non-atomic library group
AndroidX Core Team179f25b2022-02-04 15:20:48 -0800181APPCOMPAT = { group = "androidx.appcompat" }
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000182// Atomic library group
AndroidX Core Team179f25b2022-02-04 15:20:48 -0800183APPSEARCH = { group = "androidx.appsearch", atomicGroupVersion = "versions.APPSEARCH" }
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000184```
185
186Libraries within an atomic group should not specify a version in their
187`build.gradle`:
188
189```groovy
190androidx {
191 name = 'AppSearch'
192 publish = Publish.SNAPSHOT_AND_RELEASE
193 mavenGroup = LibraryGroups.APPSEARCH
194 inceptionYear = '2019'
195 description = 'Provides local and centralized app indexing'
196}
197```
198
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000199The benefits of using an atomic group are:
200
201- Easier for developers to understand dependency versioning
202- `@RestrictTo(LIBRARY_GROUP)` APIs are treated as private APIs and not
203 tracked for binary compatibility
204- `@RequiresOptIn` APIs defined within the group may be used without any
205 restrictions between libraries in the group
206
207Potential drawbacks include:
208
209- All libraries within the group must be versioned identically at head
210- All libraries within the group must release at the same time
211
AndroidX Core Teamee1457a2021-02-25 16:13:10 +0000212#### Early-stage development {#modules-atomic-alpha}
213
214There is one exception to the same-version policy: newly-added libraries within
215an atomic group may be "quarantined" from other libraries to allow for rapid
216iteration until they are API-stable.
217
218A quarantined library must stay within the `1.0.0-alphaXX` cycle until it is
219ready to conform to the same-version policy. While in quarantime, a library is
220treated at though it is in a separate group from its nomical same-version group:
221
222- Must stay in `1.0.0-alphaXX`, e.g. same-version policy is not enforced
223- May use `project` or pinned version dependencies, e.g. strict-match
224 dependencies are not enforced
225- May release on a separate cadence from other libraries within group
226- Must not reference restricted `LIBRARY-GROUP`-scoped APIs
227
228When the library would like to leave quarantine, it must wait for its atomic
229group to be within a `beta` cycle and then match the version. It is okay for a
230library in this situation to skip versions, e.g. move directly from
231`1.0.0-alpha02` to `2.1.3-beta06`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000232
233### Choosing a `minSdkVersion` {#module-minsdkversion}
234
235The recommended minimum SDK version for new Jetpack libraries is currently
alanve2f875c2021-07-09 08:58:30 -0700236**19** (Android 4.4, KitKat). This SDK was chosen to represent 99% of active
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000237devices based on Play Store check-ins (see Android Studio
238[distribution metadata](https://dl.google.com/android/studio/metadata/distributions.json)
239for current statistics). This maximizes potential users for external developers
240while minimizing the amount of overhead necessary to support legacy versions.
241
242However, if no explicit minimum SDK version is specified for a library, the
alanv195c35f2021-06-10 14:29:40 -0700243default is **14** (Android 4.0, Ice Cream Sandwich).
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000244
245Note that a library **must not** depend on another library with a higher
246`minSdkVersion` that its own, so it may be necessary for a new library to match
247its dependent libraries' `minSdkVersion`.
248
249Individual modules may choose a higher minimum SDK version for business or
250technical reasons. This is common for device-specific modules such as Auto or
251Wear.
252
253Individual classes or methods may be annotated with the
254[@RequiresApi](https://developer.android.com/reference/android/annotation/RequiresApi.html)
255annotation to indicate divergence from the overall module's minimum SDK version.
alanv1d2bee52021-09-13 08:49:27 -0700256Note that this pattern is *not recommended* because it leads to confusion for
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000257external developers and should be considered a last-resort when backporting
258behavior is not feasible.
259
AndroidX Core Team0db91f02021-05-06 22:45:18 +0000260### Kotlin extension `-ktx` libraries {#module-ktx}
261
262New libraries should prefer Kotlin sources with built-in Java compatibility via
263`@JvmName` and other affordances of the Kotlin language; however, existing Java
264sourced libraries may benefit from extending their API surface with
265Kotlin-friendly APIs in a `-ktx` library.
266
267A Kotlin extension library **may only** provide extensions for a single base
268library's API surface and its name **must** match the base library exactly. For
269example, `work:work-ktx` may only provide extensions for APIs exposed by
270`work:work`.
271
272Additionally, an extension library **must** specify an `api`-type dependency on
273the base library and **must** be versioned and released identically to the base
274library.
275
alanv1d2bee52021-09-13 08:49:27 -0700276Kotlin extension libraries *should not* expose new functionality; they should
AndroidX Core Team0db91f02021-05-06 22:45:18 +0000277only provide Kotlin-friendly versions of existing Java-facing functionality.
278
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000279## Platform compatibility API patterns {#platform-compatibility-apis}
280
AndroidX Core Team37584142021-02-25 17:58:46 +0000281NOTE For all library APIs that wrap or provide parity with platform APIs,
alanv1d2bee52021-09-13 08:49:27 -0700282*parity with the platform APIs overrides API guidelines*. For example, if the
AndroidX Core Team37584142021-02-25 17:58:46 +0000283platform API being wrapped has incorrect `Executor` and `Callback` ordering
284according to the API Guidelines, the corresponding library API should have the
285exact same (incorrect) ordering.
286
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000287### Static shims (ex. [ViewCompat](https://developer.android.com/reference/android/support/v4/view/ViewCompat.html)) {#static-shim}
288
289When to use?
290
291* Platform class exists at module's `minSdkVersion`
292* Compatibility implementation does not need to store additional metadata
293
294Implementation requirements
295
296* Class name **must** be `<PlatformClass>Compat`
297* Package name **must** be `androidx.<feature>.<platform.package>`
298* Superclass **must** be `Object`
299* Class **must** be non-instantiable, i.e. constructor is private no-op
300* Static fields and static methods **must** match match signatures with
AndroidX Core Team4cc85fa2021-11-23 15:58:34 +0000301 `<PlatformClass>`
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000302 * Static fields that can be inlined, ex. integer constants, **must not**
303 be shimmed
304* Public method names **must** match platform method names
AndroidX Core Team4cc85fa2021-11-23 15:58:34 +0000305* Public methods **must** be static and take `<PlatformClass>` as first
306 parameter (except in the case of static methods on the platform class, as
307 shown below)
308* Implementation *may* delegate to `<PlatformClass>` methods when available
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000309
310#### Sample {#static-shim-sample}
311
312The following sample provides static helper methods for the platform class
313`android.os.Process`.
314
315```java
316/**
317 * Helper for accessing features in {@link Process}.
318 */
319public final class ProcessCompat {
320 private ProcessCompat() {
321 // This class is non-instantiable.
322 }
323
324 /**
325 * [Docs should match platform docs.]
326 *
327 * Compatibility behavior:
328 * <ul>
329 * <li>SDK 24 and above, this method matches platform behavior.
330 * <li>SDK 16 through 23, this method is a best-effort to match platform behavior, but may
331 * default to returning {@code true} if an accurate result is not available.
332 * <li>SDK 15 and below, this method always returns {@code true} as application UIDs and
333 * isolated processes did not exist yet.
334 * </ul>
335 *
336 * @param [match platform docs]
337 * @return [match platform docs], or a value based on platform-specific fallback behavior
338 */
339 public static boolean isApplicationUid(int uid) {
340 if (Build.VERSION.SDK_INT >= 24) {
341 return Api24Impl.isApplicationUid(uid);
342 } else if (Build.VERSION.SDK_INT >= 17) {
343 return Api17Impl.isApplicationUid(uid);
344 } else if (Build.VERSION.SDK_INT == 16) {
345 return Api16Impl.isApplicationUid(uid);
346 } else {
347 return true;
348 }
349 }
350
351 @RequiresApi(24)
352 static class Api24Impl {
353 static boolean isApplicationUid(int uid) {
354 // In N, the method was made public on android.os.Process.
355 return Process.isApplicationUid(uid);
356 }
357 }
358
359 @RequiresApi(17)
360 static class Api17Impl {
361 private static Method sMethod_isAppMethod;
362 private static boolean sResolved;
363
364 static boolean isApplicationUid(int uid) {
365 // In JELLY_BEAN_MR2, the equivalent isApp(int) hidden method moved to public class
366 // android.os.UserHandle.
367 try {
368 if (!sResolved) {
369 sResolved = true;
370 sMethod_isAppMethod = UserHandle.class.getDeclaredMethod("isApp",int.class);
371 }
372 if (sMethod_isAppMethod != null) {
373 return (Boolean) sMethod_isAppMethod.invoke(null, uid);
374 }
375 } catch (Exception e) {
376 e.printStackTrace();
377 }
378 return true;
379 }
380 }
381
382 ...
383}
384```
385
386### Wrapper (ex. [AccessibilityNodeInfoCompat](https://developer.android.com/reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html)) {#wrapper}
387
388When to use?
389
390* Platform class may not exist at module's `minSdkVersion`
391* Compatibility implementation may need to store additional metadata
392* Needs to integrate with platform APIs as return value or method argument
393* **Note:** Should be avoided when possible, as using wrapper classes makes it
394 very difficult to deprecate classes and migrate source code when the
395 `minSdkVersion` is raised
396
397#### Sample {#wrapper-sample}
398
399The following sample wraps a hypothetical platform class `ModemInfo` that was
400added to the platform SDK in API level 23:
401
402```java
403public final class ModemInfoCompat {
404 // Only guaranteed to be non-null on SDK_INT >= 23. Note that referencing the
405 // class itself directly is fine -- only references to class members need to
406 // be pushed into static inner classes.
407 private final ModemInfo wrappedObj;
408
409 /**
410 * [Copy platform docs for matching constructor.]
411 */
412 public ModemInfoCompat() {
413 if (SDK_INT >= 23) {
414 wrappedObj = Api23Impl.create();
415 } else {
416 wrappedObj = null;
417 }
418 ...
419 }
420
421 @RequiresApi(23)
422 private ModemInfoCompat(@NonNull ModemInfo obj) {
423 mWrapped = obj;
424 }
425
426 /**
427 * Provides a backward-compatible wrapper for {@link ModemInfo}.
428 * <p>
429 * This method is not supported on devices running SDK < 23 since the platform
430 * class will not be available.
431 *
432 * @param info platform class to wrap
433 * @return wrapped class, or {@code null} if parameter is {@code null}
434 */
435 @RequiresApi(23)
436 @NonNull
437 public static ModemInfoCompat toModemInfoCompat(@NonNull ModemInfo info) {
438 return new ModemInfoCompat(obj);
439 }
440
441 /**
442 * Provides the {@link ModemInfo} represented by this object.
443 * <p>
444 * This method is not supported on devices running SDK < 23 since the platform
445 * class will not be available.
446 *
447 * @return platform class object
448 * @see ModemInfoCompat#toModemInfoCompat(ModemInfo)
449 */
450 @RequiresApi(23)
451 @NonNull
452 public ModemInfo toModemInfo() {
453 return mWrapped;
454 }
455
456 /**
457 * [Docs should match platform docs.]
458 *
459 * Compatibility behavior:
460 * <ul>
461 * <li>API level 23 and above, this method matches platform behavior.
462 * <li>API level 18 through 22, this method ...
463 * <li>API level 17 and earlier, this method always returns false.
464 * </ul>
465 *
466 * @return [match platform docs], or platform-specific fallback behavior
467 */
468 public boolean isLteSupported() {
469 if (SDK_INT >= 23) {
470 return Api23Impl.isLteSupported(mWrapped);
471 } else if (SDK_INT >= 18) {
472 // Smart fallback behavior based on earlier APIs.
473 ...
474 }
475 // Default behavior.
476 return false;
477 }
478
479 // All references to class members -- including the constructor -- must be
480 // made on an inner class to avoid soft-verification errors that slow class
481 // loading and prevent optimization.
482 @RequiresApi(23)
483 private static class Api23Impl {
AndroidX Core Team4cc85fa2021-11-23 15:58:34 +0000484 @DoNotInline
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000485 @NonNull
486 static ModemInfo create() {
487 return new ModemInfo();
488 }
489
AndroidX Core Team4cc85fa2021-11-23 15:58:34 +0000490 @DoNotInline
491 static boolean isLteSupported(ModemInfo obj) {
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000492 return obj.isLteSupported();
493 }
494 }
495}
496```
497
498Note that libraries written in Java should express conversion to and from the
499platform class differently than Kotlin classes. For Java classes, conversion
500from the platform class to the wrapper should be expressed as a `static` method,
501while conversion from the wrapper to the platform class should be a method on
502the wrapper object:
503
504```java
505@NonNull
506public static ModemInfoCompat toModemInfoCompat(@NonNull ModemInfo info);
507
508@NonNull
509public ModemInfo toModemInfo();
510```
511
512In cases where the primary library is written in Java and has an accompanying
513`-ktx` Kotlin extensions library, the following conversion should be provided as
514an extension function:
515
516```kotlin
517fun ModemInfo.toModemInfoCompat() : ModemInfoCompat
518```
519
520Whereas in cases where the primary library is written in Kotlin, the conversion
521should be provided as an extension factory:
522
523```kotlin
524class ModemInfoCompat {
525 fun toModemInfo() : ModemInfo
526
527 companion object {
528 @JvmStatic
529 @JvmName("toModemInfoCompat")
530 fun ModemInfo.toModemInfoCompat() : ModemInfoCompat
531 }
532}
533```
534
535#### API guidelines {#wrapper-api-guidelines}
536
537##### Naming {#wrapper-naming}
538
539* Class name **must** be `<PlatformClass>Compat`
540* Package name **must** be `androidx.core.<platform.package>`
541* Superclass **must not** be `<PlatformClass>`
542
543##### Construction {#wrapper-construction}
544
alanv1d2bee52021-09-13 08:49:27 -0700545* Class *may* have public constructor(s) to provide parity with public
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000546 `PlatformClass` constructors
547 * Constructor used to wrap `PlatformClass` **must not** be public
548* Class **must** implement a static `PlatformClassCompat
549 toPlatformClassCompat(PlatformClass)` method to wrap `PlatformClass` on
550 supported SDK levels
551 * If class does not exist at module's `minSdkVersion`, method must be
552 annotated with `@RequiresApi(<sdk>)` for SDK version where class was
553 introduced
554
555#### Implementation {#wrapper-implementation}
556
557* Class **must** implement a `PlatformClass toPlatformClass()` method to
558 unwrap `PlatformClass` on supported SDK levels
559 * If class does not exist at module's `minSdkVersion`, method must be
560 annotated with `@RequiresApi(<sdk>)` for SDK version where class was
561 introduced
alanv1d2bee52021-09-13 08:49:27 -0700562* Implementation *may* delegate to `PlatformClass` methods when available (see
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000563 below note for caveats)
564* To avoid runtime class verification issues, all operations that interact
565 with the internal structure of `PlatformClass` must be implemented in inner
566 classes targeted to the SDK level at which the operation was added.
567 * See the [sample](#wrapper-sample) for an example of interacting with a
568 method that was added in SDK level 23.
569
570### Standalone (ex. [ArraySet](https://developer.android.com/reference/android/support/v4/util/ArraySet.html), [Fragment](https://developer.android.com/reference/android/support/v4/app/Fragment.html)) {#standalone}
571
572When to use?
573
574* Platform class may exist at module's `minSdkVersion`
575* Does not need to integrate with platform APIs
576* Does not need to coexist with platform class, ex. no potential `import`
577 collision due to both compatibility and platform classes being referenced
578 within the same source file
579
580Implementation requirements
581
582* Class name **must** be `<PlatformClass>`
583* Package name **must** be `androidx.<platform.package>`
584* Superclass **must not** be `<PlatformClass>`
585* Class **must not** expose `PlatformClass` in public API
alanv1d2bee52021-09-13 08:49:27 -0700586 * In exceptional cases, a *released* standalone class may add conversion
587 between itself and the equivalent platform class; however, *new* classes
AndroidX Core Teamee1457a2021-02-25 16:13:10 +0000588 that support conversion should follow the [Wrapper](#wrapper)
589 guidelines. In these cases, use a `toPlatform<PlatformClass>` and
590 `static toCompat<PlatformClass>` method naming convention.
alanv1d2bee52021-09-13 08:49:27 -0700591* Implementation *may* delegate to `PlatformClass` methods when available
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000592
593### Standalone JAR library (no Android dependencies) {#standalone-jar-library-no-android-dependencies}
594
595When to use
596
597* General purpose library with minimal interaction with Android types
598 * or when abstraction around types can be used (e.g. Room's SQLite
599 wrapper)
600* Lib used in parts of app with minimal Android dependencies
601 * ex. Repository, ViewModel
602* When Android dependency can sit on top of common library
603* Clear separation between android dependent and independent parts of your
604 library
605* Clear that future integration with android dependencies can be layered
606 separately
607
608**Examples:**
609
610The **Paging Library** pages data from DataSources (such as DB content from Room
611or network content from Retrofit) into PagedLists, so they can be presented in a
612RecyclerView. Since the included Adapter receives a PagedList, and there are no
613other Android dependencies, Paging is split into two parts - a no-android
614library (paging-common) with the majority of the paging code, and an android
615library (paging-runtime) with just the code to present a PagedList in a
616RecyclerView Adapter. This way, tests of Repositories and their components can
617be tested in host-side tests.
618
619**Room** loads SQLite data on Android, but provides an abstraction for those
620that want to use a different SQL implementation on device. This abstraction, and
621the fact that Room generates code dynamically, means that Room interfaces can be
622used in host-side tests (though actual DB code should be tested on device, since
623DB impls may be significantly different on host).
624
625## Implementing compatibility {#compat}
626
627### Referencing new APIs {#compat-newapi}
628
629Generally, methods on extension library classes should be available to all
630devices above the library's `minSdkVersion`.
631
632#### Checking device SDK version {#compat-sdk}
633
634The most common way of delegating to platform or backport implementations is to
635compare the device's `Build.VERSION.SDK_INT` field to a known-good SDK version;
636for example, the SDK in which a method first appeared or in which a critical bug
637was first fixed.
638
639Non-reflective calls to new APIs gated on `SDK_INT` **must** be made from
640version-specific static inner classes to avoid verification errors that
641negatively affect run-time performance. For more information, see Chromium's
642guide to
643[Class Verification Failures](https://chromium.googlesource.com/chromium/src/+/HEAD/build/android/docs/class_verification_failures.md).
644
645Methods in implementation-specific classes **must** be paired with the
646`@DoNotInline` annotation to prevent them from being inlined.
647
648```java {.good}
649public static void saveAttributeDataForStyleable(@NonNull View view, ...) {
650 if (Build.VERSION.SDK_INT >= 29) {
651 Api29Impl.saveAttributeDataForStyleable(view, ...);
652 }
653}
654
655@RequiresApi(29)
656private static class Api29Impl {
657 @DoNotInline
658 static void saveAttributeDataForStyleable(@NonNull View view, ...) {
659 view.saveAttributeDataForStyleable(...);
660 }
661}
662```
663
664Alternatively, in Kotlin sources:
665
666```kotlin {.good}
667@RequiresApi(29)
AndroidX Core Team23c50442021-05-18 13:03:40 -0400668private object Api29Impl {
669 @JvmStatic
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000670 @DoNotInline
671 fun saveAttributeDataForStyleable(view: View, ...) { ... }
672}
673```
674
675When developing against pre-release SDKs where the `SDK_INT` has not been
676finalized, SDK checks **must** use `BuildCompat.isAtLeastX()` methods.
677
678```java {.good}
679@NonNull
680public static List<Window> getAllWindows() {
681 if (BuildCompat.isAtLeastR()) {
682 return ApiRImpl.getAllWindows();
683 }
684 return Collections.emptyList();
685}
686```
687
688#### Device-specific issues {#compat-oem}
689
690Library code may work around device- or manufacturer-specific issues -- issues
691not present in AOSP builds of Android -- *only* if a corresponding CTS test
692and/or CDD policy is added to the next revision of the Android platform. Doing
693so ensures that such issues can be detected and fixed by OEMs.
694
695#### Handling `minSdkVersion` disparity {#compat-minsdk}
696
697Methods that only need to be accessible on newer devices, including
698`to<PlatformClass>()` methods, may be annotated with `@RequiresApi(<sdk>)` to
699indicate they will fail to link on older SDKs. This annotation is enforced at
700build time by Lint.
701
702#### Handling `targetSdkVersion` behavior changes {#compat-targetsdk}
703
704To preserve application functionality, device behavior at a given API level may
705change based on an application's `targetSdkVersion`. For example, if an app with
706`targetSdkVersion` set to API level 22 runs on a device with API level 29, all
707required permissions will be granted at installation time and the run-time
708permissions framework will emulate earlier device behavior.
709
710Libraries do not have control over the app's `targetSdkVersion` and -- in rare
711cases -- may need to handle variations in platform behavior. Refer to the
712following pages for version-specific behavior changes:
713
714* API level 29:
715 [Android Q behavior changes: apps targeting Q](https://developer.android.com/preview/behavior-changes-q)
716* API level 28:
717 [Behavior changes: apps targeting API level 28+](https://developer.android.com/about/versions/pie/android-9.0-changes-28)
718* API level 26:
719 [Changes for apps targeting Android 8.0](https://developer.android.com/about/versions/oreo/android-8.0-changes#o-apps)
720* API level 24:
721 [Changes for apps targeting Android 7.0](https://developer.android.com/about/versions/nougat/android-7.0-changes#n-apps)
722* API level 21:
723 [Android 5.0 Behavior Changes](https://developer.android.com/about/versions/android-5.0-changes)
724* API level 19:
725 [Android 4.4 APIs](https://developer.android.com/about/versions/android-4.4)
726
727#### Working around Lint issues {#compat-lint}
728
729In rare cases, Lint may fail to interpret API usages and yield a `NewApi` error
730and require the use of `@TargetApi` or `@SuppressLint('NewApi')` annotations.
731Both of these annotations are strongly discouraged and may only be used
732temporarily. They **must never** be used in a stable release. Any usage of these
733annotation **must** be associated with an active bug, and the usage must be
734removed when the bug is resolved.
735
736### Delegating to API-specific implementations {#delegating-to-api-specific-implementations}
737
738#### SDK-dependent reflection
739
740Starting in API level 28, the platform restricts which
741[non-SDK interfaces](https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces)
742can be accessed via reflection by apps and libraries. As a general rule, you
743will **not** be able to use reflection to access hidden APIs on devices with
744`SDK_INT` greater than `Build.VERSION_CODES.P` (28).
745
746On earlier devices, reflection on hidden platform APIs is allowed **only** when
747an alternative public platform API exists in a later revision of the Android
748SDK. For example, the following implementation is allowed:
749
750```java
751public AccessibilityDelegate getAccessibilityDelegate(View v) {
752 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
753 // Retrieve the delegate using a public API.
754 return v.getAccessibilityDelegate();
755 } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
756 // Retrieve the delegate by reflecting on a private field. If the
757 // field does not exist or cannot be accessed, this will no-op.
758 if (sAccessibilityDelegateField == null) {
759 try {
760 sAccessibilityDelegateField = View.class
761 .getDeclaredField("mAccessibilityDelegate");
762 sAccessibilityDelegateField.setAccessible(true);
763 } catch (Throwable t) {
764 sAccessibilityDelegateCheckFailed = true;
765 return null;
766 }
767 }
768 try {
769 Object o = sAccessibilityDelegateField.get(v);
770 if (o instanceof View.AccessibilityDelegate) {
771 return (View.AccessibilityDelegate) o;
772 }
773 return null;
774 } catch (Throwable t) {
775 sAccessibilityDelegateCheckFailed = true;
776 return null;
777 }
778 } else {
779 // There is no way to retrieve the delegate, even via reflection.
780 return null;
781 }
782```
783
784Calls to public APIs added in pre-release revisions *must* be gated using
785`BuildCompat`:
786
787```java
788if (BuildCompat.isAtLeastQ()) {
789 // call new API added in Q
790} else if (Build.SDK_INT.VERSION >= Build.VERSION_CODES.SOME_RELEASE) {
791 // make a best-effort using APIs that we expect to be available
792} else {
793 // no-op or best-effort given no information
794}
795```
796
797### Inter-process communication {#inter-process-communication}
798
799Protocols and data structures used for IPC must support interoperability between
800different versions of libraries and should be treated similarly to public API.
801
802#### Data structures
803
alanvdf3e8b92021-11-30 13:13:05 -0800804**Do not** use `Parcelable` for any class that may be used for IPC or otherwise
805exposed as public API. The wire format used by `Parcelable` does not provide any
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000806compatibility guarantees and will result in crashes if fields are added or
807removed between library versions.
808
809**Do not** design your own serialization mechanism or wire format for disk
810storage or inter-process communication. Preserving and verifying compatibility
811is difficult and error-prone.
812
alanvca083302021-08-19 10:30:02 -0700813Developers **should** use protocol buffers for most cases. See
814[Protobuf](#dependencies-protobuf) for more information on using protocol
alanvdf3e8b92021-11-30 13:13:05 -0800815buffers in your library. **Do** use protocol buffers if your data structure is
816complex and likely to change over time. If your data includes `FileDescriptor`s,
817`Binder`s, or other platform-defined `Parcelable` data structures, they will
818need to be stored alongside the protobuf bytes in a `Bundle`.
alanvca083302021-08-19 10:30:02 -0700819
alanvdf3e8b92021-11-30 13:13:05 -0800820Developers **may** use `Bundle` in simple cases that require sending `Binder`s,
821`FileDescriptor`s, or platform `Parcelable`s across IPC
822([example](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core/src/main/java/androidx/core/graphics/drawable/IconCompat.java;l=820)).
823Note that `Bundle` has several caveats:
alanv1d2bee52021-09-13 08:49:27 -0700824
AndroidX Core Team4e1909a2021-10-20 15:04:04 +0000825- When running on Android S and below, accessing *any* entry in a `Bundle`
826 will result in the platform attempting to deserialize *every* entry. This
827 has been fixed in Android T and later with "lazy" bundles, but developers
828 should be careful when accessing `Bundle` on earlier platforms. If a single
829 entry cannot be loaded -- for example if a developer added a custom
830 `Parcelable` that doesn't exist in the receiver's classpath -- an exception
831 will be thrown when accessing *any* entry.
832- On all platforms, library code that receives `Bundle`s data from outside the
833 process **must** read the data defensively. See previous note regarding
834 additional concerns for Android S and below.
835- On all platforms, library code that sends `Bundle`s outside the process
alanv1d2bee52021-09-13 08:49:27 -0700836 *should* discourage clients from passing custom `Parcelable`s.
837- `Bundle` provides no versioning and Jetpack provides no affordances for
838 tracking the keys or value types associated with a `Bundle`. Library owners
839 are responsible for providing their own system for guaranteeing wire format
840 compatibility between versions.
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000841
alanvdf3e8b92021-11-30 13:13:05 -0800842Developers **may** use `VersionedParcelable` in cases where they are already
843using the library and understand its limitations.
844
845In all cases, **do not** expose your serialization mechanism in your API
846surface.
847
848NOTE We are currently investigating the suitability of Square's
849[`wire` library](https://github.com/square/wire) for handling protocol buffers
850in Android libraries. If adopted, it will replace `proto` library dependencies.
851Libraries that expose their serialization mechanism in their API surface *will
852not be able to migrate*.
853
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000854#### Communication protocols
855
856Any communication prototcol, handshake, etc. must maintain compatibility
857consistent with SemVer guidelines. Consider how your protocol will handle
858addition and removal of operations or constants, compatibility-breaking changes,
859and other modifications without crashing either the host or client process.
860
861## Deprecation and removal
862
863While SemVer's binary compatibility guarantees restrict the types of changes
864that may be made within a library revision and make it difficult to remove an
865API, there are many other ways to influence how developers interact with your
866library.
867
868### Deprecation (`@deprecated`)
869
870Deprecation lets a developer know that they should stop using an API or class.
871All deprecations must be marked with a `@Deprecated` Java annotation as well as
872a `@deprecated <migration-docs>` docs annotation explaining how the developer
873should migrate away from the API.
874
875Deprecation is an non-breaking API change that must occur in a **major** or
876**minor** release.
877
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +0000878APIs that are added during a pre-release cycle and marked as `@Deprecated`
879within the same cycle, e.g. added in `alpha01` and deprecated in `alpha06`,
880[must be removed](versioning.md#beta-checklist) before moving to `beta01`.
881
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000882### Soft removal (@removed)
883
884Soft removal preserves binary compatibility while preventing source code from
885compiling against an API. It is a *source-breaking change* and not recommended.
886
887Soft removals **must** do the following:
888
889* Mark the API as deprecated for at least one stable release prior to removal.
890* Mark the API with a `@RestrictTo(LIBRARY)` Java annotation as well as a
891 `@removed <reason>` docs annotation explaining why the API was removed.
892* Maintain binary compatibility, as the API may still be called by existing
893 dependent libraries.
894* Maintain behavioral compatibility and existing tests.
895
896This is a disruptive change and should be avoided when possible.
897
898Soft removal is a source-breaking API change that must occur in a **major** or
899**minor** release.
900
901### Hard removal
902
903Hard removal entails removing the entire implementation of an API that was
904exposed in a public release. Prior to removal, an API must be marked as
905`@deprecated` for a full **minor** version (`alpha`->`beta`->`rc`->stable),
906prior to being hard removed.
907
908This is a disruptive change and should be avoided when possible.
909
910Hard removal is a binary-breaking API change that must occur in a **major**
911release.
912
913### For entire artifacts
914
915We do not typically deprecate or remove entire artifacts; however, it may be
916useful in cases where we want to halt development and focus elsewhere or
917strongly discourage developers from using a library.
918
919Halting development, either because of staffing or prioritization issues, leaves
920the door open for future bug fixes or continued development. This quite simply
921means we stop releasing updates but retain the source in our tree.
922
923Deprecating an artifact provides developers with a migration path and strongly
924encourages them -- through Lint warnings -- to migrate elsewhere. This is
925accomplished by adding a `@Deprecated` and `@deprecated` (with migration
926comment) annotation pair to *every* class and interface in the artifact.
927
alanvf6ca094d2022-05-09 09:02:52 -0700928To deprecate an entire artifact:
929
9301. Mark every top-level API (class, interface, extension function, etc.) in the
931 artifact as `@Deprecated` and update the API files
932 ([example CL](https://android-review.googlesource.com/c/platform/frameworks/support/+/1938773))
9331. Schedule a release of the artifact as a new minor version. When you populate
934 the release notes, explain that the entire artifact has been deprecated.
935 Include the reason for deprecation and the migration strategy.
9361. After the artifact has been released, remove the artifact from the source
937 tree, versions file, and tip-of-tree docs configuration
938 ([example CL](https://android-review.googlesource.com/c/platform/frameworks/support/+/2061731/))
AndroidX Core Team95f812d2021-07-07 12:52:35 -0700939
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000940The fully-deprecated artifact will be released as a deprecation release -- it
941will ship normally with accompanying release notes indicating the reason for
942deprecation and migration strategy, and it will be the last version of the
943artifact that ships. It will ship as a new minor stable release. For example, if
944`1.0.0` was the last stable release, then the deprecation release will be
945`1.1.0`. This is so Android Studio users will get a suggestion to update to a
946new stable version, which will contain the `@deprecated` annotations.
947
948After an artifact has been released as fully-deprecated, it can be removed from
949the source tree.
950
951## Resources {#resources}
952
953Generally, follow the official Android guidelines for
954[app resources](https://developer.android.com/guide/topics/resources/providing-resources).
955Special guidelines for library resources are noted below.
956
957### Defining new resources
958
959Libraries may define new value and attribute resources using the standard
960application directory structure used by Android Gradle Plugin:
961
962```
963src/main/res/
964 values/
965 attrs.xml Theme attributes and styleables
966 dimens.xml Dimensional values
967 public.xml Public resource definitions
968 ...
969```
970
971However, some libraries may still be using non-standard, legacy directory
972structures such as `res-public` for their public resource declarations or a
973top-level `res` directory and accompanying custom source set in `build.gradle`.
974These libraries will eventually be migrated to follow standard guidelines.
975
976#### Naming conventions
977
978Libraries follow the Android platform's resource naming conventions, which use
979`camelCase` for attributes and `underline_delimited` for values. For example,
980`R.attr.fontProviderPackage` and `R.dimen.material_blue_grey_900`.
981
982#### Attribute formats
983
984At build time, attribute definitions are pooled globally across all libraries
985used in an application, which means attribute `format`s *must* be identical for
986a given `name` to avoid a conflict.
987
988Within Jetpack, new attribute names *must* be globally unique. Libraries *may*
989reference existing public attributes from their dependencies. See below for more
990information on public attributes.
991
992When adding a new attribute, the format should be defined *once* in an `<attr
993/>` element in the definitions block at the top of `src/main/res/attrs.xml`.
994Subsequent references in `<declare-styleable>` elements *must* not include a
995`format`:
996
997`src/main/res/attrs.xml`
998
999```xml
1000<resources>
1001 <attr name="fontProviderPackage" format="string" />
1002
1003 <declare-styleable name="FontFamily">
1004 <attr name="fontProviderPackage" />
1005 </declare-styleable>
1006</resources>
1007```
1008
1009### Public resources
1010
1011Library resources are private by default, which means developers are discouraged
1012from referencing any defined attributes or values from XML or code; however,
1013library resources may be declared public to make them available to developers.
1014
1015Public library resources are considered API surface and are thus subject to the
1016same API consistency and documentation requirements as Java APIs.
1017
1018Libraries will typically only expose theme attributes, ex. `<attr />` elements,
1019as public API so that developers can set and retrieve the values stored in
1020styles and themes. Exposing values -- such as `<dimen />` and `<string />` -- or
1021images -- such as drawable XML and PNGs -- locks the current state of those
1022elements as public API that cannot be changed without a major version bump. That
1023means changing a publicly-visible icon would be considered a breaking change.
1024
1025#### Documentation
1026
1027All public resource definitions should be documented, including top-level
1028definitions and re-uses inside `<styleable>` elements:
1029
1030`src/main/res/attrs.xml`
1031
1032```xml
1033<resources>
1034 <!-- String specifying the application package for a Font Provider. -->
1035 <attr name="fontProviderPackage" format="string" />
1036
1037 <!-- Attributes that are read when parsing a <fontfamily> tag. -->
1038 <declare-styleable name="FontFamily">
1039 <!-- The package for the Font Provider to be used for the request. This is
1040 used to verify the identity of the provider. -->
1041 <attr name="fontProviderPackage" />
1042 </declare-styleable>
1043</resources>
1044```
1045
1046`src/main/res/colors.xml`
1047
1048```xml
1049<resources>
1050 <!-- Color for Material Blue-Grey 900. -->
1051 <color name="material_blue_grey_900">#ff263238</color>
1052</resources>
1053```
1054
1055#### Public declaration
1056
1057Resources are declared public by providing a separate `<public />` element with
1058a matching type:
1059
1060`src/main/res/public.xml`
1061
1062```xml
1063<resources>
1064 <public name="fontProviderPackage" type="attr" />
1065 <public name="material_blue_grey_900" type="color" />
1066</resources>
1067```
1068
1069#### More information
1070
1071See also the official Android Gradle Plugin documentation for
1072[Private Resources](https://developer.android.com/studio/projects/android-library#PrivateResources).
1073
1074### Manifest entries (`AndroidManifest.xml`) {#resources-manifest}
1075
1076#### Metadata tags (`<meta-data>`) {#resources-manifest-metadata}
1077
1078Developers **must not** add `<application>`-level `<meta-data>` tags to library
1079manifests or advise developers to add such tags to their application manifests.
alanv1d2bee52021-09-13 08:49:27 -07001080Doing so may *inadvertently cause denial-of-service attacks against other apps*.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001081
1082Assume a library adds a single item of meta-data at the application level. When
1083an app uses the library, that meta-data will be merged into the resulting app's
1084application entry via manifest merger.
1085
1086If another app attempts to obtain a list of all activities associated with the
1087primary app, that list will contain multiple copies of the `ApplicationInfo`,
1088each of which in turn contains a copy of the library's meta-data. As a result,
1089one `<metadata>` tag may become hundreds of KB on the binder call to obtain the
1090list -- resulting in apps hitting transaction too large exceptions and crashing.
1091
1092```xml {.bad}
1093<manifest xmlns:android="http://schemas.android.com/apk/res/android"
1094 package="androidx.librarypackage">
1095 <application>
1096 <meta-data
1097 android:name="keyName"
1098 android:value="@string/value" />
1099 </application>
1100</manifest>
1101```
1102
1103Instead, developers may consider adding `<metadata>` nested inside of
1104placeholder `<service>` tags.
1105
1106```xml {.good}
1107<manifest xmlns:android="http://schemas.android.com/apk/res/android"
1108 package="androidx.librarypackage">
1109 <application>
1110 <service
1111 android:name="androidx.librarypackage.MetadataHolderService"
1112 android:enabled="false"
1113 android:exported="false">
1114 <meta-data
1115 android:name="androidx.librarypackage.MetadataHolderService.KEY_NAME"
1116 android:resource="@string/value" />
1117 </service>
1118 </application>
1119```
1120
1121```java {.good}
1122package androidx.libraryname.featurename;
1123
1124/**
1125 * A placeholder service to avoid adding application-level metadata. The service
1126 * is only used to expose metadata defined in the library's manifest. It is
1127 * never invoked.
1128 */
1129public final class MetadataHolderService {
1130 private MetadataHolderService() {}
1131
1132 @Override
1133 public IBinder onBind(Intent intent) {
1134 throw new UnsupportedOperationException();
1135 }
1136}
1137```
1138
1139## Dependencies {#dependencies}
1140
alanv93da5db2021-08-11 13:05:51 -07001141Artifacts may depend on other artifacts within AndroidX as well as sanctioned
1142third-party libraries.
1143
1144### Versioned artifacts {#dependencies-versioned}
1145
1146One of the most difficult aspects of independently-versioned releases is
1147maintaining compatibility with public artifacts. In a mono repo such as Google's
1148repository or Android Git at master revision, it's easy for an artifact to
1149accidentally gain a dependency on a feature that may not be released on the same
1150schedule.
alanv11786ae2021-05-25 10:55:11 -07001151
1152- Project `project(":core:core")` uses the tip-of-tree sources for the
1153 `androidx.core:core` library and requires that they be loaded in the
1154 workspace.
1155- Playground `projectOrArtifact(":core:core")` is used for
1156 [Playground](playground.md) projects and will use tip-of-tree sources, if
1157 present in the workspace, or `SNAPSHOT` prebuilt artifacts from
1158 [androidx.dev](http://androidx.dev) otherwise.
1159- Explicit `"androidx.core:core:1.4.0"` uses the prebuilt AAR and requires
1160 that it be checked in to the `prebuilts/androidx/internal` local Maven
1161 repository.
1162
1163Libraries should prefer explicit dependencies with the lowest possible versions
1164that include the APIs or behaviors required by the library, using project or
1165Playground specs only in cases where tip-of-tree APIs or behaviors are required.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001166
alanv93da5db2021-08-11 13:05:51 -07001167#### Pre-release dependencies {#dependencies-pre-release}
1168
1169Pre-release suffixes **must** propagate up the dependency tree. For example, if
1170your artifact has API-type dependencies on pre-release artifacts, ex.
1171`1.1.0-alpha01`, then your artifact must also carry the `alpha` suffix. If you
1172only have implementation-type dependencies, your artifact may carry either the
1173`alpha` or `beta` suffix.
1174
1175Note: This does not apply to test dependencies: suffixes of test dependencies do
alanv1d2bee52021-09-13 08:49:27 -07001176*not* carry over to your artifact.
alanv93da5db2021-08-11 13:05:51 -07001177
1178#### Pinned versions {#dependencies-prebuilt}
1179
1180To avoid issues with dependency versioning, consider pinning your artifact's
1181dependencies to the oldest version (available via local `maven_repo` or Google
1182Maven) that satisfies the artifact's API requirements. This will ensure that the
1183artifact's release schedule is not accidentally tied to that of another artifact
1184and will allow developers to use older libraries if desired.
1185
1186```
1187dependencies {
1188 api("androidx.collection:collection:1.0.0")
1189 ...
1190}
1191```
1192
1193Artifacts should be built and tested against both pinned and tip-of-tree
1194versions of their dependencies to ensure behavioral compatibility.
1195
1196#### Tip-of-tree versions {#dependencies-project}
1197
1198Below is an example of a non-pinned dependency. It ties the artifact's release
1199schedule to that of the dependency artifact, because the dependency will need to
1200be released at the same time.
1201
1202```
1203dependencies {
1204 api(project(":collection"))
1205 ...
1206}
1207```
1208
1209### Non-public APIs {#dependencies-non-public-apis}
1210
1211Artifacts may depend on non-public (e.g. `@hide`) APIs exposed within their own
1212artifact or another artifact in the same `groupId`; however, cross-artifact
1213usages are subject to binary compatibility guarantees and
1214`@RestrictTo(Scope.LIBRARY_GROUP)` APIs must be tracked like public APIs.
1215
1216```
1217Dependency versioning policies are enforced at build time in the createArchive task. This task will ensure that pre-release version suffixes are propagated appropriately.
1218
1219Cross-artifact API usage policies are enforced by the checkApi and checkApiRelease tasks (see Life of a release).
1220```
1221
1222### Third-party libraries {#dependencies-3p}
1223
1224Artifacts may depend on libraries developed outside of AndroidX; however, they
1225must conform to the following guidelines:
1226
1227* Prebuilt **must** be checked into Android Git with both Maven and Make
1228 artifacts
1229 * `prebuilts/maven_repo` is recommended if this dependency is only
1230 intended for use with AndroidX artifacts, otherwise please use
1231 `external`
1232* Prebuilt directory **must** contains an `OWNERS` file identifying one or
1233 more individual owners (e.g. NOT a group alias)
1234* Library **must** be approved by legal
1235
1236Please see Jetpack's [open-source policy page](open_source.md) for more details
1237on using third-party libraries.
1238
alanva9915e82021-09-10 15:21:02 -07001239### Types of dependencies {#dependencies-types}
1240
1241AndroidX allows dependencies to be specified as `api` or `implementation` with a
1242"pinned" Maven spec (ex. `androidx.core:core:1.0.0`) or a "tip-of-tree" project
1243spec (ex. `project(":core:core")`).
1244
1245Projects used in Playground, the experimental GitHub workflow, should use a
1246"recent" project or artifact spec (ex. `projectOrArtifact(":core:core")`) which
1247will default to tip-of-tree when used outside of the Playground workflow or a
1248pinned `SNAPSHOT` artifact otherwise.
1249
1250Regardless of which dependency spec is used, all projects are built against
1251tip-of-tree dependencies in CI to prevent regressions and enforce Jetpack's
1252compatible-at-head policy.
1253
1254#### `api` versus `implementation` {#dependencies-api-vs-impl}
1255
1256`api`-type dependencies will appear in clients' auto-complete as though they had
1257added the dependency directly to their project, and Studio will run any lint
1258checks bundled with `api`-type dependencies.
1259
1260Dependencies whose APIs are exposed in a library's API surface **must** be
1261included as `api`-type. For example, if your library's API surface includes
1262`AccessibilityNodeInfoCompat` then you will use an `api`-type dependency on the
1263`androidx.core:core` library.
1264
1265NOTE Libraries that provide client-facing lint checks, including
1266`annotation-experimental`, **must** be included as `api`-type to ensure that
1267lint checks are run in the clients' dependent projects.
1268
1269`implementation`-type dependencies will be included in the classpath, but will
1270not be made available at design time (ex. in auto-complete) unless the client
1271explicitly adds them.
1272
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001273### System health {#dependencies-health}
1274
alanva9915e82021-09-10 15:21:02 -07001275Generally, Jetpack libraries should avoid dependencies that negatively impact
1276developers without providing substantial benefit. Libraries should consider the
1277system health implications of their dependencies, including:
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001278
1279- Large dependencies where only a small portion is needed (e.g. APK bloat)
1280- Dependencies that slow down build times through annotation processing or
1281 compiler overhead
1282
1283#### Kotlin {#dependencies-kotlin}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001284
alanv1d2bee52021-09-13 08:49:27 -07001285Kotlin is *strongly recommended* for new libraries; however, it's important to
AndroidX Core Team43201242021-01-26 21:38:01 +00001286consider its size impact on clients. Currently, the Kotlin stdlib adds a minimum
1287of 40kB post-optimization. It may not make sense to use Kotlin for a library
1288that targets Java-only clients or space-constrained (ex. Android Go) clients.
1289
alanv1d2bee52021-09-13 08:49:27 -07001290Existing Java-based libraries are *strongly discouraged* from using Kotlin,
AndroidX Core Team43201242021-01-26 21:38:01 +00001291primarily because our documentation system does not currently provide a
alanv1d2bee52021-09-13 08:49:27 -07001292Java-facing version of Kotlin API reference docs. Java-based libraries *may*
AndroidX Core Team43201242021-01-26 21:38:01 +00001293migrate to Kotlin, but they must consider the docs usability and size impacts on
1294existing Java-only and space-constrained clients.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001295
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001296#### Kotlin coroutines {#dependencies-coroutines}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001297
1298Kotlin's coroutine library adds around 100kB post-shrinking. New libraries that
1299are written in Kotlin should prefer coroutines over `ListenableFuture`, but
1300existing libraries must consider the size impact on their clients. See
1301[Asynchronous work with return values](#async-return) for more details on using
1302Kotlin coroutines in Jetpack libraries.
1303
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001304#### Guava {#dependencies-guava}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001305
1306The full Guava library is very large and *must not* be used. Libraries that
1307would like to depend on Guava's `ListenableFuture` may instead depend on the
1308standalone `com.google.guava:listenablefuture` artifact. See
1309[Asynchronous work with return values](#async-return) for more details on using
1310`ListenableFuture` in Jetpack libraries.
1311
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001312#### Java 8 {#dependencies-java8}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001313
alanv1d2bee52021-09-13 08:49:27 -07001314Libraries that take a dependency on a library targeting Java 8 must *also*
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001315target Java 8, which will incur a ~5% build performance (as of 8/2019) hit for
AndroidX Core Team4074b462021-06-01 06:53:40 -07001316clients. New libraries targeting Java 8 may use Java 8 dependencies.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001317
1318The default language level for `androidx` libraries is Java 8, and we encourage
1319libraries to stay on Java 8. However, if you have a business need to target Java
13207, you can specify Java 7 in your `build.gradle` as follows:
1321
alanv93da5db2021-08-11 13:05:51 -07001322```groovy
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001323android {
1324 compileOptions {
1325 sourceCompatibility = JavaVersion.VERSION_1_7
1326 targetCompatibility = JavaVersion.VERSION_1_7
1327 }
1328}
1329```
1330
alanvca083302021-08-19 10:30:02 -07001331#### Protobuf {#dependencies-protobuf}
1332
1333[Protocol buffers](https://developers.google.com/protocol-buffers) provide a
1334language- and platform-neutral mechanism for serializing structured data. The
1335implementation enables developers to maintain protocol compatibility across
1336library versions, meaning that two clients can communicate regardless of the
1337library versions included in their APKs.
1338
1339The Protobuf library itself, however, does not guarantee ABI compatibility
1340across minor versions and a specific version **must** be bundled with a library
1341to avoid conflict with other dependencies used by the developer.
1342
1343Additionally, the Java API surface generated by the Protobuf compiler is not
1344guaranteed to be stable and **must not** be exposed to developers. Library
1345owners should wrap the generated API surface with well-documented public APIs
1346that follow an appropriate language-specific paradigm for constructing data
1347classes, e.g. the Java `Builder` pattern.
1348
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001349### Open-source compatibility {#dependencies-aosp}
1350
alanvf3ff25e2022-01-05 07:16:05 -08001351Jetpack's [open-source](open_source.md) principle requires that libraries
1352consider the open-source compatibility implications of their dependencies,
1353including:
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001354
1355- Closed-source or proprietary libraries or services that may not be available
1356 on AOSP devices
1357- Dependencies that may prevent developers from effectively isolating their
1358 tests from third-party libraries or services
1359
1360Primary artifacts, e.g. `workmanager`, **must not** depend on closed-source
1361components including libraries and hard-coded references to packages,
AndroidX Core Teame5ea2412022-05-09 15:00:33 -07001362permissions, or IPC mechanisms that may only be fulfilled by closed-source
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001363components.
1364
alanv1d2bee52021-09-13 08:49:27 -07001365Optional artifacts, e.g. `workmanager-gcm`, *may* depend on closed-source
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001366components or configure a primary artifact to be backed by a closed-source
1367component via service discovery or initialization.
1368
1369Some examples of safely depending on closed-source components include:
1370
alanvacbb0892021-09-14 07:58:29 -07001371- WorkManager's GCM Network Manager integration, which uses
alanvf52991b2022-05-06 06:58:34 -07001372 [manifest metadata](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:work/workmanager-gcm/src/main/AndroidManifest.xml)
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001373 for service discovery and provides an optional artifact exposing the
1374 service.
1375- Ads Identifier's Play Services integration, which provides a default backend
alanvacbb0892021-09-14 07:58:29 -07001376 and uses
1377 [`Intent` handling](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/AdvertisingIdProviderManager.java;l=108)
1378 as a service discovery mechanism for Play Services.
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001379- Downloadable Fonts integration with Play Services, which plugs in via a
alanvf52991b2022-05-06 06:58:34 -07001380 [`ContentProvider`](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core/src/androidTest/java/androidx/core/provider/MockFontProvider.java)
alanvacbb0892021-09-14 07:58:29 -07001381 as a service discovery mechanism with developer-specified
1382 [signature verification](https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts#adding-certificates)
1383 for additional security.
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001384
alanv1d2bee52021-09-13 08:49:27 -07001385Note that in all cases, the developer is not *required* to use GCM or Play
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001386Services and may instead use another compatible service implementing the same
1387publicly-defined protocols.
1388
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001389## More API guidelines {#more-api-guidelines}
1390
1391### Annotations {#annotation}
1392
1393#### Annotation processors {#annotation-processor}
1394
1395Annotation processors should opt-in to incremental annotation processing to
1396avoid triggering a full recompilation on every client source code change. See
1397Gradle's
1398[Incremental annotation processing](https://docs.gradle.org/current/userguide/java_plugin.html#sec:incremental_annotation_processing)
1399documentation for information on how to opt-in.
1400
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00001401### `@RequiresOptIn` APIs {#experimental-api}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001402
1403Jetpack libraries may choose to annotate API surfaces as unstable using either
1404Kotlin's
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00001405[`@RequiresOptIn` meta-annotation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-requires-opt-in/)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001406for APIs written in Kotlin or Jetpack's
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00001407[`@RequiresOptIn` meta-annotation](https://developer.android.com/reference/kotlin/androidx/annotation/RequiresOptIn)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001408for APIs written in Java.
1409
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00001410> `@RequiresOptIn` at-a-glance:
1411>
1412> * Use for unstable API surfaces
1413> * Can be called by anyone
1414> * Documented in public documentation
1415> * Does not maintain compatibility
1416
1417For either annotation, API surfaces marked as opt-in are considered alpha and
1418will be excluded from API compatibility guarantees. Due to the lack of
1419compatibility guarantees, stable libraries *must never* call experimental APIs
1420exposed by other libraries outside of their
alanvf5ca4b92021-02-10 13:07:47 -08001421[same-version group](#same-version-atomic-groups) and *may not* use the `@OptIn`
1422annotation except in the following cases:
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001423
1424* A library within a same-version group *may* call an experimental API exposed
1425 by another library **within its same-version group**. In this case, API
1426 compatibility guarantees are covered under the same-version group policies
alanvf5ca4b92021-02-10 13:07:47 -08001427 and the library *may* use the `@OptIn` annotation to prevent propagation of
1428 the experimental property. **Library owners must exercise care to ensure
1429 that post-alpha APIs backed by experimental APIs actually meet the release
1430 criteria for post-alpha APIs.**
1431* An `alpha` library may use experimental APIs from outside its same-version
1432 group. These usages must be removed when the library moves to `beta`.
1433
1434NOTE JetBrains's own usage of `@RequiresOptIn` in Kotlin language libraries
1435varies and may indicate binary instability, functional instability, or simply
1436that an API is really difficult to use. Jetpack libraries should treat instances
1437of `@RequiresOptIn` in JetBrains libraries as indicating **binary instability**
1438and avoid using them outside of `alpha`; however, teams are welcome to obtain
1439written assurance from JetBrains regarding binary stability of specific APIs.
alanv1d2bee52021-09-13 08:49:27 -07001440`@RequiresOptIn` APIs that are guaranteed to remain binary compatible *may* be
alanvf5ca4b92021-02-10 13:07:47 -08001441used in `beta`, but usages must be removed when the library moves to `rc`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001442
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00001443#### When to mark an API surface as experimental
1444
1445*Do not* use `@RequiresOptIn` for a stable API surface that is difficult to use.
1446It is not a substitute for a properly-designed API surface.
1447
1448*Do not* use `@RequiresOptIn` for an API surface that is unreliable or unstable
1449because it is missing tests. It is not a substitute for a properly-tested API
1450surface, and all APIs -- including those in `alpha` -- are expected to be
1451functionally stable.
1452
1453*Do not* use `@RequiresOptIn` for an internal-facing API surface. Use either the
1454appropriate language visibility (ex. `private` or `internal`) or `@RestrictTo`.
1455
1456*Do not* use `@RequiresOptIn` for an API that you expect library developers to
1457call. Experimental APIs do not maintain binary compatibility guarantees, and you
1458will put external clients in a difficult situation.
1459
1460*Do* use `@RequiresOptIn` for API surfaces that must be publicly available and
1461documented but need the flexibility to stay in `alpha` (and break compatibility)
1462during the rest of the library's `beta`, `rc`, or stable cycles.
1463
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001464#### How to mark an API surface as experimental
1465
alanvf5ca4b92021-02-10 13:07:47 -08001466All libraries using `@RequiresOptIn` annotations *must* depend on the
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001467`androidx.annotation:annotation-experimental` artifact regardless of whether
1468they are using the `androidx` or Kotlin annotation. This artifact provides Lint
1469enforcement of experimental usage restrictions for Kotlin callers as well as
1470Java (which the Kotlin annotation doesn't handle on its own, since it's a Kotlin
1471compiler feature). Libraries *may* include the dependency as `api`-type to make
alanvf5ca4b92021-02-10 13:07:47 -08001472`@OptIn` available to Java clients; however, this will also unnecessarily expose
1473the `@RequiresOptIn` annotation.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001474
1475```java
1476dependencies {
1477 implementation(project(":annotation:annotation-experimental"))
1478}
1479```
1480
1481See Kotlin's
alanvf5ca4b92021-02-10 13:07:47 -08001482[opt-in requirements documentation](https://kotlinlang.org/docs/reference/opt-in-requirements.html)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001483for general usage information. If you are writing experimental Java APIs, you
1484will use the Jetpack
alanvf5ca4b92021-02-10 13:07:47 -08001485[`@RequiresOptIn` annotation](https://developer.android.com/reference/kotlin/androidx/annotation/RequiresOptIn)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001486rather than the Kotlin compiler's annotation.
1487
1488#### How to transition an API out of experimental
1489
1490When an API surface is ready to transition out of experimental, the annotation
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00001491may only be removed during an alpha pre-release stage. Removing the experimental
1492marker from an API is equivalent to adding the API to the current API surface.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001493
1494When transitioning an entire feature surface out of experimental, you *should*
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00001495remove the definition for the associated annotation.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001496
1497When making any change to the experimental API surface, you *must* run
1498`./gradlew updateApi` prior to uploading your change.
1499
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00001500### `@RestrictTo` APIs {#restricted-api}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001501
1502Jetpack's library tooling supports hiding Java-visible (ex. `public` and
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001503`protected`) APIs from developers using a combination of the `@RestrictTo`
1504source annotation, and the `@hide` docs annotation (`@suppress` in Kotlin).
1505These annotations **must** be paired together when used, and are validated as
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00001506part of presubmit checks for Java code.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001507
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00001508> `@RestrictTo` at-a-glance:
1509>
1510> * Use for internal-facing API surfaces
1511> * Can be called within the specified `Scope`
1512> * Does not appear in public documentation
1513> * Does not maintain compatibility in most scopes
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001514
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00001515While restricted APIs do not appear in documentation and Android Studio will
1516warn against calling them, hiding an API does *not* provide strong guarantees
1517about usage:
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001518
1519* There are no runtime restrictions on calling hidden APIs
1520* Android Studio will not warn if hidden APIs are called using reflection
1521* Hidden APIs will still show in Android Studio's auto-complete
1522
1523#### When to use `@hide` {#restricted-api-usage}
1524
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001525In other cases, avoid using `@hide` / `@suppress`. These annotations indicates
alanv1d2bee52021-09-13 08:49:27 -07001526that developers should not call an API that is *technically* public from a Java
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001527visibility perspective. Hiding APIs is often a sign of a poorly-abstracted API
1528surface, and priority should be given to creating public, maintainable APIs and
1529using Java visibility modifiers.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001530
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001531*Do not* use `@hide`/`@suppress` to bypass API tracking and review for
1532production APIs; instead, rely on API+1 and API Council review to ensure APIs
1533are reviewed on a timely basis.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001534
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001535*Do not* use `@hide`/`@suppress` for implementation detail APIs that are used
1536between libraries and could reasonably be made public.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001537
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001538*Do* use `@hide`/`@suppress` paired with `@RestrictTo(LIBRARY)` for
1539implementation detail APIs used within a single library (but prefer Java
1540language `private` or `default` visibility).
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001541
1542#### `RestrictTo.Scope` and inter- versus intra-library API surfaces {#private-api-types}
1543
1544To maintain binary compatibility between different versions of libraries,
alanv3e722072021-09-10 09:39:35 -07001545restricted API surfaces that are used between libraries within Jetpack
1546(inter-library APIs) must follow the same Semantic Versioning rules as public
1547APIs. Inter-library APIs should be annotated with the
1548`@RestrictTo(LIBRARY_GROUP)` source annotation and `@hide` docs annotation.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001549
1550Restricted API surfaces used within a single library (intra-library APIs), on
1551the other hand, may be added or removed without any compatibility
alanv3e722072021-09-10 09:39:35 -07001552considerations. It is safe to assume that developers *never* call these APIs,
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001553even though it is technically feasible. Intra-library APIs should be annotated
alanv3e722072021-09-10 09:39:35 -07001554with the `@RestrictTo(LIBRARY)` source annotation and `@hide` docs annotation.
1555
1556In all cases, correctness and compatibility tracking are handled by AndroidX's
1557build system and lint checks.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001558
1559The following table shows the visibility of a hypothetical API within Maven
1560coordinate `androidx.concurrent:concurrent` when annotated with a variety of
1561scopes:
1562
1563<table>
1564 <tr>
1565 <td><code>RestrictTo.Scope</code></td>
1566 <td>Visibility by Maven coordinate</td>
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001567 <td>Versioning</td>
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00001568 <td>Note</td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001569 </tr>
1570 <tr>
1571 <td><code>LIBRARY</code></td>
1572 <td><code>androidx.concurrent:concurrent</code></td>
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00001573 <td>No compatibility guarantees (same as private)</td>
1574 <td></td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001575 </tr>
1576 <tr>
1577 <td><code>LIBRARY_GROUP</code></td>
1578 <td><code>androidx.concurrent:*</code></td>
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001579 <td>Semantic versioning (including deprecation)</td>
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00001580 <td></td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001581 </tr>
1582 <tr>
1583 <td><code>LIBRARY_GROUP_PREFIX</code></td>
1584 <td><code>androidx.*:*</code></td>
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001585 <td>Semantic versioning (including deprecation)</td>
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00001586 <td></td>
1587 </tr>
1588 <tr>
1589 <td><code>TEST</code></td>
1590 <td><code>*</code></td>
1591 <td>No compatibility guarantees (same as private)</td>
1592 <td>Not recommended. Prefer language visibility, e.g. `internal` or package-private.</td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001593 </tr>
1594</table>
1595
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001596#### `@IntDef` `@StringDef` and `@LongDef` and visibility
1597
1598All `@IntDef`, `@StringDef`, and `@LongDef` will be stripped from resulting
1599artifacts to avoid issues where compiler inlining constants removes information
1600as to which `@IntDef` defined the value of `1`. The annotations are extracted
1601and packaged separately to be read by Android Studio and lint which enforces the
1602types in application code.
1603
AndroidX Core Team26cc3c72021-09-08 01:05:14 -07001604* Libraries *must* `@hide` all `@IntDef`, `@StringDef`, and `@LongDef`
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001605 declarations.
AndroidX Core Team26cc3c72021-09-08 01:05:14 -07001606* Libraries *must* expose constants used to define the `@IntDef` etc at the
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001607 same Java visibility as the hidden `@IntDef`
AndroidX Core Team26cc3c72021-09-08 01:05:14 -07001608* Libraries *must* use `@RestrictTo` to create a warning when the type is used
1609 incorrectly.
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001610
1611Here is a complete example of an `@IntDef`
1612
1613```java
1614// constants match Java visibility of ExifStreamType
1615// code outside this module interacting with ExifStreamType uses these constants
1616public static final int STREAM_TYPE_FULL_IMAGE_DATA = 1;
1617public static final int STREAM_TYPE_EXIF_DATA_ONLY = 2;
1618
1619/** @hide */
1620@RestrictTo(RestrictTo.Scope.LIBRARY) // Don't export ExifStreamType outside module
1621@Retention(RetentionPolicy.SOURCE)
1622@IntDef({
1623 STREAM_TYPE_FULL_IMAGE_DATA,
1624 STREAM_TYPE_EXIF_DATA_ONLY,
1625})
1626public @interface ExifStreamType {}
1627```
1628
1629Java visibilty should be set as appropriate for the code in question (`private`,
1630`package` or `public`) and is unrelated to hiding.
1631
1632For more, read the section in
1633[Android API Council Guidelines](https://android.googlesource.com/platform/developers/docs/+/refs/heads/master/api-guidelines/index.md#no-public-typedefs)
1634
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001635### Constructors {#constructors}
1636
1637#### View constructors {#view-constructors}
1638
1639The four-arg View constructor -- `View(Context, AttributeSet, int, int)` -- was
1640added in SDK 21 and allows a developer to pass in an explicit default style
1641resource rather than relying on a theme attribute to resolve the default style
1642resource. Because this API was added in SDK 21, care must be taken to ensure
1643that it is not called through any < SDK 21 code path.
1644
alanv1d2bee52021-09-13 08:49:27 -07001645Views *may* implement a four-arg constructor in one of the following ways:
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001646
16471. Do not implement.
16481. Implement and annotate with `@RequiresApi(21)`. This means the three-arg
1649 constructor **must not** call into the four-arg constructor.
1650
1651### Asynchronous work {#async}
1652
1653#### With return values {#async-return}
1654
AndroidX Core Team21ccf652022-04-01 14:53:07 +00001655###### Kotlin
1656
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001657Traditionally, asynchronous work on Android that results in an output value
1658would use a callback; however, better alternatives exist for libraries.
1659
AndroidX Core Team21ccf652022-04-01 14:53:07 +00001660Kotlin libraries should consider
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001661[coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) and
AndroidX Core Team21ccf652022-04-01 14:53:07 +00001662`suspend` functions for APIs according to the following rules, but please refer
1663to the guidance on [allowable dependencies](#dependencies-coroutines) before
1664adding a new dependency on coroutines.
1665
1666Kotlin suspend fun vs blocking | Behavior
1667------------------------------------ | --------------------------
1668blocking function with @WorkerThread | API is blocking
1669suspend | API is async (e.g. Future)
1670
1671In general, do not introduce a suspend function entirely to switch threads for
1672blocking calls. To do so correctly requires that we allow the developer to
1673configure the Dispatcher. As there is already a coroutines-based API for
1674changing dispatchers (withContext) that the caller may use to switch threads, it
1675is unecessary API overhead to provide a duplicate mechanism. In addition, it
1676unecessary limits callers to coroutine contexts.
1677
1678```kotlin
1679// DO expose blocking calls as blocking calls
1680@WorkerThread
1681fun blockingCall()
1682
1683// DON'T wrap in suspend functions (only to switch threads)
1684suspend fun blockingCallWrappedInSuspend(
1685 dispatcher: CoroutineDispatcher = Dispatchers.Default
1686) = withContext(dispatcher) { /* ... */ }
1687
1688// DO expose async calls as suspend funs
1689suspend fun asyncCall(): ReturnValue
1690
1691// DON'T expose async calls as a callback-based API (for the main API)
1692fun asyncCall(executor: Executor, callback: (ReturnValue) -> Unit)
1693```
1694
1695###### Java
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001696
1697Java libraries should prefer `ListenableFuture` and the
1698[`CallbackToFutureAdapter`](https://developer.android.com/reference/androidx/concurrent/futures/CallbackToFutureAdapter)
1699implementation provided by the `androidx.concurrent:concurrent-futures` library.
AndroidX Core Team673068f2021-09-09 11:06:18 -07001700Functions and methods that return `ListenableFuture` should be suffixed by,
1701`Async` to reserve the shorter, unmodified name for a `suspend` method or
1702extension function in Kotlin that returns the value normally in accordance with
1703structured concurrency.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001704
1705Libraries **must not** use `java.util.concurrent.CompletableFuture`, as it has a
1706large API surface that permits arbitrary mutation of the future's value and has
1707error-prone defaults.
1708
1709See the [Dependencies](#dependencies) section for more information on using
1710Kotlin coroutines and Guava in your library.
1711
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001712#### Cancellation
1713
1714Libraries that expose APIs for performing asynchronous work should support
alanv1d2bee52021-09-13 08:49:27 -07001715cancellation. There are *very few* cases where it is not feasible to support
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001716cancellation.
1717
1718Libraries that use `ListenableFuture` must be careful to follow the exact
1719specification of
1720[`Future.cancel(boolean mayInterruptIfRunning)`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html?is-external=true#cancel-boolean-)
1721behavior.
1722
1723```java {.bad}
1724@Override
1725public boolean cancel(boolean mayInterruptIfRunning) {
1726 // Does not support cancellation.
1727 return false;
1728}
1729```
1730
1731```java {.bad}
1732@Override
1733public boolean cancel(boolean mayInterruptIfRunning) {
1734 // Aggressively does not support cancellation.
1735 throw new UnsupportedOperationException();
1736}
1737```
1738
1739```java {.good}
1740@Override
1741public boolean cancel(boolean mayInterruptIfRunning) {
1742 // Pseudocode that ignores threading but follows the spec.
1743 if (mCompleted
1744 || mCancelled
1745 || mRunning && !mayInterruptIfRunning) {
1746 return false;
1747 }
1748 mCancelled = true;
1749 return true;
1750}
1751```
1752
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001753#### Avoid `synchronized` methods
1754
1755Whenever multiple threads are interacting with shared (mutable) references those
1756reads and writes must be synchronized in some way. However synchronized blocks
1757make your code thread-safe at the expense of concurrent execution. Any time
1758execution enters a synchronized block or method any other thread trying to enter
1759a synchronized block on the same object has to wait; even if in practice the
1760operations are unrelated (e.g. they interact with different fields). This can
1761dramatically reduce the benefit of trying to write multi-threaded code in the
1762first place.
1763
1764Locking with synchronized is a heavyweight form of ensuring ordering between
1765threads, and there are a number of common APIs and patterns that you can use
1766that are more lightweight, depending on your use case:
1767
1768* Compute a value once and make it available to all threads
1769* Update Set and Map data structures across threads
1770* Allow a group of threads to process a stream of data concurrently
1771* Provide instances of a non-thread-safe type to multiple threads
1772* Update a value from multiple threads atomically
1773* Maintain granular control of your concurrency invariants
1774
alanvf89295e2022-05-10 08:08:55 -07001775### Kotlin-specific guidelines {#kotlin}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001776
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001777#### Nullability from Java (new APIs)
1778
1779All new Java APIs should be annotated either `@Nullable` or `@NonNull` for all
1780reference parameters and reference return types.
1781
1782```java
1783 @Nullable
1784 public Object someNewApi(@NonNull Thing arg1, @Nullable List<WhatsIt> arg2) {
1785 if(/** something **/) {
1786 return someObject;
1787 } else {
1788 return null;
1789 }
1790```
1791
1792#### Nullability from Java (existing APIs)
1793
1794Adding `@Nullable` or `@NonNull` annotations to existing APIs to document their
1795existing nullability is OK. This is a source breaking change for Kotlin
1796consumers, and you should ensure that it's noted in the release notes and try to
1797minimize the frequency of these updates in releases.
1798
1799Changing the nullability of an API is a breaking change.
1800
1801#### Extending APIs that expose types without nullability annotations
1802
1803[Platform types](https://kotlinlang.org/docs/java-interop.html#null-safety-and-platform-types)
1804are exposed by Java types that do not have a `@Nullable` or `@NonNull`
1805annotation. In Kotlin they are indicated with the `!` suffix.
1806
1807When interacting with an Android platform API that exposes APIs with unknown
1808nullability follow these rules:
1809
18101. If wrapping the type in a new API, define and handle `@Nullable` or
1811 `@NonNull` in the library. Treat types with unknown nullability passed into
1812 or return from Android as `@Nullable` in the library.
18132. If extending an existing API (e.g. `@Override`), pass through the existing
1814 types with unknown nullability and annotate each with
1815 `@SuppressLint("UnknownNullness")`
1816
1817In Kotlin, a type with unknown nullability is exposed as a "platform type"
1818(indicated with a `!` suffix) which has unknown nullability in the type checker,
1819and may bypass type checking leading to runtime errors. When possible, do not
1820directly expose types with unknown nullability in new public APIs.
1821
1822#### Extending `@RecentlyNonNull` and `@RecentlyNullable` APIs
1823
1824Platform APIs are annotated in the platform SDK artifacts with fake annotations
1825`@RecentlyNonNull` and `@RecentlyNullable` to avoid breaking builds when we
1826annotated platform APIs with nullability. These annotations cause warnings
1827instead of build failures. The `RecentlyNonNull` and `RecentlyNullable`
1828annotations are added by Metalava and do not appear in platform code.
1829
1830When extending an API that is annotated `@RecentlyNonNull`, you should annotate
1831the override with `@NonNull`, and the same for `@RecentlyNullable` and
1832`@Nullable`.
1833
1834For example `SpannableStringBuilder.append` is annotated `RecentlyNonNull` and
1835an override should look like:
1836
1837```java
1838 @NonNull
1839 @Override
1840 public SpannableStringBuilder append(@SuppressLint("UnknownNullness") CharSequence text) {
1841 super.append(text);
1842 return this;
1843 }
1844```
1845
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001846#### Data classes {#kotlin-data}
1847
1848Kotlin `data` classes provide a convenient way to define simple container
1849objects, where Kotlin will generate `equals()` and `hashCode()` for you.
1850However, they are not designed to preserve API/binary compatibility when members
1851are added. This is due to other methods which are generated for you -
1852[destructuring declarations](https://kotlinlang.org/docs/reference/multi-declarations.html),
1853and [copying](https://kotlinlang.org/docs/reference/data-classes.html#copying).
1854
1855Example data class as tracked by metalava:
1856
1857<pre>
1858 public final class TargetAnimation {
1859 ctor public TargetAnimation(float target, androidx.animation.AnimationBuilder animation);
1860 <b>method public float component1();</b>
1861 <b>method public androidx.animation.AnimationBuilder component2();</b>
1862 <b>method public androidx.animation.TargetAnimation copy(float target, androidx.animation.AnimationBuilder animation);</b>
1863 method public androidx.animation.AnimationBuilder getAnimation();
1864 method public float getTarget();
1865 }
1866</pre>
1867
1868Because members are exposed as numbered components for destructuring, you can
1869only safely add members at the end of the member list. As `copy` is generated
1870with every member name in order as well, you'll also have to manually
1871re-implement any old `copy` variants as items are added. If these constraints
1872are acceptable, data classes may still be useful to you.
1873
alanv1d2bee52021-09-13 08:49:27 -07001874As a result, Kotlin `data` classes are *strongly discouraged* in library APIs.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001875Instead, follow best-practices for Java data classes including implementing
1876`equals`, `hashCode`, and `toString`.
1877
1878See Jake Wharton's article on
1879[Public API challenges in Kotlin](https://jakewharton.com/public-api-challenges-in-kotlin/)
1880for more details.
1881
AndroidX Core Team6fd727f2021-06-01 12:26:34 -07001882#### Exhaustive `when` and `sealed class`/`enum class` {#exhaustive-when}
1883
1884A key feature of Kotlin's `sealed class` and `enum class` declarations is that
1885they permit the use of **exhaustive `when` expressions.** For example:
1886
1887```kotlin
1888enum class CommandResult { Permitted, DeniedByUser }
1889
1890val message = when (commandResult) {
1891 Permitted -> "the operation was permitted"
1892 DeniedByUser -> "the user said no"
1893}
1894
1895println(message)
1896```
1897
1898This highlights challenges for library API design and compatibility. Consider
1899the following addition to the `CommandResult` possibilities:
1900
1901```kotlin {.bad}
1902enum class CommandResult {
1903 Permitted,
1904 DeniedByUser,
1905 DeniedByAdmin // New in androidx.mylibrary:1.1.0!
1906}
1907```
1908
1909This change is both **source and binary breaking.**
1910
1911It is **source breaking** because the author of the `when` block above will see
1912a compiler error about not handling the new result value.
1913
1914It is **binary breaking** because if the `when` block above was compiled as part
1915of a library `com.example.library:1.0.0` that transitively depends on
1916`androidx.mylibrary:1.0.0`, and an app declares the dependencies:
1917
1918```kotlin
1919implementation("com.example.library:1.0.0")
1920implementation("androidx.mylibrary:1.1.0") // Updated!
1921```
1922
1923`com.example.library:1.0.0` does not handle the new result value, leading to a
1924runtime exception.
1925
1926**Note:** The above example is one where Kotlin's `enum class` is the correct
1927tool and the library should **not** add a new constant! Kotlin turns this
1928semantic API design problem into a compiler or runtime error. This type of
1929library API change could silently cause app logic errors or data corruption
1930without the protection provided by exhaustive `when`. See
1931[When to use exhaustive types](#when-to-use-exhaustive-types).
1932
1933`sealed class` exhibits the same characteristic; adding a new subtype of an
1934existing sealed class is a breaking change for the following code:
1935
1936```kotlin
1937val message = when (command) {
1938 is Command.Migrate -> "migrating to ${command.destination}"
1939 is Command.Quack -> "quack!"
1940}
1941```
1942
1943##### Non-exhaustive alternatives to `enum class`
1944
1945Kotlin's `@JvmInline value class` with a `private constructor` can be used to
1946create type-safe sets of non-exhaustive constants as of Kotlin 1.5. Compose's
1947`BlendMode` uses the following pattern:
1948
1949```kotlin {.good}
1950@JvmInline
1951value class BlendMode private constructor(val value: Int) {
1952 companion object {
1953 /** Drop both the source and destination images, leaving nothing. */
1954 val Clear = BlendMode(0)
1955 /** Drop the destination image, only paint the source image. */
1956 val Src = BlendMode(1)
1957 // ...
1958 }
1959}
1960```
1961
1962**Note:** This recommendation may be temporary. Kotlin may add new annotations
1963or other language features to declare non-exhaustive enum classes in the future.
1964
1965Alternatively, the existing `@IntDef` mechanism used in Java-language androidx
1966libraries may also be used, but type checking of constants will only be
1967performed by lint, and functions overloaded with parameters of different value
1968class types are not supported. Prefer the `@JvmInline value class` solution for
1969new code unless it would break local consistency with other API in the same
1970module that already uses `@IntDef`.
1971
1972##### Non-exhaustive alternatives to `sealed class`
1973
1974Abstract classes with constructors marked as `internal` or `private` can
1975represent the same subclassing restrictions of sealed classes as seen from
1976outside of a library module's own codebase:
1977
1978```kotlin
1979abstract class Command private constructor() {
1980 class Migrate(val destination: String) : Command()
1981 object Quack : Command()
1982}
1983```
1984
1985Using an `internal` constructor will permit non-nested subclasses, but will
1986**not** restrict subclasses to the same package within the module, as sealed
1987classes do.
1988
1989##### When to use exhaustive types
1990
1991Use `enum class` or `sealed class` when the values or subtypes are intended to
1992be exhaustive by design from the API's initial release. Use non-exhaustive
1993alternatives when the set of constants or subtypes might expand in a minor
1994version release.
1995
1996Consider using an **exhaustive** (`enum class` or `sealed class`) type
1997declaration if:
1998
1999* The developer is expected to **accept** values of the type
2000* The developer is expected to **act** on **any and all** values received
2001
2002Consider using a **non-exhaustive** type declaration if:
2003
2004* The developer is expected to **provide** values of the type to APIs exposed
2005 by the same module **only**
2006* The developer is expected to **ignore** unknown values received
2007
2008The `CommandResult` example above is a good example of a type that **should**
2009use the exhaustive `enum class`; `CommandResult`s are **returned** to the
2010developer and the developer cannot implement correct app behavior by ignoring
2011unrecognized result values. Adding a new result value would semantically break
2012existing code regardless of the language facility used to express the type.
2013
2014```kotlin {.good}
2015enum class CommandResult { Permitted, DeniedByUser, DeniedByAdmin }
2016```
2017
2018Compose's `BlendMode` is a good example of a type that **should not** use the
2019exhaustive `enum class`; blending modes are used as arguments to Compose
2020graphics APIs and are not intended for interpretation by app code. Additionally,
2021there is historical precedent from `android.graphics` for new blending modes to
2022be added in the future.
2023
AndroidX Core Team2e416b22020-12-03 22:58:07 +00002024#### Extension and top-level functions {#kotlin-extension-functions}
2025
AndroidX Core Team6fd727f2021-06-01 12:26:34 -07002026If your Kotlin file contains any symbols outside of class-like types
AndroidX Core Team2e416b22020-12-03 22:58:07 +00002027(extension/top-level functions, properties, etc), the file must be annotated
2028with `@JvmName`. This ensures unanticipated use-cases from Java callers don't
2029get stuck using `BlahKt` files.
2030
2031Example:
2032
2033```kotlin {.bad}
2034package androidx.example
2035
2036fun String.foo() = // ...
2037```
2038
2039```kotlin {.good}
2040@file:JvmName("StringUtils")
2041
2042package androidx.example
2043
2044fun String.foo() = // ...
2045```
2046
2047NOTE This guideline may be ignored for libraries that only work in Kotlin (think
2048Compose).
2049
2050## Testing Guidelines
2051
2052### [Do not Mock, AndroidX](do_not_mock.md)
2053
2054## Android Lint Guidelines
2055
2056### Suppression vs Baselines
2057
2058Lint sometimes flags false positives, even though it is safe to ignore these
2059errors (for example WeakerAccess warnings when you are avoiding synthetic
2060access). There may also be lint failures when your library is in the middle of a
2061beta / rc / stable release, and cannot make the breaking changes needed to fix
2062the root cause. There are two ways of ignoring lint errors:
2063
20641. Suppression - using `@SuppressLint` (for Java) or `@Suppress` annotations to
2065 ignore the warning per call site, per method, or per file. *Note
2066 `@SuppressLint` - Requires Android dependency*.
20672. Baselines - allowlisting errors in a lint-baseline.xml file at the root of
2068 the project directory.
2069
2070Where possible, you should use a **suppression annotation at the call site**.
2071This helps ensure that you are only suppressing the *exact* failure, and this
2072also keeps the failure visible so it can be fixed later on. Only use a baseline
2073if you are in a Java library without Android dependencies, or when enabling a
2074new lint check, and it is prohibitively expensive / not possible to fix the
2075errors generated by enabling this lint check.
2076
AndroidX Core Team21ccf652022-04-01 14:53:07 +00002077To update a lint baseline (`lint-baseline.xml`) after you have fixed issues, run
2078the `updateLintBaseline` task.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00002079
2080```shell
AndroidX Core Team21ccf652022-04-01 14:53:07 +00002081./gradlew :core:core:updateLintBaseline
AndroidX Core Team2e416b22020-12-03 22:58:07 +00002082```
2083
2084## Metalava API Lint
2085
2086As well as Android Lint, which runs on all source code, Metalava will also run
2087checks on the public API surface of each library. Similar to with Android Lint,
2088there can sometimes be false positives / intended deviations from the API
2089guidelines that Metalava will lint your API surface against. When this happens,
2090you can suppress Metalava API lint issues using `@SuppressLint` (for Java) or
2091`@Suppress` annotations. In cases where it is not possible, update Metalava's
2092baseline with the `updateApiLintBaseline` task.
2093
2094```shell
AndroidX Core Team4e1909a2021-10-20 15:04:04 +00002095./gradlew :core:core:updateApiLintBaseline
AndroidX Core Team2e416b22020-12-03 22:58:07 +00002096```
2097
2098This will create/amend the `api_lint.ignore` file that lives in a library's
2099`api` directory.
2100
2101## Build Output Guidelines
2102
2103In order to more easily identify the root cause of build failures, we want to
2104keep the amount of output generated by a successful build to a minimum.
2105Consequently, we track build output similarly to the way in which we track Lint
2106warnings.
2107
2108### Invoking build output validation
2109
2110You can add `-Pandroidx.validateNoUnrecognizedMessages` to any other AndroidX
2111gradlew command to enable validation of build output. For example:
2112
2113```shell
2114/gradlew -Pandroidx.validateNoUnrecognizedMessages :help
2115```
2116
2117### Exempting new build output messages
2118
2119Please avoid exempting new build output and instead fix or suppress the warnings
2120themselves, because that will take effect not only on the build server but also
2121in Android Studio, and will also run more quickly.
2122
2123If you cannot prevent the message from being generating and must exempt the
2124message anyway, follow the instructions in the error:
2125
2126```shell
2127$ ./gradlew -Pandroidx.validateNoUnrecognizedMessages :help
2128
2129Error: build_log_simplifier.py found 15 new messages found in /usr/local/google/workspace/aosp-androidx-git/out/dist/gradle.log.
2130
2131Please fix or suppress these new messages in the tool that generates them.
2132If you cannot, then you can exempt them by doing:
2133
2134 1. cp /usr/local/google/workspace/aosp-androidx-git/out/dist/gradle.log.ignore /usr/local/google/workspace/aosp-androidx-git/frameworks/support/development/build_log_simplifier/messages.ignore
2135 2. modify the new lines to be appropriately generalized
2136```
2137
2138Each line in this exemptions file is a regular expressing matching one or more
2139lines of output to be exempted. You may want to make these expressions as
2140specific as possible to ensure that the addition of new, similar messages will
2141also be detected (for example, discovering an existing warning in a new source
2142file).
2143
2144## Behavior changes
2145
2146### Changes that affect API documentation
2147
2148Do not make behavior changes that require altering API documentation in a way
2149that would break existing clients, even if such changes are technically binary
2150compatible. For example, changing the meaning of a method's return value to
2151return true rather than false in a given state would be considered a breaking
2152change. Because this change is binary-compatible, it will not be caught by
2153tooling and is effectively invisible to clients.
2154
2155Instead, add new methods and deprecate the existing ones if necessary, noting
2156behavior changes in the deprecation message.
2157
2158### High-risk behavior changes
2159
2160Behavior changes that conform to documented API contracts but are highly complex
2161and difficult to comprehensively test are considered high-risk and should be
2162implemented using behavior flags. These changes may be flagged on initially, but
2163the original behaviors must be preserved until the library enters release
2164candidate stage and the behavior changes have been appropriately verified by
2165integration testing against public pre-release
2166revisions.
2167
2168It may be necessary to soft-revert a high-risk behavior change with only 24-hour
2169notice, which should be achievable by flipping the behavior flag to off.
2170
2171```java
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00002172// Flag for whether to throw exceptions when the state is known to be bad. This
2173// is expected to be a high-risk change since apps may be working fine even with
2174// a bad state, so we may need to disable this as a hotfix.
2175private static final boolean FLAG_EXCEPTION_ON_BAD_STATE = false;
2176```
2177
2178```java
2179/**
2180 * Allows a developer to toggle throwing exceptions when the state is known to
2181 * be bad. This method is intended to give developers time to update their code.
2182 * It is temporary and will be removed in a future release.
2183 */
2184@TemporaryFeatureFlag
2185public void setExceptionOnBadStateEnabled(boolean enabled);
AndroidX Core Team2e416b22020-12-03 22:58:07 +00002186```
2187
2188Avoid adding multiple high-risk changes during a feature cycle, as verifying the
2189interaction of multiple feature flags leads to unnecessary complexity and
2190exposes clients to high risk even when a single change is flagged off. Instead,
2191wait until one high-risk change has landed in RC before moving on to the next.
2192
2193#### Testing
2194
2195Relevant tests should be run for the behavior change in both the on and off
2196flagged states to prevent regressions.
2197
2198## Sample code in Kotlin modules
2199
2200### Background
2201
2202Public API can (and should!) have small corresponding code snippets that
2203demonstrate functionality and usage of a particular API. These are often exposed
2204inline in the documentation for the function / class - this causes consistency
2205and correctness issues as this code is not compiled against, and the underlying
2206implementation can easily change.
2207
2208KDoc (JavaDoc for Kotlin) supports a `@sample` tag, which allows referencing the
2209body of a function from documentation. This means that code samples can be just
2210written as a normal function, compiled and linted against, and reused from other
2211modules such as tests! This allows for some guarantees on the correctness of a
2212sample, and ensuring that it is always kept up to date.
2213
2214### Enforcement
2215
2216There are still some visibility issues here - it can be hard to tell if a
2217function is a sample, and is used from public documentation - so as a result we
2218have lint checks to ensure sample correctness.
2219
2220Primarily, there are three requirements when using sample links:
2221
22221. All functions linked to from a `@sample` KDoc tag must be annotated with
2223 `@Sampled`
22242. All sample functions annotated with `@Sampled` must be linked to from a
2225 `@sample` KDoc tag
22263. All sample functions must live inside a separate `samples` library
2227 submodule - see the section on module configuration below for more
2228 information.
2229
2230This enforces visibility guarantees, and make it easier to know that a sample is
2231a sample. This also prevents orphaned samples that aren't used, and remain
2232unmaintained and outdated.
2233
2234### Sample usage
2235
2236The follow demonstrates how to reference sample functions from public API. It is
2237also recommended to reuse these samples in unit tests / integration tests / test
AndroidX Core Team4cc85fa2021-11-23 15:58:34 +00002238apps / library demos where possible to help ensure that the samples work as
2239intended.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00002240
2241**Public API:**
2242
2243```
2244/*
2245 * Fancy prints the given [string]
2246 *
2247 * @sample androidx.printer.samples.fancySample
2248 */
2249fun fancyPrint(str: String) ...
2250```
2251
2252**Sample function:**
2253
2254```
2255package androidx.printer.samples
2256
2257import androidx.printer.fancyPrint
2258
2259@Sampled
2260fun fancySample() {
2261 fancyPrint("Fancy!")
2262}
2263```
2264
AndroidX Core Team4cc85fa2021-11-23 15:58:34 +00002265**Generated documentation visible on d.android.com / within Android Studio**
AndroidX Core Team2e416b22020-12-03 22:58:07 +00002266
2267```
2268fun fancyPrint(str: String)
2269
2270Fancy prints the given [string]
2271
2272<code>
2273 import androidx.printer.fancyPrint
2274
2275 fancyPrint("Fancy!")
2276<code>
2277```
2278
AndroidX Core Team4cc85fa2021-11-23 15:58:34 +00002279Warning: Only the body of the function is used in generated documentation, so
2280any other references to elements defined outside the body of the function (such
2281as variables defined within the sample file) will not be visible. To ensure that
2282samples can be easily copy and pasted without errors, make sure that any
2283references are defined within the body of the function.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00002284
2285### Module configuration
2286
AndroidX Core Team4cc85fa2021-11-23 15:58:34 +00002287The following module setups should be used for sample functions:
2288
2289**Per-module samples**
2290
2291For library groups with relatively independent sub-libraries. This is the
2292recommended project setup, and should be used in most cases.
2293
2294Gradle project name: `:foo-library:foo-module:foo-module-samples`
2295
2296```
2297foo-library/
2298 foo-module/
2299 samples/
2300```
AndroidX Core Team2e416b22020-12-03 22:58:07 +00002301
2302**Group-level samples**
2303
AndroidX Core Team4cc85fa2021-11-23 15:58:34 +00002304For library groups with strongly related samples that want to share code and be
2305reused across a library group, a singular shared samples library can be created.
2306In most cases this is discouraged - samples should be small and show the usage
2307of a particular API / small set of APIs, instead of more complicated usage
2308combining multiple APIs from across libraries. For these cases a sample
2309application is more appropriate.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00002310
AndroidX Core Team0db91f02021-05-06 22:45:18 +00002311Gradle project name: `:foo-library:foo-library-samples`
AndroidX Core Team2e416b22020-12-03 22:58:07 +00002312
2313```
2314foo-library/
2315 foo-module/
2316 bar-module/
2317 samples/
2318```
2319
AndroidX Core Team0db91f02021-05-06 22:45:18 +00002320**Samples module configuration**
2321
2322Samples modules are published to GMaven so that they are available to Android
AndroidX Core Team4cc85fa2021-11-23 15:58:34 +00002323Studio, which displays referenced samples as hover-over pop-ups.
AndroidX Core Team0db91f02021-05-06 22:45:18 +00002324
2325To achieve this, samples modules must declare the same MavenGroup and `publish`
2326as the library(s) they are samples for.