blob: 2510986b742a3ced3da1894094159dcb282c2ebe [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
45#### Project directory structure {#module-structure}
46
47Libraries developed in AndroidX follow a consistent project naming and directory
48structure.
49
50Library groups should organize their projects into directories and project names
51(in brackets) as:
52
53```
54<feature-name>/
55 <feature-name>-<sub-feature>/ [<feature-name>:<feature-name>-<sub-feature>]
56 samples/ [<feature-name>:<feature-name>-<sub-feature>:samples]
57 integration-tests/
58 testapp/ [<feature-name>:testapp]
59 testlib/ [<feature-name>:testlib]
60```
61
62For example, the `navigation` library group's directory structure is:
63
64```
65navigation/
66 navigation-benchmark/ [navigation:navigation-benchmark]
67 ...
68 navigation-ui/ [navigation:navigation-ui]
69 navigation-ui-ktx/ [navigation:navigation-ui-ktx]
70 integration-tests/
71 testapp/ [navigation:integration-tests:testapp]
72```
73
74#### Project creator script {#module-creation}
75
76Note: The terms _project_, _module_, and _library_ are often used
77interchangeably within AndroidX, with project being the technical term used by
78Gradle to describe a build target, e.g. a library that maps to a single AAR.
79
80New projects can be created using our
81[project creation script](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:development/project-creator/?q=project-creator&ss=androidx%2Fplatform%2Fframeworks%2Fsupport)
82available in our repo.
83
84It will create a new project with the proper structure and configuration based
85on your project needs!
86
87To use it:
88
89```sh
AndroidX Core Teamfa352702021-08-16 10:06:19 -070090cd ~/androidx-main/frameworks/support && \
alanv93da5db2021-08-11 13:05:51 -070091cd development/project-creator && \
92./create_project.py androidx.foo foo-bar
93```
AndroidX Core Team9f9538a2021-06-07 12:03:58 -070094
AndroidX Core Team2e416b22020-12-03 22:58:07 +000095#### Common sub-feature names {#module-naming-subfeature}
96
97* `-testing` for an artifact intended to be used while testing usages of your
98 library, e.g. `androidx.room:room-testing`
99* `-core` for a low-level artifact that *may* contain public APIs but is
100 primarily intended for use by other libraries in the group
101* `-ktx` for an Kotlin artifact that exposes idiomatic Kotlin APIs as an
AndroidX Core Team0db91f02021-05-06 22:45:18 +0000102 extension to a Java-only library (see
103 [additional -ktx guidance](#module-ktx))
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000104* `-<third-party>` for an artifact that integrates an optional third-party API
105 surface, e.g. `-proto` or `-rxjava2`. Note that a major version is included
106 in the sub-feature name for third-party API surfaces where the major version
107 indicates binary compatibility (only needed for post-1.x).
108
109Artifacts **should not** use `-impl` or `-base` to indicate that a library is an
110implementation detail shared within the group. Instead, use `-core`.
111
112#### Splitting existing modules
113
114Existing modules _should not_ be split into smaller modules; doing so creates
115the potential for class duplication issues when a developer depends on a new
116sub-module alongside the older top-level module. Consider the following
117scenario:
118
119* `androidx.library:1.0.0`
AndroidX Core Team43201242021-01-26 21:38:01 +0000120 * contains class `androidx.library.A`
121 * contains class `androidx.library.util.B`
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000122
123This module is split, moving `androidx.library.util.B` to a new module:
124
125* `androidx.library:1.1.0`
126 * contains class `androidx.library.A`
AndroidX Core Team43201242021-01-26 21:38:01 +0000127 * depends on `androidx.library.util:1.1.0`
128* `androidx.library.util:1.1.0`
129 * contains class `androidx.library.util.B`
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000130
AndroidX Core Team43201242021-01-26 21:38:01 +0000131A developer writes an app that depends directly on `androidx.library.util:1.1.0`
132and also transitively pulls in `androidx.library:1.0.0`. Their app will no
133longer compile due to class duplication of `androidx.library.util.B`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000134
135While it is possible for the developer to fix this by manually specifying a
136dependency on `androidx.library:1.1.0`, there is no easy way for the developer
137to discover this solution from the class duplication error raised at compile
138time.
139
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +0000140Same-version groups are a special case for this rule. Existing modules that are
141already in a same-version group may be split into sub-modules provided that (a)
142the sub-modules are also in the same-version group and (b) the full API surface
143of the existing module is preserved through transitive dependencies, e.g. the
144sub-modules are added as dependencies of the existing module.
145
AndroidX Core Teamee1457a2021-02-25 16:13:10 +0000146#### Same-version (atomic) groups {#modules-atomic}
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000147
148Library groups are encouraged to opt-in to a same-version policy whereby all
149libraries in the group use the same version and express exact-match dependencies
150on libraries within the group. Such groups must increment the version of every
151library at the same time and release all libraries at the same time.
152
153Atomic groups are specified in
AndroidX Core Team408c27b2020-12-15 15:57:00 +0000154[`LibraryGroups.kt`](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt):
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000155
156```kotlin
157// Non-atomic library group
158val APPCOMPAT = LibraryGroup("androidx.appcompat", null)
159// Atomic library group
160val APPSEARCH = LibraryGroup("androidx.appsearch", LibraryVersions.APPSEARCH)
161```
162
163Libraries within an atomic group should not specify a version in their
164`build.gradle`:
165
166```groovy
167androidx {
168 name = 'AppSearch'
169 publish = Publish.SNAPSHOT_AND_RELEASE
170 mavenGroup = LibraryGroups.APPSEARCH
171 inceptionYear = '2019'
172 description = 'Provides local and centralized app indexing'
173}
174```
175
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000176The benefits of using an atomic group are:
177
178- Easier for developers to understand dependency versioning
179- `@RestrictTo(LIBRARY_GROUP)` APIs are treated as private APIs and not
180 tracked for binary compatibility
181- `@RequiresOptIn` APIs defined within the group may be used without any
182 restrictions between libraries in the group
183
184Potential drawbacks include:
185
186- All libraries within the group must be versioned identically at head
187- All libraries within the group must release at the same time
188
AndroidX Core Teamee1457a2021-02-25 16:13:10 +0000189#### Early-stage development {#modules-atomic-alpha}
190
191There is one exception to the same-version policy: newly-added libraries within
192an atomic group may be "quarantined" from other libraries to allow for rapid
193iteration until they are API-stable.
194
195A quarantined library must stay within the `1.0.0-alphaXX` cycle until it is
196ready to conform to the same-version policy. While in quarantime, a library is
197treated at though it is in a separate group from its nomical same-version group:
198
199- Must stay in `1.0.0-alphaXX`, e.g. same-version policy is not enforced
200- May use `project` or pinned version dependencies, e.g. strict-match
201 dependencies are not enforced
202- May release on a separate cadence from other libraries within group
203- Must not reference restricted `LIBRARY-GROUP`-scoped APIs
204
205When the library would like to leave quarantine, it must wait for its atomic
206group to be within a `beta` cycle and then match the version. It is okay for a
207library in this situation to skip versions, e.g. move directly from
208`1.0.0-alpha02` to `2.1.3-beta06`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000209
210### Choosing a `minSdkVersion` {#module-minsdkversion}
211
212The recommended minimum SDK version for new Jetpack libraries is currently
alanve2f875c2021-07-09 08:58:30 -0700213**19** (Android 4.4, KitKat). This SDK was chosen to represent 99% of active
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000214devices based on Play Store check-ins (see Android Studio
215[distribution metadata](https://dl.google.com/android/studio/metadata/distributions.json)
216for current statistics). This maximizes potential users for external developers
217while minimizing the amount of overhead necessary to support legacy versions.
218
219However, if no explicit minimum SDK version is specified for a library, the
alanv195c35f2021-06-10 14:29:40 -0700220default is **14** (Android 4.0, Ice Cream Sandwich).
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000221
222Note that a library **must not** depend on another library with a higher
223`minSdkVersion` that its own, so it may be necessary for a new library to match
224its dependent libraries' `minSdkVersion`.
225
226Individual modules may choose a higher minimum SDK version for business or
227technical reasons. This is common for device-specific modules such as Auto or
228Wear.
229
230Individual classes or methods may be annotated with the
231[@RequiresApi](https://developer.android.com/reference/android/annotation/RequiresApi.html)
232annotation to indicate divergence from the overall module's minimum SDK version.
233Note that this pattern is _not recommended_ because it leads to confusion for
234external developers and should be considered a last-resort when backporting
235behavior is not feasible.
236
AndroidX Core Team0db91f02021-05-06 22:45:18 +0000237### Kotlin extension `-ktx` libraries {#module-ktx}
238
239New libraries should prefer Kotlin sources with built-in Java compatibility via
240`@JvmName` and other affordances of the Kotlin language; however, existing Java
241sourced libraries may benefit from extending their API surface with
242Kotlin-friendly APIs in a `-ktx` library.
243
244A Kotlin extension library **may only** provide extensions for a single base
245library's API surface and its name **must** match the base library exactly. For
246example, `work:work-ktx` may only provide extensions for APIs exposed by
247`work:work`.
248
249Additionally, an extension library **must** specify an `api`-type dependency on
250the base library and **must** be versioned and released identically to the base
251library.
252
253Kotlin extension libraries _should not_ expose new functionality; they should
254only provide Kotlin-friendly versions of existing Java-facing functionality.
255
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000256## Platform compatibility API patterns {#platform-compatibility-apis}
257
AndroidX Core Team37584142021-02-25 17:58:46 +0000258NOTE For all library APIs that wrap or provide parity with platform APIs,
259_parity with the platform APIs overrides API guidelines_. For example, if the
260platform API being wrapped has incorrect `Executor` and `Callback` ordering
261according to the API Guidelines, the corresponding library API should have the
262exact same (incorrect) ordering.
263
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000264### Static shims (ex. [ViewCompat](https://developer.android.com/reference/android/support/v4/view/ViewCompat.html)) {#static-shim}
265
266When to use?
267
268* Platform class exists at module's `minSdkVersion`
269* Compatibility implementation does not need to store additional metadata
270
271Implementation requirements
272
273* Class name **must** be `<PlatformClass>Compat`
274* Package name **must** be `androidx.<feature>.<platform.package>`
275* Superclass **must** be `Object`
276* Class **must** be non-instantiable, i.e. constructor is private no-op
277* Static fields and static methods **must** match match signatures with
278 `PlatformClass`
279 * Static fields that can be inlined, ex. integer constants, **must not**
280 be shimmed
281* Public method names **must** match platform method names
282* Public methods **must** be static and take `PlatformClass` as first
283 parameter
284* Implementation _may_ delegate to `PlatformClass` methods when available
285
286#### Sample {#static-shim-sample}
287
288The following sample provides static helper methods for the platform class
289`android.os.Process`.
290
291```java
292/**
293 * Helper for accessing features in {@link Process}.
294 */
295public final class ProcessCompat {
296 private ProcessCompat() {
297 // This class is non-instantiable.
298 }
299
300 /**
301 * [Docs should match platform docs.]
302 *
303 * Compatibility behavior:
304 * <ul>
305 * <li>SDK 24 and above, this method matches platform behavior.
306 * <li>SDK 16 through 23, this method is a best-effort to match platform behavior, but may
307 * default to returning {@code true} if an accurate result is not available.
308 * <li>SDK 15 and below, this method always returns {@code true} as application UIDs and
309 * isolated processes did not exist yet.
310 * </ul>
311 *
312 * @param [match platform docs]
313 * @return [match platform docs], or a value based on platform-specific fallback behavior
314 */
315 public static boolean isApplicationUid(int uid) {
316 if (Build.VERSION.SDK_INT >= 24) {
317 return Api24Impl.isApplicationUid(uid);
318 } else if (Build.VERSION.SDK_INT >= 17) {
319 return Api17Impl.isApplicationUid(uid);
320 } else if (Build.VERSION.SDK_INT == 16) {
321 return Api16Impl.isApplicationUid(uid);
322 } else {
323 return true;
324 }
325 }
326
327 @RequiresApi(24)
328 static class Api24Impl {
329 static boolean isApplicationUid(int uid) {
330 // In N, the method was made public on android.os.Process.
331 return Process.isApplicationUid(uid);
332 }
333 }
334
335 @RequiresApi(17)
336 static class Api17Impl {
337 private static Method sMethod_isAppMethod;
338 private static boolean sResolved;
339
340 static boolean isApplicationUid(int uid) {
341 // In JELLY_BEAN_MR2, the equivalent isApp(int) hidden method moved to public class
342 // android.os.UserHandle.
343 try {
344 if (!sResolved) {
345 sResolved = true;
346 sMethod_isAppMethod = UserHandle.class.getDeclaredMethod("isApp",int.class);
347 }
348 if (sMethod_isAppMethod != null) {
349 return (Boolean) sMethod_isAppMethod.invoke(null, uid);
350 }
351 } catch (Exception e) {
352 e.printStackTrace();
353 }
354 return true;
355 }
356 }
357
358 ...
359}
360```
361
362### Wrapper (ex. [AccessibilityNodeInfoCompat](https://developer.android.com/reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html)) {#wrapper}
363
364When to use?
365
366* Platform class may not exist at module's `minSdkVersion`
367* Compatibility implementation may need to store additional metadata
368* Needs to integrate with platform APIs as return value or method argument
369* **Note:** Should be avoided when possible, as using wrapper classes makes it
370 very difficult to deprecate classes and migrate source code when the
371 `minSdkVersion` is raised
372
373#### Sample {#wrapper-sample}
374
375The following sample wraps a hypothetical platform class `ModemInfo` that was
376added to the platform SDK in API level 23:
377
378```java
379public final class ModemInfoCompat {
380 // Only guaranteed to be non-null on SDK_INT >= 23. Note that referencing the
381 // class itself directly is fine -- only references to class members need to
382 // be pushed into static inner classes.
383 private final ModemInfo wrappedObj;
384
385 /**
386 * [Copy platform docs for matching constructor.]
387 */
388 public ModemInfoCompat() {
389 if (SDK_INT >= 23) {
390 wrappedObj = Api23Impl.create();
391 } else {
392 wrappedObj = null;
393 }
394 ...
395 }
396
397 @RequiresApi(23)
398 private ModemInfoCompat(@NonNull ModemInfo obj) {
399 mWrapped = obj;
400 }
401
402 /**
403 * Provides a backward-compatible wrapper for {@link ModemInfo}.
404 * <p>
405 * This method is not supported on devices running SDK < 23 since the platform
406 * class will not be available.
407 *
408 * @param info platform class to wrap
409 * @return wrapped class, or {@code null} if parameter is {@code null}
410 */
411 @RequiresApi(23)
412 @NonNull
413 public static ModemInfoCompat toModemInfoCompat(@NonNull ModemInfo info) {
414 return new ModemInfoCompat(obj);
415 }
416
417 /**
418 * Provides the {@link ModemInfo} represented by this object.
419 * <p>
420 * This method is not supported on devices running SDK < 23 since the platform
421 * class will not be available.
422 *
423 * @return platform class object
424 * @see ModemInfoCompat#toModemInfoCompat(ModemInfo)
425 */
426 @RequiresApi(23)
427 @NonNull
428 public ModemInfo toModemInfo() {
429 return mWrapped;
430 }
431
432 /**
433 * [Docs should match platform docs.]
434 *
435 * Compatibility behavior:
436 * <ul>
437 * <li>API level 23 and above, this method matches platform behavior.
438 * <li>API level 18 through 22, this method ...
439 * <li>API level 17 and earlier, this method always returns false.
440 * </ul>
441 *
442 * @return [match platform docs], or platform-specific fallback behavior
443 */
444 public boolean isLteSupported() {
445 if (SDK_INT >= 23) {
446 return Api23Impl.isLteSupported(mWrapped);
447 } else if (SDK_INT >= 18) {
448 // Smart fallback behavior based on earlier APIs.
449 ...
450 }
451 // Default behavior.
452 return false;
453 }
454
455 // All references to class members -- including the constructor -- must be
456 // made on an inner class to avoid soft-verification errors that slow class
457 // loading and prevent optimization.
458 @RequiresApi(23)
459 private static class Api23Impl {
460 @NonNull
461 static ModemInfo create() {
462 return new ModemInfo();
463 }
464
465 static boolean isLteSupported(PlatformClass obj) {
466 return obj.isLteSupported();
467 }
468 }
469}
470```
471
472Note that libraries written in Java should express conversion to and from the
473platform class differently than Kotlin classes. For Java classes, conversion
474from the platform class to the wrapper should be expressed as a `static` method,
475while conversion from the wrapper to the platform class should be a method on
476the wrapper object:
477
478```java
479@NonNull
480public static ModemInfoCompat toModemInfoCompat(@NonNull ModemInfo info);
481
482@NonNull
483public ModemInfo toModemInfo();
484```
485
486In cases where the primary library is written in Java and has an accompanying
487`-ktx` Kotlin extensions library, the following conversion should be provided as
488an extension function:
489
490```kotlin
491fun ModemInfo.toModemInfoCompat() : ModemInfoCompat
492```
493
494Whereas in cases where the primary library is written in Kotlin, the conversion
495should be provided as an extension factory:
496
497```kotlin
498class ModemInfoCompat {
499 fun toModemInfo() : ModemInfo
500
501 companion object {
502 @JvmStatic
503 @JvmName("toModemInfoCompat")
504 fun ModemInfo.toModemInfoCompat() : ModemInfoCompat
505 }
506}
507```
508
509#### API guidelines {#wrapper-api-guidelines}
510
511##### Naming {#wrapper-naming}
512
513* Class name **must** be `<PlatformClass>Compat`
514* Package name **must** be `androidx.core.<platform.package>`
515* Superclass **must not** be `<PlatformClass>`
516
517##### Construction {#wrapper-construction}
518
519* Class _may_ have public constructor(s) to provide parity with public
520 `PlatformClass` constructors
521 * Constructor used to wrap `PlatformClass` **must not** be public
522* Class **must** implement a static `PlatformClassCompat
523 toPlatformClassCompat(PlatformClass)` method to wrap `PlatformClass` on
524 supported SDK levels
525 * If class does not exist at module's `minSdkVersion`, method must be
526 annotated with `@RequiresApi(<sdk>)` for SDK version where class was
527 introduced
528
529#### Implementation {#wrapper-implementation}
530
531* Class **must** implement a `PlatformClass toPlatformClass()` method to
532 unwrap `PlatformClass` on supported SDK levels
533 * If class does not exist at module's `minSdkVersion`, method must be
534 annotated with `@RequiresApi(<sdk>)` for SDK version where class was
535 introduced
536* Implementation _may_ delegate to `PlatformClass` methods when available (see
537 below note for caveats)
538* To avoid runtime class verification issues, all operations that interact
539 with the internal structure of `PlatformClass` must be implemented in inner
540 classes targeted to the SDK level at which the operation was added.
541 * See the [sample](#wrapper-sample) for an example of interacting with a
542 method that was added in SDK level 23.
543
544### 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}
545
546When to use?
547
548* Platform class may exist at module's `minSdkVersion`
549* Does not need to integrate with platform APIs
550* Does not need to coexist with platform class, ex. no potential `import`
551 collision due to both compatibility and platform classes being referenced
552 within the same source file
553
554Implementation requirements
555
556* Class name **must** be `<PlatformClass>`
557* Package name **must** be `androidx.<platform.package>`
558* Superclass **must not** be `<PlatformClass>`
559* Class **must not** expose `PlatformClass` in public API
AndroidX Core Teamee1457a2021-02-25 16:13:10 +0000560 * In exceptional cases, a _released_ standalone class may add conversion
561 between itself and the equivalent platform class; however, _new_ classes
562 that support conversion should follow the [Wrapper](#wrapper)
563 guidelines. In these cases, use a `toPlatform<PlatformClass>` and
564 `static toCompat<PlatformClass>` method naming convention.
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000565* Implementation _may_ delegate to `PlatformClass` methods when available
566
567### Standalone JAR library (no Android dependencies) {#standalone-jar-library-no-android-dependencies}
568
569When to use
570
571* General purpose library with minimal interaction with Android types
572 * or when abstraction around types can be used (e.g. Room's SQLite
573 wrapper)
574* Lib used in parts of app with minimal Android dependencies
575 * ex. Repository, ViewModel
576* When Android dependency can sit on top of common library
577* Clear separation between android dependent and independent parts of your
578 library
579* Clear that future integration with android dependencies can be layered
580 separately
581
582**Examples:**
583
584The **Paging Library** pages data from DataSources (such as DB content from Room
585or network content from Retrofit) into PagedLists, so they can be presented in a
586RecyclerView. Since the included Adapter receives a PagedList, and there are no
587other Android dependencies, Paging is split into two parts - a no-android
588library (paging-common) with the majority of the paging code, and an android
589library (paging-runtime) with just the code to present a PagedList in a
590RecyclerView Adapter. This way, tests of Repositories and their components can
591be tested in host-side tests.
592
593**Room** loads SQLite data on Android, but provides an abstraction for those
594that want to use a different SQL implementation on device. This abstraction, and
595the fact that Room generates code dynamically, means that Room interfaces can be
596used in host-side tests (though actual DB code should be tested on device, since
597DB impls may be significantly different on host).
598
599## Implementing compatibility {#compat}
600
601### Referencing new APIs {#compat-newapi}
602
603Generally, methods on extension library classes should be available to all
604devices above the library's `minSdkVersion`.
605
606#### Checking device SDK version {#compat-sdk}
607
608The most common way of delegating to platform or backport implementations is to
609compare the device's `Build.VERSION.SDK_INT` field to a known-good SDK version;
610for example, the SDK in which a method first appeared or in which a critical bug
611was first fixed.
612
613Non-reflective calls to new APIs gated on `SDK_INT` **must** be made from
614version-specific static inner classes to avoid verification errors that
615negatively affect run-time performance. For more information, see Chromium's
616guide to
617[Class Verification Failures](https://chromium.googlesource.com/chromium/src/+/HEAD/build/android/docs/class_verification_failures.md).
618
619Methods in implementation-specific classes **must** be paired with the
620`@DoNotInline` annotation to prevent them from being inlined.
621
622```java {.good}
623public static void saveAttributeDataForStyleable(@NonNull View view, ...) {
624 if (Build.VERSION.SDK_INT >= 29) {
625 Api29Impl.saveAttributeDataForStyleable(view, ...);
626 }
627}
628
629@RequiresApi(29)
630private static class Api29Impl {
631 @DoNotInline
632 static void saveAttributeDataForStyleable(@NonNull View view, ...) {
633 view.saveAttributeDataForStyleable(...);
634 }
635}
636```
637
638Alternatively, in Kotlin sources:
639
640```kotlin {.good}
641@RequiresApi(29)
AndroidX Core Team23c50442021-05-18 13:03:40 -0400642private object Api29Impl {
643 @JvmStatic
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000644 @DoNotInline
645 fun saveAttributeDataForStyleable(view: View, ...) { ... }
646}
647```
648
649When developing against pre-release SDKs where the `SDK_INT` has not been
650finalized, SDK checks **must** use `BuildCompat.isAtLeastX()` methods.
651
652```java {.good}
653@NonNull
654public static List<Window> getAllWindows() {
655 if (BuildCompat.isAtLeastR()) {
656 return ApiRImpl.getAllWindows();
657 }
658 return Collections.emptyList();
659}
660```
661
662#### Device-specific issues {#compat-oem}
663
664Library code may work around device- or manufacturer-specific issues -- issues
665not present in AOSP builds of Android -- *only* if a corresponding CTS test
666and/or CDD policy is added to the next revision of the Android platform. Doing
667so ensures that such issues can be detected and fixed by OEMs.
668
669#### Handling `minSdkVersion` disparity {#compat-minsdk}
670
671Methods that only need to be accessible on newer devices, including
672`to<PlatformClass>()` methods, may be annotated with `@RequiresApi(<sdk>)` to
673indicate they will fail to link on older SDKs. This annotation is enforced at
674build time by Lint.
675
676#### Handling `targetSdkVersion` behavior changes {#compat-targetsdk}
677
678To preserve application functionality, device behavior at a given API level may
679change based on an application's `targetSdkVersion`. For example, if an app with
680`targetSdkVersion` set to API level 22 runs on a device with API level 29, all
681required permissions will be granted at installation time and the run-time
682permissions framework will emulate earlier device behavior.
683
684Libraries do not have control over the app's `targetSdkVersion` and -- in rare
685cases -- may need to handle variations in platform behavior. Refer to the
686following pages for version-specific behavior changes:
687
688* API level 29:
689 [Android Q behavior changes: apps targeting Q](https://developer.android.com/preview/behavior-changes-q)
690* API level 28:
691 [Behavior changes: apps targeting API level 28+](https://developer.android.com/about/versions/pie/android-9.0-changes-28)
692* API level 26:
693 [Changes for apps targeting Android 8.0](https://developer.android.com/about/versions/oreo/android-8.0-changes#o-apps)
694* API level 24:
695 [Changes for apps targeting Android 7.0](https://developer.android.com/about/versions/nougat/android-7.0-changes#n-apps)
696* API level 21:
697 [Android 5.0 Behavior Changes](https://developer.android.com/about/versions/android-5.0-changes)
698* API level 19:
699 [Android 4.4 APIs](https://developer.android.com/about/versions/android-4.4)
700
701#### Working around Lint issues {#compat-lint}
702
703In rare cases, Lint may fail to interpret API usages and yield a `NewApi` error
704and require the use of `@TargetApi` or `@SuppressLint('NewApi')` annotations.
705Both of these annotations are strongly discouraged and may only be used
706temporarily. They **must never** be used in a stable release. Any usage of these
707annotation **must** be associated with an active bug, and the usage must be
708removed when the bug is resolved.
709
710### Delegating to API-specific implementations {#delegating-to-api-specific-implementations}
711
712#### SDK-dependent reflection
713
714Starting in API level 28, the platform restricts which
715[non-SDK interfaces](https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces)
716can be accessed via reflection by apps and libraries. As a general rule, you
717will **not** be able to use reflection to access hidden APIs on devices with
718`SDK_INT` greater than `Build.VERSION_CODES.P` (28).
719
720On earlier devices, reflection on hidden platform APIs is allowed **only** when
721an alternative public platform API exists in a later revision of the Android
722SDK. For example, the following implementation is allowed:
723
724```java
725public AccessibilityDelegate getAccessibilityDelegate(View v) {
726 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
727 // Retrieve the delegate using a public API.
728 return v.getAccessibilityDelegate();
729 } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
730 // Retrieve the delegate by reflecting on a private field. If the
731 // field does not exist or cannot be accessed, this will no-op.
732 if (sAccessibilityDelegateField == null) {
733 try {
734 sAccessibilityDelegateField = View.class
735 .getDeclaredField("mAccessibilityDelegate");
736 sAccessibilityDelegateField.setAccessible(true);
737 } catch (Throwable t) {
738 sAccessibilityDelegateCheckFailed = true;
739 return null;
740 }
741 }
742 try {
743 Object o = sAccessibilityDelegateField.get(v);
744 if (o instanceof View.AccessibilityDelegate) {
745 return (View.AccessibilityDelegate) o;
746 }
747 return null;
748 } catch (Throwable t) {
749 sAccessibilityDelegateCheckFailed = true;
750 return null;
751 }
752 } else {
753 // There is no way to retrieve the delegate, even via reflection.
754 return null;
755 }
756```
757
758Calls to public APIs added in pre-release revisions *must* be gated using
759`BuildCompat`:
760
761```java
762if (BuildCompat.isAtLeastQ()) {
763 // call new API added in Q
764} else if (Build.SDK_INT.VERSION >= Build.VERSION_CODES.SOME_RELEASE) {
765 // make a best-effort using APIs that we expect to be available
766} else {
767 // no-op or best-effort given no information
768}
769```
770
771### Inter-process communication {#inter-process-communication}
772
773Protocols and data structures used for IPC must support interoperability between
774different versions of libraries and should be treated similarly to public API.
775
776#### Data structures
777
778**Do not** use Parcelable for any class that may be used for IPC or otherwise
779exposed as public API. The data format used by Parcelable does not provide any
780compatibility guarantees and will result in crashes if fields are added or
781removed between library versions.
782
783**Do not** design your own serialization mechanism or wire format for disk
784storage or inter-process communication. Preserving and verifying compatibility
785is difficult and error-prone.
786
787If you expose a `Bundle` to callers that can cross processes, you should
788[prevent apps from adding their own custom parcelables](https://android.googlesource.com/platform/frameworks/base/+/6cddbe14e1ff67dc4691a013fe38a2eb0893fe03)
789as top-level entries; if *any* entry in a `Bundle` can't be loaded, even if it's
790not actually accessed, the receiving process is likely to crash.
791
792**Do** use protocol buffers or, in some simpler cases, `VersionedParcelable`.
793
794#### Communication protocols
795
796Any communication prototcol, handshake, etc. must maintain compatibility
797consistent with SemVer guidelines. Consider how your protocol will handle
798addition and removal of operations or constants, compatibility-breaking changes,
799and other modifications without crashing either the host or client process.
800
801## Deprecation and removal
802
803While SemVer's binary compatibility guarantees restrict the types of changes
804that may be made within a library revision and make it difficult to remove an
805API, there are many other ways to influence how developers interact with your
806library.
807
808### Deprecation (`@deprecated`)
809
810Deprecation lets a developer know that they should stop using an API or class.
811All deprecations must be marked with a `@Deprecated` Java annotation as well as
812a `@deprecated <migration-docs>` docs annotation explaining how the developer
813should migrate away from the API.
814
815Deprecation is an non-breaking API change that must occur in a **major** or
816**minor** release.
817
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +0000818APIs that are added during a pre-release cycle and marked as `@Deprecated`
819within the same cycle, e.g. added in `alpha01` and deprecated in `alpha06`,
820[must be removed](versioning.md#beta-checklist) before moving to `beta01`.
821
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000822### Soft removal (@removed)
823
824Soft removal preserves binary compatibility while preventing source code from
825compiling against an API. It is a *source-breaking change* and not recommended.
826
827Soft removals **must** do the following:
828
829* Mark the API as deprecated for at least one stable release prior to removal.
830* Mark the API with a `@RestrictTo(LIBRARY)` Java annotation as well as a
831 `@removed <reason>` docs annotation explaining why the API was removed.
832* Maintain binary compatibility, as the API may still be called by existing
833 dependent libraries.
834* Maintain behavioral compatibility and existing tests.
835
836This is a disruptive change and should be avoided when possible.
837
838Soft removal is a source-breaking API change that must occur in a **major** or
839**minor** release.
840
841### Hard removal
842
843Hard removal entails removing the entire implementation of an API that was
844exposed in a public release. Prior to removal, an API must be marked as
845`@deprecated` for a full **minor** version (`alpha`->`beta`->`rc`->stable),
846prior to being hard removed.
847
848This is a disruptive change and should be avoided when possible.
849
850Hard removal is a binary-breaking API change that must occur in a **major**
851release.
852
853### For entire artifacts
854
855We do not typically deprecate or remove entire artifacts; however, it may be
856useful in cases where we want to halt development and focus elsewhere or
857strongly discourage developers from using a library.
858
859Halting development, either because of staffing or prioritization issues, leaves
860the door open for future bug fixes or continued development. This quite simply
861means we stop releasing updates but retain the source in our tree.
862
863Deprecating an artifact provides developers with a migration path and strongly
864encourages them -- through Lint warnings -- to migrate elsewhere. This is
865accomplished by adding a `@Deprecated` and `@deprecated` (with migration
866comment) annotation pair to *every* class and interface in the artifact.
867
AndroidX Core Team95f812d2021-07-07 12:52:35 -0700868Entire packages (including Kotlin) can be deprecated by using a
869`package-info.java` file and applying the `@Deprecated` annotation there.
870
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000871The fully-deprecated artifact will be released as a deprecation release -- it
872will ship normally with accompanying release notes indicating the reason for
873deprecation and migration strategy, and it will be the last version of the
874artifact that ships. It will ship as a new minor stable release. For example, if
875`1.0.0` was the last stable release, then the deprecation release will be
876`1.1.0`. This is so Android Studio users will get a suggestion to update to a
877new stable version, which will contain the `@deprecated` annotations.
878
879After an artifact has been released as fully-deprecated, it can be removed from
880the source tree.
881
882## Resources {#resources}
883
884Generally, follow the official Android guidelines for
885[app resources](https://developer.android.com/guide/topics/resources/providing-resources).
886Special guidelines for library resources are noted below.
887
888### Defining new resources
889
890Libraries may define new value and attribute resources using the standard
891application directory structure used by Android Gradle Plugin:
892
893```
894src/main/res/
895 values/
896 attrs.xml Theme attributes and styleables
897 dimens.xml Dimensional values
898 public.xml Public resource definitions
899 ...
900```
901
902However, some libraries may still be using non-standard, legacy directory
903structures such as `res-public` for their public resource declarations or a
904top-level `res` directory and accompanying custom source set in `build.gradle`.
905These libraries will eventually be migrated to follow standard guidelines.
906
907#### Naming conventions
908
909Libraries follow the Android platform's resource naming conventions, which use
910`camelCase` for attributes and `underline_delimited` for values. For example,
911`R.attr.fontProviderPackage` and `R.dimen.material_blue_grey_900`.
912
913#### Attribute formats
914
915At build time, attribute definitions are pooled globally across all libraries
916used in an application, which means attribute `format`s *must* be identical for
917a given `name` to avoid a conflict.
918
919Within Jetpack, new attribute names *must* be globally unique. Libraries *may*
920reference existing public attributes from their dependencies. See below for more
921information on public attributes.
922
923When adding a new attribute, the format should be defined *once* in an `<attr
924/>` element in the definitions block at the top of `src/main/res/attrs.xml`.
925Subsequent references in `<declare-styleable>` elements *must* not include a
926`format`:
927
928`src/main/res/attrs.xml`
929
930```xml
931<resources>
932 <attr name="fontProviderPackage" format="string" />
933
934 <declare-styleable name="FontFamily">
935 <attr name="fontProviderPackage" />
936 </declare-styleable>
937</resources>
938```
939
940### Public resources
941
942Library resources are private by default, which means developers are discouraged
943from referencing any defined attributes or values from XML or code; however,
944library resources may be declared public to make them available to developers.
945
946Public library resources are considered API surface and are thus subject to the
947same API consistency and documentation requirements as Java APIs.
948
949Libraries will typically only expose theme attributes, ex. `<attr />` elements,
950as public API so that developers can set and retrieve the values stored in
951styles and themes. Exposing values -- such as `<dimen />` and `<string />` -- or
952images -- such as drawable XML and PNGs -- locks the current state of those
953elements as public API that cannot be changed without a major version bump. That
954means changing a publicly-visible icon would be considered a breaking change.
955
956#### Documentation
957
958All public resource definitions should be documented, including top-level
959definitions and re-uses inside `<styleable>` elements:
960
961`src/main/res/attrs.xml`
962
963```xml
964<resources>
965 <!-- String specifying the application package for a Font Provider. -->
966 <attr name="fontProviderPackage" format="string" />
967
968 <!-- Attributes that are read when parsing a <fontfamily> tag. -->
969 <declare-styleable name="FontFamily">
970 <!-- The package for the Font Provider to be used for the request. This is
971 used to verify the identity of the provider. -->
972 <attr name="fontProviderPackage" />
973 </declare-styleable>
974</resources>
975```
976
977`src/main/res/colors.xml`
978
979```xml
980<resources>
981 <!-- Color for Material Blue-Grey 900. -->
982 <color name="material_blue_grey_900">#ff263238</color>
983</resources>
984```
985
986#### Public declaration
987
988Resources are declared public by providing a separate `<public />` element with
989a matching type:
990
991`src/main/res/public.xml`
992
993```xml
994<resources>
995 <public name="fontProviderPackage" type="attr" />
996 <public name="material_blue_grey_900" type="color" />
997</resources>
998```
999
1000#### More information
1001
1002See also the official Android Gradle Plugin documentation for
1003[Private Resources](https://developer.android.com/studio/projects/android-library#PrivateResources).
1004
1005### Manifest entries (`AndroidManifest.xml`) {#resources-manifest}
1006
1007#### Metadata tags (`<meta-data>`) {#resources-manifest-metadata}
1008
1009Developers **must not** add `<application>`-level `<meta-data>` tags to library
1010manifests or advise developers to add such tags to their application manifests.
1011Doing so may _inadvertently cause denial-of-service attacks against other apps_.
1012
1013Assume a library adds a single item of meta-data at the application level. When
1014an app uses the library, that meta-data will be merged into the resulting app's
1015application entry via manifest merger.
1016
1017If another app attempts to obtain a list of all activities associated with the
1018primary app, that list will contain multiple copies of the `ApplicationInfo`,
1019each of which in turn contains a copy of the library's meta-data. As a result,
1020one `<metadata>` tag may become hundreds of KB on the binder call to obtain the
1021list -- resulting in apps hitting transaction too large exceptions and crashing.
1022
1023```xml {.bad}
1024<manifest xmlns:android="http://schemas.android.com/apk/res/android"
1025 package="androidx.librarypackage">
1026 <application>
1027 <meta-data
1028 android:name="keyName"
1029 android:value="@string/value" />
1030 </application>
1031</manifest>
1032```
1033
1034Instead, developers may consider adding `<metadata>` nested inside of
1035placeholder `<service>` tags.
1036
1037```xml {.good}
1038<manifest xmlns:android="http://schemas.android.com/apk/res/android"
1039 package="androidx.librarypackage">
1040 <application>
1041 <service
1042 android:name="androidx.librarypackage.MetadataHolderService"
1043 android:enabled="false"
1044 android:exported="false">
1045 <meta-data
1046 android:name="androidx.librarypackage.MetadataHolderService.KEY_NAME"
1047 android:resource="@string/value" />
1048 </service>
1049 </application>
1050```
1051
1052```java {.good}
1053package androidx.libraryname.featurename;
1054
1055/**
1056 * A placeholder service to avoid adding application-level metadata. The service
1057 * is only used to expose metadata defined in the library's manifest. It is
1058 * never invoked.
1059 */
1060public final class MetadataHolderService {
1061 private MetadataHolderService() {}
1062
1063 @Override
1064 public IBinder onBind(Intent intent) {
1065 throw new UnsupportedOperationException();
1066 }
1067}
1068```
1069
1070## Dependencies {#dependencies}
1071
alanv93da5db2021-08-11 13:05:51 -07001072Artifacts may depend on other artifacts within AndroidX as well as sanctioned
1073third-party libraries.
1074
1075### Versioned artifacts {#dependencies-versioned}
1076
1077One of the most difficult aspects of independently-versioned releases is
1078maintaining compatibility with public artifacts. In a mono repo such as Google's
1079repository or Android Git at master revision, it's easy for an artifact to
1080accidentally gain a dependency on a feature that may not be released on the same
1081schedule.
alanv11786ae2021-05-25 10:55:11 -07001082
1083- Project `project(":core:core")` uses the tip-of-tree sources for the
1084 `androidx.core:core` library and requires that they be loaded in the
1085 workspace.
1086- Playground `projectOrArtifact(":core:core")` is used for
1087 [Playground](playground.md) projects and will use tip-of-tree sources, if
1088 present in the workspace, or `SNAPSHOT` prebuilt artifacts from
1089 [androidx.dev](http://androidx.dev) otherwise.
1090- Explicit `"androidx.core:core:1.4.0"` uses the prebuilt AAR and requires
1091 that it be checked in to the `prebuilts/androidx/internal` local Maven
1092 repository.
1093
1094Libraries should prefer explicit dependencies with the lowest possible versions
1095that include the APIs or behaviors required by the library, using project or
1096Playground specs only in cases where tip-of-tree APIs or behaviors are required.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001097
alanv93da5db2021-08-11 13:05:51 -07001098#### Pre-release dependencies {#dependencies-pre-release}
1099
1100Pre-release suffixes **must** propagate up the dependency tree. For example, if
1101your artifact has API-type dependencies on pre-release artifacts, ex.
1102`1.1.0-alpha01`, then your artifact must also carry the `alpha` suffix. If you
1103only have implementation-type dependencies, your artifact may carry either the
1104`alpha` or `beta` suffix.
1105
1106Note: This does not apply to test dependencies: suffixes of test dependencies do
1107_not_ carry over to your artifact.
1108
1109#### Pinned versions {#dependencies-prebuilt}
1110
1111To avoid issues with dependency versioning, consider pinning your artifact's
1112dependencies to the oldest version (available via local `maven_repo` or Google
1113Maven) that satisfies the artifact's API requirements. This will ensure that the
1114artifact's release schedule is not accidentally tied to that of another artifact
1115and will allow developers to use older libraries if desired.
1116
1117```
1118dependencies {
1119 api("androidx.collection:collection:1.0.0")
1120 ...
1121}
1122```
1123
1124Artifacts should be built and tested against both pinned and tip-of-tree
1125versions of their dependencies to ensure behavioral compatibility.
1126
1127#### Tip-of-tree versions {#dependencies-project}
1128
1129Below is an example of a non-pinned dependency. It ties the artifact's release
1130schedule to that of the dependency artifact, because the dependency will need to
1131be released at the same time.
1132
1133```
1134dependencies {
1135 api(project(":collection"))
1136 ...
1137}
1138```
1139
1140### Non-public APIs {#dependencies-non-public-apis}
1141
1142Artifacts may depend on non-public (e.g. `@hide`) APIs exposed within their own
1143artifact or another artifact in the same `groupId`; however, cross-artifact
1144usages are subject to binary compatibility guarantees and
1145`@RestrictTo(Scope.LIBRARY_GROUP)` APIs must be tracked like public APIs.
1146
1147```
1148Dependency versioning policies are enforced at build time in the createArchive task. This task will ensure that pre-release version suffixes are propagated appropriately.
1149
1150Cross-artifact API usage policies are enforced by the checkApi and checkApiRelease tasks (see Life of a release).
1151```
1152
1153### Third-party libraries {#dependencies-3p}
1154
1155Artifacts may depend on libraries developed outside of AndroidX; however, they
1156must conform to the following guidelines:
1157
1158* Prebuilt **must** be checked into Android Git with both Maven and Make
1159 artifacts
1160 * `prebuilts/maven_repo` is recommended if this dependency is only
1161 intended for use with AndroidX artifacts, otherwise please use
1162 `external`
1163* Prebuilt directory **must** contains an `OWNERS` file identifying one or
1164 more individual owners (e.g. NOT a group alias)
1165* Library **must** be approved by legal
1166
1167Please see Jetpack's [open-source policy page](open_source.md) for more details
1168on using third-party libraries.
1169
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001170### System health {#dependencies-health}
1171
1172Libraries should consider the system health implications of their dependencies,
1173including:
1174
1175- Large dependencies where only a small portion is needed (e.g. APK bloat)
1176- Dependencies that slow down build times through annotation processing or
1177 compiler overhead
1178
1179#### Kotlin {#dependencies-kotlin}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001180
AndroidX Core Team43201242021-01-26 21:38:01 +00001181Kotlin is _strongly recommended_ for new libraries; however, it's important to
1182consider its size impact on clients. Currently, the Kotlin stdlib adds a minimum
1183of 40kB post-optimization. It may not make sense to use Kotlin for a library
1184that targets Java-only clients or space-constrained (ex. Android Go) clients.
1185
1186Existing Java-based libraries are _strongly discouraged_ from using Kotlin,
1187primarily because our documentation system does not currently provide a
1188Java-facing version of Kotlin API reference docs. Java-based libraries _may_
1189migrate to Kotlin, but they must consider the docs usability and size impacts on
1190existing Java-only and space-constrained clients.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001191
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001192#### Kotlin coroutines {#dependencies-coroutines}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001193
1194Kotlin's coroutine library adds around 100kB post-shrinking. New libraries that
1195are written in Kotlin should prefer coroutines over `ListenableFuture`, but
1196existing libraries must consider the size impact on their clients. See
1197[Asynchronous work with return values](#async-return) for more details on using
1198Kotlin coroutines in Jetpack libraries.
1199
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001200#### Guava {#dependencies-guava}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001201
1202The full Guava library is very large and *must not* be used. Libraries that
1203would like to depend on Guava's `ListenableFuture` may instead depend on the
1204standalone `com.google.guava:listenablefuture` artifact. See
1205[Asynchronous work with return values](#async-return) for more details on using
1206`ListenableFuture` in Jetpack libraries.
1207
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001208#### Java 8 {#dependencies-java8}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001209
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001210Libraries that take a dependency on a library targeting Java 8 must _also_
1211target Java 8, which will incur a ~5% build performance (as of 8/2019) hit for
AndroidX Core Team4074b462021-06-01 06:53:40 -07001212clients. New libraries targeting Java 8 may use Java 8 dependencies.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001213
1214The default language level for `androidx` libraries is Java 8, and we encourage
1215libraries to stay on Java 8. However, if you have a business need to target Java
12167, you can specify Java 7 in your `build.gradle` as follows:
1217
alanv93da5db2021-08-11 13:05:51 -07001218```groovy
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001219android {
1220 compileOptions {
1221 sourceCompatibility = JavaVersion.VERSION_1_7
1222 targetCompatibility = JavaVersion.VERSION_1_7
1223 }
1224}
1225```
1226
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001227### Open-source compatibility {#dependencies-aosp}
1228
1229[Jetpack Principles](principles.md) require that libraries consider the
1230open-source compatibility implications of their dependencies, including:
1231
1232- Closed-source or proprietary libraries or services that may not be available
1233 on AOSP devices
1234- Dependencies that may prevent developers from effectively isolating their
1235 tests from third-party libraries or services
1236
1237Primary artifacts, e.g. `workmanager`, **must not** depend on closed-source
1238components including libraries and hard-coded references to packages,
1239permissions, or IPC mechanisms that may only be fulfulled by closed-source
1240components.
1241
1242Optional artifacts, e.g. `workmanager-gcm`, _may_ depend on closed-source
1243components or configure a primary artifact to be backed by a closed-source
1244component via service discovery or initialization.
1245
1246Some examples of safely depending on closed-source components include:
1247
1248- WorkManager's GCM Network Manager integration, which uses manifest metadata
1249 for service discovery and provides an optional artifact exposing the
1250 service.
1251- Ads Identifier's Play Services integration, which provides a default backend
1252 and uses `Intent` handling as a service discovery mechanism for Play
1253 Services.
1254- Downloadable Fonts integration with Play Services, which plugs in via a
1255 `ContentProvider` as a service discovery mechanism with developer-specified
1256 signature verification for additional security.
1257
1258Note that in all cases, the developer is not _required_ to use GCM or Play
1259Services and may instead use another compatible service implementing the same
1260publicly-defined protocols.
1261
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001262## More API guidelines {#more-api-guidelines}
1263
1264### Annotations {#annotation}
1265
1266#### Annotation processors {#annotation-processor}
1267
1268Annotation processors should opt-in to incremental annotation processing to
1269avoid triggering a full recompilation on every client source code change. See
1270Gradle's
1271[Incremental annotation processing](https://docs.gradle.org/current/userguide/java_plugin.html#sec:incremental_annotation_processing)
1272documentation for information on how to opt-in.
1273
alanvf5ca4b92021-02-10 13:07:47 -08001274### Experimental `@RequiresOptIn` APIs {#experimental-api}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001275
1276Jetpack libraries may choose to annotate API surfaces as unstable using either
1277Kotlin's
alanvf5ca4b92021-02-10 13:07:47 -08001278[`@RequiresOptIn` annotation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-requires-opt-in/)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001279for APIs written in Kotlin or Jetpack's
alanvf5ca4b92021-02-10 13:07:47 -08001280[`@RequiresOptIn` annotation](https://developer.android.com/reference/kotlin/androidx/annotation/RequiresOptIn)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001281for APIs written in Java.
1282
1283In both cases, API surfaces marked as experimental are considered alpha and will
1284be excluded from API compatibility guarantees. Due to the lack of compatibility
alanvf5ca4b92021-02-10 13:07:47 -08001285guarantees, stable libraries *must never* call experimental APIs exposed by
1286other libraries outside of their
1287[same-version group](#same-version-atomic-groups) and *may not* use the `@OptIn`
1288annotation except in the following cases:
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001289
1290* A library within a same-version group *may* call an experimental API exposed
1291 by another library **within its same-version group**. In this case, API
1292 compatibility guarantees are covered under the same-version group policies
alanvf5ca4b92021-02-10 13:07:47 -08001293 and the library *may* use the `@OptIn` annotation to prevent propagation of
1294 the experimental property. **Library owners must exercise care to ensure
1295 that post-alpha APIs backed by experimental APIs actually meet the release
1296 criteria for post-alpha APIs.**
1297* An `alpha` library may use experimental APIs from outside its same-version
1298 group. These usages must be removed when the library moves to `beta`.
1299
1300NOTE JetBrains's own usage of `@RequiresOptIn` in Kotlin language libraries
1301varies and may indicate binary instability, functional instability, or simply
1302that an API is really difficult to use. Jetpack libraries should treat instances
1303of `@RequiresOptIn` in JetBrains libraries as indicating **binary instability**
1304and avoid using them outside of `alpha`; however, teams are welcome to obtain
1305written assurance from JetBrains regarding binary stability of specific APIs.
1306`@RequiresOptIn` APIs that are guaranteed to remain binary compatible _may_ be
1307used in `beta`, but usages must be removed when the library moves to `rc`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001308
1309#### How to mark an API surface as experimental
1310
alanvf5ca4b92021-02-10 13:07:47 -08001311All libraries using `@RequiresOptIn` annotations *must* depend on the
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001312`androidx.annotation:annotation-experimental` artifact regardless of whether
1313they are using the `androidx` or Kotlin annotation. This artifact provides Lint
1314enforcement of experimental usage restrictions for Kotlin callers as well as
1315Java (which the Kotlin annotation doesn't handle on its own, since it's a Kotlin
1316compiler feature). Libraries *may* include the dependency as `api`-type to make
alanvf5ca4b92021-02-10 13:07:47 -08001317`@OptIn` available to Java clients; however, this will also unnecessarily expose
1318the `@RequiresOptIn` annotation.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001319
1320```java
1321dependencies {
1322 implementation(project(":annotation:annotation-experimental"))
1323}
1324```
1325
1326See Kotlin's
alanvf5ca4b92021-02-10 13:07:47 -08001327[opt-in requirements documentation](https://kotlinlang.org/docs/reference/opt-in-requirements.html)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001328for general usage information. If you are writing experimental Java APIs, you
1329will use the Jetpack
alanvf5ca4b92021-02-10 13:07:47 -08001330[`@RequiresOptIn` annotation](https://developer.android.com/reference/kotlin/androidx/annotation/RequiresOptIn)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001331rather than the Kotlin compiler's annotation.
1332
1333#### How to transition an API out of experimental
1334
1335When an API surface is ready to transition out of experimental, the annotation
1336may only be removed during an alpha pre-release stage since removing the
1337experimental marker from an API is equivalent to adding the API to the current
1338API surface.
1339
1340When transitioning an entire feature surface out of experimental, you *should*
1341remove the associated annotations.
1342
1343When making any change to the experimental API surface, you *must* run
1344`./gradlew updateApi` prior to uploading your change.
1345
1346### Restricted APIs {#restricted-api}
1347
1348Jetpack's library tooling supports hiding Java-visible (ex. `public` and
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001349`protected`) APIs from developers using a combination of the `@RestrictTo`
1350source annotation, and the `@hide` docs annotation (`@suppress` in Kotlin).
1351These annotations **must** be paired together when used, and are validated as
1352part of presubmit checks for Java code (Kotlin not yet supported by Checkstyle).
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001353
1354The effects of hiding an API are as follows:
1355
1356* The API will not appear in documentation
1357* Android Studio will warn the developer not to use the API
1358
1359Hiding an API does *not* provide strong guarantees about usage:
1360
1361* There are no runtime restrictions on calling hidden APIs
1362* Android Studio will not warn if hidden APIs are called using reflection
1363* Hidden APIs will still show in Android Studio's auto-complete
1364
1365#### When to use `@hide` {#restricted-api-usage}
1366
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001367In other cases, avoid using `@hide` / `@suppress`. These annotations indicates
1368that developers should not call an API that is _technically_ public from a Java
1369visibility perspective. Hiding APIs is often a sign of a poorly-abstracted API
1370surface, and priority should be given to creating public, maintainable APIs and
1371using Java visibility modifiers.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001372
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001373*Do not* use `@hide`/`@suppress` to bypass API tracking and review for
1374production APIs; instead, rely on API+1 and API Council review to ensure APIs
1375are reviewed on a timely basis.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001376
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001377*Do not* use `@hide`/`@suppress` for implementation detail APIs that are used
1378between libraries and could reasonably be made public.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001379
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001380*Do* use `@hide`/`@suppress` paired with `@RestrictTo(LIBRARY)` for
1381implementation detail APIs used within a single library (but prefer Java
1382language `private` or `default` visibility).
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001383
1384#### `RestrictTo.Scope` and inter- versus intra-library API surfaces {#private-api-types}
1385
1386To maintain binary compatibility between different versions of libraries,
1387restricted API surfaces that are used between libraries (inter-library APIs)
1388must follow the same Semantic Versioning rules as public APIs. Inter-library
1389APIs should be annotated with the `@RestrictTo(LIBRARY_GROUP)` source
1390annotation.
1391
1392Restricted API surfaces used within a single library (intra-library APIs), on
1393the other hand, may be added or removed without any compatibility
1394considerations. It is safe to assume that developers _never_ call these APIs,
1395even though it is technically feasible. Intra-library APIs should be annotated
1396with the `@RestrictTo(LIBRARY)` source annotation.
1397
1398The following table shows the visibility of a hypothetical API within Maven
1399coordinate `androidx.concurrent:concurrent` when annotated with a variety of
1400scopes:
1401
1402<table>
1403 <tr>
1404 <td><code>RestrictTo.Scope</code></td>
1405 <td>Visibility by Maven coordinate</td>
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001406 <td>Versioning</td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001407 </tr>
1408 <tr>
1409 <td><code>LIBRARY</code></td>
1410 <td><code>androidx.concurrent:concurrent</code></td>
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001411 <td>No compatibility gurantees (same as private)</td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001412 </tr>
1413 <tr>
1414 <td><code>LIBRARY_GROUP</code></td>
1415 <td><code>androidx.concurrent:*</code></td>
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001416 <td>Semantic versioning (including deprecation)</td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001417 </tr>
1418 <tr>
1419 <td><code>LIBRARY_GROUP_PREFIX</code></td>
1420 <td><code>androidx.*:*</code></td>
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001421 <td>Semantic versioning (including deprecation)</td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001422 </tr>
1423</table>
1424
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001425#### `@IntDef` `@StringDef` and `@LongDef` and visibility
1426
1427All `@IntDef`, `@StringDef`, and `@LongDef` will be stripped from resulting
1428artifacts to avoid issues where compiler inlining constants removes information
1429as to which `@IntDef` defined the value of `1`. The annotations are extracted
1430and packaged separately to be read by Android Studio and lint which enforces the
1431types in application code.
1432
1433* Libraries _must_ `@hide` all `@IntDef`, `@StringDef`, and `@LongDef`
1434 declarations.
1435* Libraries _must_ expose constants used to define the `@IntDef` etc at the
1436 same Java visibility as the hidden `@IntDef`
1437* Libraries _should_ also use @RestrictTo to create a warning when the type
1438 used incorrectly.
1439
1440Here is a complete example of an `@IntDef`
1441
1442```java
1443// constants match Java visibility of ExifStreamType
1444// code outside this module interacting with ExifStreamType uses these constants
1445public static final int STREAM_TYPE_FULL_IMAGE_DATA = 1;
1446public static final int STREAM_TYPE_EXIF_DATA_ONLY = 2;
1447
1448/** @hide */
1449@RestrictTo(RestrictTo.Scope.LIBRARY) // Don't export ExifStreamType outside module
1450@Retention(RetentionPolicy.SOURCE)
1451@IntDef({
1452 STREAM_TYPE_FULL_IMAGE_DATA,
1453 STREAM_TYPE_EXIF_DATA_ONLY,
1454})
1455public @interface ExifStreamType {}
1456```
1457
1458Java visibilty should be set as appropriate for the code in question (`private`,
1459`package` or `public`) and is unrelated to hiding.
1460
1461For more, read the section in
1462[Android API Council Guidelines](https://android.googlesource.com/platform/developers/docs/+/refs/heads/master/api-guidelines/index.md#no-public-typedefs)
1463
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001464### Constructors {#constructors}
1465
1466#### View constructors {#view-constructors}
1467
1468The four-arg View constructor -- `View(Context, AttributeSet, int, int)` -- was
1469added in SDK 21 and allows a developer to pass in an explicit default style
1470resource rather than relying on a theme attribute to resolve the default style
1471resource. Because this API was added in SDK 21, care must be taken to ensure
1472that it is not called through any < SDK 21 code path.
1473
1474Views _may_ implement a four-arg constructor in one of the following ways:
1475
14761. Do not implement.
14771. Implement and annotate with `@RequiresApi(21)`. This means the three-arg
1478 constructor **must not** call into the four-arg constructor.
1479
1480### Asynchronous work {#async}
1481
1482#### With return values {#async-return}
1483
1484Traditionally, asynchronous work on Android that results in an output value
1485would use a callback; however, better alternatives exist for libraries.
1486
1487Kotlin libraries should prefer
1488[coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) and
1489`suspend` functions, but please refer to the guidance on
1490[allowable dependencies](#dependencies-coroutines) before adding a new
1491dependency on coroutines.
1492
1493Java libraries should prefer `ListenableFuture` and the
1494[`CallbackToFutureAdapter`](https://developer.android.com/reference/androidx/concurrent/futures/CallbackToFutureAdapter)
1495implementation provided by the `androidx.concurrent:concurrent-futures` library.
1496
1497Libraries **must not** use `java.util.concurrent.CompletableFuture`, as it has a
1498large API surface that permits arbitrary mutation of the future's value and has
1499error-prone defaults.
1500
1501See the [Dependencies](#dependencies) section for more information on using
1502Kotlin coroutines and Guava in your library.
1503
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001504#### Cancellation
1505
1506Libraries that expose APIs for performing asynchronous work should support
1507cancellation. There are _very few_ cases where it is not feasible to support
1508cancellation.
1509
1510Libraries that use `ListenableFuture` must be careful to follow the exact
1511specification of
1512[`Future.cancel(boolean mayInterruptIfRunning)`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html?is-external=true#cancel-boolean-)
1513behavior.
1514
1515```java {.bad}
1516@Override
1517public boolean cancel(boolean mayInterruptIfRunning) {
1518 // Does not support cancellation.
1519 return false;
1520}
1521```
1522
1523```java {.bad}
1524@Override
1525public boolean cancel(boolean mayInterruptIfRunning) {
1526 // Aggressively does not support cancellation.
1527 throw new UnsupportedOperationException();
1528}
1529```
1530
1531```java {.good}
1532@Override
1533public boolean cancel(boolean mayInterruptIfRunning) {
1534 // Pseudocode that ignores threading but follows the spec.
1535 if (mCompleted
1536 || mCancelled
1537 || mRunning && !mayInterruptIfRunning) {
1538 return false;
1539 }
1540 mCancelled = true;
1541 return true;
1542}
1543```
1544
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001545#### Avoid `synchronized` methods
1546
1547Whenever multiple threads are interacting with shared (mutable) references those
1548reads and writes must be synchronized in some way. However synchronized blocks
1549make your code thread-safe at the expense of concurrent execution. Any time
1550execution enters a synchronized block or method any other thread trying to enter
1551a synchronized block on the same object has to wait; even if in practice the
1552operations are unrelated (e.g. they interact with different fields). This can
1553dramatically reduce the benefit of trying to write multi-threaded code in the
1554first place.
1555
1556Locking with synchronized is a heavyweight form of ensuring ordering between
1557threads, and there are a number of common APIs and patterns that you can use
1558that are more lightweight, depending on your use case:
1559
1560* Compute a value once and make it available to all threads
1561* Update Set and Map data structures across threads
1562* Allow a group of threads to process a stream of data concurrently
1563* Provide instances of a non-thread-safe type to multiple threads
1564* Update a value from multiple threads atomically
1565* Maintain granular control of your concurrency invariants
1566
1567### Kotlin {#kotlin}
1568
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001569#### Nullability from Java (new APIs)
1570
1571All new Java APIs should be annotated either `@Nullable` or `@NonNull` for all
1572reference parameters and reference return types.
1573
1574```java
1575 @Nullable
1576 public Object someNewApi(@NonNull Thing arg1, @Nullable List<WhatsIt> arg2) {
1577 if(/** something **/) {
1578 return someObject;
1579 } else {
1580 return null;
1581 }
1582```
1583
1584#### Nullability from Java (existing APIs)
1585
1586Adding `@Nullable` or `@NonNull` annotations to existing APIs to document their
1587existing nullability is OK. This is a source breaking change for Kotlin
1588consumers, and you should ensure that it's noted in the release notes and try to
1589minimize the frequency of these updates in releases.
1590
1591Changing the nullability of an API is a breaking change.
1592
1593#### Extending APIs that expose types without nullability annotations
1594
1595[Platform types](https://kotlinlang.org/docs/java-interop.html#null-safety-and-platform-types)
1596are exposed by Java types that do not have a `@Nullable` or `@NonNull`
1597annotation. In Kotlin they are indicated with the `!` suffix.
1598
1599When interacting with an Android platform API that exposes APIs with unknown
1600nullability follow these rules:
1601
16021. If wrapping the type in a new API, define and handle `@Nullable` or
1603 `@NonNull` in the library. Treat types with unknown nullability passed into
1604 or return from Android as `@Nullable` in the library.
16052. If extending an existing API (e.g. `@Override`), pass through the existing
1606 types with unknown nullability and annotate each with
1607 `@SuppressLint("UnknownNullness")`
1608
1609In Kotlin, a type with unknown nullability is exposed as a "platform type"
1610(indicated with a `!` suffix) which has unknown nullability in the type checker,
1611and may bypass type checking leading to runtime errors. When possible, do not
1612directly expose types with unknown nullability in new public APIs.
1613
1614#### Extending `@RecentlyNonNull` and `@RecentlyNullable` APIs
1615
1616Platform APIs are annotated in the platform SDK artifacts with fake annotations
1617`@RecentlyNonNull` and `@RecentlyNullable` to avoid breaking builds when we
1618annotated platform APIs with nullability. These annotations cause warnings
1619instead of build failures. The `RecentlyNonNull` and `RecentlyNullable`
1620annotations are added by Metalava and do not appear in platform code.
1621
1622When extending an API that is annotated `@RecentlyNonNull`, you should annotate
1623the override with `@NonNull`, and the same for `@RecentlyNullable` and
1624`@Nullable`.
1625
1626For example `SpannableStringBuilder.append` is annotated `RecentlyNonNull` and
1627an override should look like:
1628
1629```java
1630 @NonNull
1631 @Override
1632 public SpannableStringBuilder append(@SuppressLint("UnknownNullness") CharSequence text) {
1633 super.append(text);
1634 return this;
1635 }
1636```
1637
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001638#### Data classes {#kotlin-data}
1639
1640Kotlin `data` classes provide a convenient way to define simple container
1641objects, where Kotlin will generate `equals()` and `hashCode()` for you.
1642However, they are not designed to preserve API/binary compatibility when members
1643are added. This is due to other methods which are generated for you -
1644[destructuring declarations](https://kotlinlang.org/docs/reference/multi-declarations.html),
1645and [copying](https://kotlinlang.org/docs/reference/data-classes.html#copying).
1646
1647Example data class as tracked by metalava:
1648
1649<pre>
1650 public final class TargetAnimation {
1651 ctor public TargetAnimation(float target, androidx.animation.AnimationBuilder animation);
1652 <b>method public float component1();</b>
1653 <b>method public androidx.animation.AnimationBuilder component2();</b>
1654 <b>method public androidx.animation.TargetAnimation copy(float target, androidx.animation.AnimationBuilder animation);</b>
1655 method public androidx.animation.AnimationBuilder getAnimation();
1656 method public float getTarget();
1657 }
1658</pre>
1659
1660Because members are exposed as numbered components for destructuring, you can
1661only safely add members at the end of the member list. As `copy` is generated
1662with every member name in order as well, you'll also have to manually
1663re-implement any old `copy` variants as items are added. If these constraints
1664are acceptable, data classes may still be useful to you.
1665
1666As a result, Kotlin `data` classes are _strongly discouraged_ in library APIs.
1667Instead, follow best-practices for Java data classes including implementing
1668`equals`, `hashCode`, and `toString`.
1669
1670See Jake Wharton's article on
1671[Public API challenges in Kotlin](https://jakewharton.com/public-api-challenges-in-kotlin/)
1672for more details.
1673
AndroidX Core Team6fd727f2021-06-01 12:26:34 -07001674#### Exhaustive `when` and `sealed class`/`enum class` {#exhaustive-when}
1675
1676A key feature of Kotlin's `sealed class` and `enum class` declarations is that
1677they permit the use of **exhaustive `when` expressions.** For example:
1678
1679```kotlin
1680enum class CommandResult { Permitted, DeniedByUser }
1681
1682val message = when (commandResult) {
1683 Permitted -> "the operation was permitted"
1684 DeniedByUser -> "the user said no"
1685}
1686
1687println(message)
1688```
1689
1690This highlights challenges for library API design and compatibility. Consider
1691the following addition to the `CommandResult` possibilities:
1692
1693```kotlin {.bad}
1694enum class CommandResult {
1695 Permitted,
1696 DeniedByUser,
1697 DeniedByAdmin // New in androidx.mylibrary:1.1.0!
1698}
1699```
1700
1701This change is both **source and binary breaking.**
1702
1703It is **source breaking** because the author of the `when` block above will see
1704a compiler error about not handling the new result value.
1705
1706It is **binary breaking** because if the `when` block above was compiled as part
1707of a library `com.example.library:1.0.0` that transitively depends on
1708`androidx.mylibrary:1.0.0`, and an app declares the dependencies:
1709
1710```kotlin
1711implementation("com.example.library:1.0.0")
1712implementation("androidx.mylibrary:1.1.0") // Updated!
1713```
1714
1715`com.example.library:1.0.0` does not handle the new result value, leading to a
1716runtime exception.
1717
1718**Note:** The above example is one where Kotlin's `enum class` is the correct
1719tool and the library should **not** add a new constant! Kotlin turns this
1720semantic API design problem into a compiler or runtime error. This type of
1721library API change could silently cause app logic errors or data corruption
1722without the protection provided by exhaustive `when`. See
1723[When to use exhaustive types](#when-to-use-exhaustive-types).
1724
1725`sealed class` exhibits the same characteristic; adding a new subtype of an
1726existing sealed class is a breaking change for the following code:
1727
1728```kotlin
1729val message = when (command) {
1730 is Command.Migrate -> "migrating to ${command.destination}"
1731 is Command.Quack -> "quack!"
1732}
1733```
1734
1735##### Non-exhaustive alternatives to `enum class`
1736
1737Kotlin's `@JvmInline value class` with a `private constructor` can be used to
1738create type-safe sets of non-exhaustive constants as of Kotlin 1.5. Compose's
1739`BlendMode` uses the following pattern:
1740
1741```kotlin {.good}
1742@JvmInline
1743value class BlendMode private constructor(val value: Int) {
1744 companion object {
1745 /** Drop both the source and destination images, leaving nothing. */
1746 val Clear = BlendMode(0)
1747 /** Drop the destination image, only paint the source image. */
1748 val Src = BlendMode(1)
1749 // ...
1750 }
1751}
1752```
1753
1754**Note:** This recommendation may be temporary. Kotlin may add new annotations
1755or other language features to declare non-exhaustive enum classes in the future.
1756
1757Alternatively, the existing `@IntDef` mechanism used in Java-language androidx
1758libraries may also be used, but type checking of constants will only be
1759performed by lint, and functions overloaded with parameters of different value
1760class types are not supported. Prefer the `@JvmInline value class` solution for
1761new code unless it would break local consistency with other API in the same
1762module that already uses `@IntDef`.
1763
1764##### Non-exhaustive alternatives to `sealed class`
1765
1766Abstract classes with constructors marked as `internal` or `private` can
1767represent the same subclassing restrictions of sealed classes as seen from
1768outside of a library module's own codebase:
1769
1770```kotlin
1771abstract class Command private constructor() {
1772 class Migrate(val destination: String) : Command()
1773 object Quack : Command()
1774}
1775```
1776
1777Using an `internal` constructor will permit non-nested subclasses, but will
1778**not** restrict subclasses to the same package within the module, as sealed
1779classes do.
1780
1781##### When to use exhaustive types
1782
1783Use `enum class` or `sealed class` when the values or subtypes are intended to
1784be exhaustive by design from the API's initial release. Use non-exhaustive
1785alternatives when the set of constants or subtypes might expand in a minor
1786version release.
1787
1788Consider using an **exhaustive** (`enum class` or `sealed class`) type
1789declaration if:
1790
1791* The developer is expected to **accept** values of the type
1792* The developer is expected to **act** on **any and all** values received
1793
1794Consider using a **non-exhaustive** type declaration if:
1795
1796* The developer is expected to **provide** values of the type to APIs exposed
1797 by the same module **only**
1798* The developer is expected to **ignore** unknown values received
1799
1800The `CommandResult` example above is a good example of a type that **should**
1801use the exhaustive `enum class`; `CommandResult`s are **returned** to the
1802developer and the developer cannot implement correct app behavior by ignoring
1803unrecognized result values. Adding a new result value would semantically break
1804existing code regardless of the language facility used to express the type.
1805
1806```kotlin {.good}
1807enum class CommandResult { Permitted, DeniedByUser, DeniedByAdmin }
1808```
1809
1810Compose's `BlendMode` is a good example of a type that **should not** use the
1811exhaustive `enum class`; blending modes are used as arguments to Compose
1812graphics APIs and are not intended for interpretation by app code. Additionally,
1813there is historical precedent from `android.graphics` for new blending modes to
1814be added in the future.
1815
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001816#### Extension and top-level functions {#kotlin-extension-functions}
1817
AndroidX Core Team6fd727f2021-06-01 12:26:34 -07001818If your Kotlin file contains any symbols outside of class-like types
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001819(extension/top-level functions, properties, etc), the file must be annotated
1820with `@JvmName`. This ensures unanticipated use-cases from Java callers don't
1821get stuck using `BlahKt` files.
1822
1823Example:
1824
1825```kotlin {.bad}
1826package androidx.example
1827
1828fun String.foo() = // ...
1829```
1830
1831```kotlin {.good}
1832@file:JvmName("StringUtils")
1833
1834package androidx.example
1835
1836fun String.foo() = // ...
1837```
1838
1839NOTE This guideline may be ignored for libraries that only work in Kotlin (think
1840Compose).
1841
1842## Testing Guidelines
1843
1844### [Do not Mock, AndroidX](do_not_mock.md)
1845
1846## Android Lint Guidelines
1847
1848### Suppression vs Baselines
1849
1850Lint sometimes flags false positives, even though it is safe to ignore these
1851errors (for example WeakerAccess warnings when you are avoiding synthetic
1852access). There may also be lint failures when your library is in the middle of a
1853beta / rc / stable release, and cannot make the breaking changes needed to fix
1854the root cause. There are two ways of ignoring lint errors:
1855
18561. Suppression - using `@SuppressLint` (for Java) or `@Suppress` annotations to
1857 ignore the warning per call site, per method, or per file. *Note
1858 `@SuppressLint` - Requires Android dependency*.
18592. Baselines - allowlisting errors in a lint-baseline.xml file at the root of
1860 the project directory.
1861
1862Where possible, you should use a **suppression annotation at the call site**.
1863This helps ensure that you are only suppressing the *exact* failure, and this
1864also keeps the failure visible so it can be fixed later on. Only use a baseline
1865if you are in a Java library without Android dependencies, or when enabling a
1866new lint check, and it is prohibitively expensive / not possible to fix the
1867errors generated by enabling this lint check.
1868
alanv48b28b12021-08-13 08:23:42 -07001869To update a lint baseline (`lint-baseline.xml`) after you have fixed issues,
1870first **manually delete the `lint-baseline.xml` file** for your project and then
1871run the `lintDebug` task for your project with the argument
1872`-PupdateLintBaseline`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001873
1874```shell
alanv48b28b12021-08-13 08:23:42 -07001875rm core/core/lint-baseline.xml
1876./gradlew :core:core:lintDebug -PupdateLintBaseline
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001877```
1878
1879## Metalava API Lint
1880
1881As well as Android Lint, which runs on all source code, Metalava will also run
1882checks on the public API surface of each library. Similar to with Android Lint,
1883there can sometimes be false positives / intended deviations from the API
1884guidelines that Metalava will lint your API surface against. When this happens,
1885you can suppress Metalava API lint issues using `@SuppressLint` (for Java) or
1886`@Suppress` annotations. In cases where it is not possible, update Metalava's
1887baseline with the `updateApiLintBaseline` task.
1888
1889```shell
1890./gradlew core:updateApiLintBaseline
1891```
1892
1893This will create/amend the `api_lint.ignore` file that lives in a library's
1894`api` directory.
1895
1896## Build Output Guidelines
1897
1898In order to more easily identify the root cause of build failures, we want to
1899keep the amount of output generated by a successful build to a minimum.
1900Consequently, we track build output similarly to the way in which we track Lint
1901warnings.
1902
1903### Invoking build output validation
1904
1905You can add `-Pandroidx.validateNoUnrecognizedMessages` to any other AndroidX
1906gradlew command to enable validation of build output. For example:
1907
1908```shell
1909/gradlew -Pandroidx.validateNoUnrecognizedMessages :help
1910```
1911
1912### Exempting new build output messages
1913
1914Please avoid exempting new build output and instead fix or suppress the warnings
1915themselves, because that will take effect not only on the build server but also
1916in Android Studio, and will also run more quickly.
1917
1918If you cannot prevent the message from being generating and must exempt the
1919message anyway, follow the instructions in the error:
1920
1921```shell
1922$ ./gradlew -Pandroidx.validateNoUnrecognizedMessages :help
1923
1924Error: build_log_simplifier.py found 15 new messages found in /usr/local/google/workspace/aosp-androidx-git/out/dist/gradle.log.
1925
1926Please fix or suppress these new messages in the tool that generates them.
1927If you cannot, then you can exempt them by doing:
1928
1929 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
1930 2. modify the new lines to be appropriately generalized
1931```
1932
1933Each line in this exemptions file is a regular expressing matching one or more
1934lines of output to be exempted. You may want to make these expressions as
1935specific as possible to ensure that the addition of new, similar messages will
1936also be detected (for example, discovering an existing warning in a new source
1937file).
1938
1939## Behavior changes
1940
1941### Changes that affect API documentation
1942
1943Do not make behavior changes that require altering API documentation in a way
1944that would break existing clients, even if such changes are technically binary
1945compatible. For example, changing the meaning of a method's return value to
1946return true rather than false in a given state would be considered a breaking
1947change. Because this change is binary-compatible, it will not be caught by
1948tooling and is effectively invisible to clients.
1949
1950Instead, add new methods and deprecate the existing ones if necessary, noting
1951behavior changes in the deprecation message.
1952
1953### High-risk behavior changes
1954
1955Behavior changes that conform to documented API contracts but are highly complex
1956and difficult to comprehensively test are considered high-risk and should be
1957implemented using behavior flags. These changes may be flagged on initially, but
1958the original behaviors must be preserved until the library enters release
1959candidate stage and the behavior changes have been appropriately verified by
1960integration testing against public pre-release
1961revisions.
1962
1963It may be necessary to soft-revert a high-risk behavior change with only 24-hour
1964notice, which should be achievable by flipping the behavior flag to off.
1965
1966```java
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001967// Flag for whether to throw exceptions when the state is known to be bad. This
1968// is expected to be a high-risk change since apps may be working fine even with
1969// a bad state, so we may need to disable this as a hotfix.
1970private static final boolean FLAG_EXCEPTION_ON_BAD_STATE = false;
1971```
1972
1973```java
1974/**
1975 * Allows a developer to toggle throwing exceptions when the state is known to
1976 * be bad. This method is intended to give developers time to update their code.
1977 * It is temporary and will be removed in a future release.
1978 */
1979@TemporaryFeatureFlag
1980public void setExceptionOnBadStateEnabled(boolean enabled);
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001981```
1982
1983Avoid adding multiple high-risk changes during a feature cycle, as verifying the
1984interaction of multiple feature flags leads to unnecessary complexity and
1985exposes clients to high risk even when a single change is flagged off. Instead,
1986wait until one high-risk change has landed in RC before moving on to the next.
1987
1988#### Testing
1989
1990Relevant tests should be run for the behavior change in both the on and off
1991flagged states to prevent regressions.
1992
1993## Sample code in Kotlin modules
1994
1995### Background
1996
1997Public API can (and should!) have small corresponding code snippets that
1998demonstrate functionality and usage of a particular API. These are often exposed
1999inline in the documentation for the function / class - this causes consistency
2000and correctness issues as this code is not compiled against, and the underlying
2001implementation can easily change.
2002
2003KDoc (JavaDoc for Kotlin) supports a `@sample` tag, which allows referencing the
2004body of a function from documentation. This means that code samples can be just
2005written as a normal function, compiled and linted against, and reused from other
2006modules such as tests! This allows for some guarantees on the correctness of a
2007sample, and ensuring that it is always kept up to date.
2008
2009### Enforcement
2010
2011There are still some visibility issues here - it can be hard to tell if a
2012function is a sample, and is used from public documentation - so as a result we
2013have lint checks to ensure sample correctness.
2014
2015Primarily, there are three requirements when using sample links:
2016
20171. All functions linked to from a `@sample` KDoc tag must be annotated with
2018 `@Sampled`
20192. All sample functions annotated with `@Sampled` must be linked to from a
2020 `@sample` KDoc tag
20213. All sample functions must live inside a separate `samples` library
2022 submodule - see the section on module configuration below for more
2023 information.
2024
2025This enforces visibility guarantees, and make it easier to know that a sample is
2026a sample. This also prevents orphaned samples that aren't used, and remain
2027unmaintained and outdated.
2028
2029### Sample usage
2030
2031The follow demonstrates how to reference sample functions from public API. It is
2032also recommended to reuse these samples in unit tests / integration tests / test
2033apps / library demos where possible.
2034
2035**Public API:**
2036
2037```
2038/*
2039 * Fancy prints the given [string]
2040 *
2041 * @sample androidx.printer.samples.fancySample
2042 */
2043fun fancyPrint(str: String) ...
2044```
2045
2046**Sample function:**
2047
2048```
2049package androidx.printer.samples
2050
2051import androidx.printer.fancyPrint
2052
2053@Sampled
2054fun fancySample() {
2055 fancyPrint("Fancy!")
2056}
2057```
2058
2059**Generated documentation visible on d.android.com\***
2060
2061```
2062fun fancyPrint(str: String)
2063
2064Fancy prints the given [string]
2065
2066<code>
2067 import androidx.printer.fancyPrint
2068
2069 fancyPrint("Fancy!")
2070<code>
2071```
2072
2073\**still some improvements to be made to DAC side, such as syntax highlighting*
2074
2075### Module configuration
2076
2077The following module setups should be used for sample functions, and are
2078enforced by lint:
2079
2080**Group-level samples**
2081
2082For library groups with strongly related samples that want to share code.
2083
AndroidX Core Team0db91f02021-05-06 22:45:18 +00002084Gradle project name: `:foo-library:foo-library-samples`
AndroidX Core Team2e416b22020-12-03 22:58:07 +00002085
2086```
2087foo-library/
2088 foo-module/
2089 bar-module/
2090 samples/
2091```
2092
2093**Per-module samples**
2094
2095For library groups with complex, relatively independent sub-libraries
2096
AndroidX Core Team0db91f02021-05-06 22:45:18 +00002097Gradle project name: `:foo-library:foo-module:foo-module-samples`
AndroidX Core Team2e416b22020-12-03 22:58:07 +00002098
2099```
2100foo-library/
2101 foo-module/
2102 samples/
2103```
AndroidX Core Team0db91f02021-05-06 22:45:18 +00002104
2105**Samples module configuration**
2106
2107Samples modules are published to GMaven so that they are available to Android
2108Studio, which displays code in @Sample annotations as hover-over pop-ups.
2109
2110To achieve this, samples modules must declare the same MavenGroup and `publish`
2111as the library(s) they are samples for.