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