blob: e2662a5602f777498fd023e067fd933b380c0cdc [file] [log] [blame] [view]
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001# Library API guidelines
2
3[TOC]
4
5## Introduction {#introduction}
6
7s.android.com/api-guidelines,
8which covers standard and practices for designing platform APIs.
9
10All platform API design guidelines also apply to Jetpack libraries, with any
11additional guidelines or exceptions noted in this document. Jetpack libraries
12also follow
13[explicit API mode](https://kotlinlang.org/docs/reference/whatsnew14.html#explicit-api-mode-for-library-authors)
14for Kotlin libraries.
15
16## Modules {#module}
17
18### Packaging and naming {#module-naming}
19
20Java packages within Jetpack follow the format `androidx.<feature-name>`. All
21classes within a feature's artifact must reside within this package, and may
22further subdivide into `androidx.<feature-name>.<layer>` using standard Android
23layers (app, widget, etc.) or layers specific to the feature.
24
25Maven artifacts use the groupId format `androidx.<feature-name>` and artifactId
26format `<feature-name>` to match the Java package.
27
28Sub-features that can be separated into their own artifact should use the
29following formats:
30
31Java package: `androidx.<feature-name>.<sub-feature>.<layer>`
32
33Maven groupId: `androidx.<feature-name>`
34
35Maven artifactId: `<feature-name>-<sub-feature>`
36
37#### Common sub-feature names {#module-naming-subfeature}
38
39* `-testing` for an artifact intended to be used while testing usages of your
40 library, e.g. `androidx.room:room-testing`
41* `-core` for a low-level artifact that *may* contain public APIs but is
42 primarily intended for use by other libraries in the group
43* `-ktx` for an Kotlin artifact that exposes idiomatic Kotlin APIs as an
AndroidX Core Team0db91f02021-05-06 22:45:18 +000044 extension to a Java-only library (see
45 [additional -ktx guidance](#module-ktx))
AndroidX Core Team2e416b22020-12-03 22:58:07 +000046* `-<third-party>` for an artifact that integrates an optional third-party API
47 surface, e.g. `-proto` or `-rxjava2`. Note that a major version is included
48 in the sub-feature name for third-party API surfaces where the major version
49 indicates binary compatibility (only needed for post-1.x).
50
51Artifacts **should not** use `-impl` or `-base` to indicate that a library is an
52implementation detail shared within the group. Instead, use `-core`.
53
54#### Splitting existing modules
55
56Existing modules _should not_ be split into smaller modules; doing so creates
57the potential for class duplication issues when a developer depends on a new
58sub-module alongside the older top-level module. Consider the following
59scenario:
60
61* `androidx.library:1.0.0`
AndroidX Core Team43201242021-01-26 21:38:01 +000062 * contains class `androidx.library.A`
63 * contains class `androidx.library.util.B`
AndroidX Core Team2e416b22020-12-03 22:58:07 +000064
65This module is split, moving `androidx.library.util.B` to a new module:
66
67* `androidx.library:1.1.0`
68 * contains class `androidx.library.A`
AndroidX Core Team43201242021-01-26 21:38:01 +000069 * depends on `androidx.library.util:1.1.0`
70* `androidx.library.util:1.1.0`
71 * contains class `androidx.library.util.B`
AndroidX Core Team2e416b22020-12-03 22:58:07 +000072
AndroidX Core Team43201242021-01-26 21:38:01 +000073A developer writes an app that depends directly on `androidx.library.util:1.1.0`
74and also transitively pulls in `androidx.library:1.0.0`. Their app will no
75longer compile due to class duplication of `androidx.library.util.B`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +000076
77While it is possible for the developer to fix this by manually specifying a
78dependency on `androidx.library:1.1.0`, there is no easy way for the developer
79to discover this solution from the class duplication error raised at compile
80time.
81
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +000082Same-version groups are a special case for this rule. Existing modules that are
83already in a same-version group may be split into sub-modules provided that (a)
84the sub-modules are also in the same-version group and (b) the full API surface
85of the existing module is preserved through transitive dependencies, e.g. the
86sub-modules are added as dependencies of the existing module.
87
AndroidX Core Teamee1457a2021-02-25 16:13:10 +000088#### Same-version (atomic) groups {#modules-atomic}
AndroidX Core Team2e416b22020-12-03 22:58:07 +000089
90Library groups are encouraged to opt-in to a same-version policy whereby all
91libraries in the group use the same version and express exact-match dependencies
92on libraries within the group. Such groups must increment the version of every
93library at the same time and release all libraries at the same time.
94
95Atomic groups are specified in
AndroidX Core Team408c27b2020-12-15 15:57:00 +000096[`LibraryGroups.kt`](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt):
AndroidX Core Team2e416b22020-12-03 22:58:07 +000097
98```kotlin
99// Non-atomic library group
100val APPCOMPAT = LibraryGroup("androidx.appcompat", null)
101// Atomic library group
102val APPSEARCH = LibraryGroup("androidx.appsearch", LibraryVersions.APPSEARCH)
103```
104
105Libraries within an atomic group should not specify a version in their
106`build.gradle`:
107
108```groovy
109androidx {
110 name = 'AppSearch'
111 publish = Publish.SNAPSHOT_AND_RELEASE
112 mavenGroup = LibraryGroups.APPSEARCH
113 inceptionYear = '2019'
114 description = 'Provides local and centralized app indexing'
115}
116```
117
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000118The benefits of using an atomic group are:
119
120- Easier for developers to understand dependency versioning
121- `@RestrictTo(LIBRARY_GROUP)` APIs are treated as private APIs and not
122 tracked for binary compatibility
123- `@RequiresOptIn` APIs defined within the group may be used without any
124 restrictions between libraries in the group
125
126Potential drawbacks include:
127
128- All libraries within the group must be versioned identically at head
129- All libraries within the group must release at the same time
130
AndroidX Core Teamee1457a2021-02-25 16:13:10 +0000131#### Early-stage development {#modules-atomic-alpha}
132
133There is one exception to the same-version policy: newly-added libraries within
134an atomic group may be "quarantined" from other libraries to allow for rapid
135iteration until they are API-stable.
136
137A quarantined library must stay within the `1.0.0-alphaXX` cycle until it is
138ready to conform to the same-version policy. While in quarantime, a library is
139treated at though it is in a separate group from its nomical same-version group:
140
141- Must stay in `1.0.0-alphaXX`, e.g. same-version policy is not enforced
142- May use `project` or pinned version dependencies, e.g. strict-match
143 dependencies are not enforced
144- May release on a separate cadence from other libraries within group
145- Must not reference restricted `LIBRARY-GROUP`-scoped APIs
146
147When the library would like to leave quarantine, it must wait for its atomic
148group to be within a `beta` cycle and then match the version. It is okay for a
149library in this situation to skip versions, e.g. move directly from
150`1.0.0-alpha02` to `2.1.3-beta06`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000151
152### Choosing a `minSdkVersion` {#module-minsdkversion}
153
154The recommended minimum SDK version for new Jetpack libraries is currently
155**17** (Android 4.2, Jelly Bean). This SDK was chosen to represent 99% of active
156devices based on Play Store check-ins (see Android Studio
157[distribution metadata](https://dl.google.com/android/studio/metadata/distributions.json)
158for current statistics). This maximizes potential users for external developers
159while minimizing the amount of overhead necessary to support legacy versions.
160
161However, if no explicit minimum SDK version is specified for a library, the
162default is 14.
163
164Note that a library **must not** depend on another library with a higher
165`minSdkVersion` that its own, so it may be necessary for a new library to match
166its dependent libraries' `minSdkVersion`.
167
168Individual modules may choose a higher minimum SDK version for business or
169technical reasons. This is common for device-specific modules such as Auto or
170Wear.
171
172Individual classes or methods may be annotated with the
173[@RequiresApi](https://developer.android.com/reference/android/annotation/RequiresApi.html)
174annotation to indicate divergence from the overall module's minimum SDK version.
175Note that this pattern is _not recommended_ because it leads to confusion for
176external developers and should be considered a last-resort when backporting
177behavior is not feasible.
178
AndroidX Core Team0db91f02021-05-06 22:45:18 +0000179### Kotlin extension `-ktx` libraries {#module-ktx}
180
181New libraries should prefer Kotlin sources with built-in Java compatibility via
182`@JvmName` and other affordances of the Kotlin language; however, existing Java
183sourced libraries may benefit from extending their API surface with
184Kotlin-friendly APIs in a `-ktx` library.
185
186A Kotlin extension library **may only** provide extensions for a single base
187library's API surface and its name **must** match the base library exactly. For
188example, `work:work-ktx` may only provide extensions for APIs exposed by
189`work:work`.
190
191Additionally, an extension library **must** specify an `api`-type dependency on
192the base library and **must** be versioned and released identically to the base
193library.
194
195Kotlin extension libraries _should not_ expose new functionality; they should
196only provide Kotlin-friendly versions of existing Java-facing functionality.
197
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000198## Platform compatibility API patterns {#platform-compatibility-apis}
199
AndroidX Core Team37584142021-02-25 17:58:46 +0000200NOTE For all library APIs that wrap or provide parity with platform APIs,
201_parity with the platform APIs overrides API guidelines_. For example, if the
202platform API being wrapped has incorrect `Executor` and `Callback` ordering
203according to the API Guidelines, the corresponding library API should have the
204exact same (incorrect) ordering.
205
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000206### Static shims (ex. [ViewCompat](https://developer.android.com/reference/android/support/v4/view/ViewCompat.html)) {#static-shim}
207
208When to use?
209
210* Platform class exists at module's `minSdkVersion`
211* Compatibility implementation does not need to store additional metadata
212
213Implementation requirements
214
215* Class name **must** be `<PlatformClass>Compat`
216* Package name **must** be `androidx.<feature>.<platform.package>`
217* Superclass **must** be `Object`
218* Class **must** be non-instantiable, i.e. constructor is private no-op
219* Static fields and static methods **must** match match signatures with
220 `PlatformClass`
221 * Static fields that can be inlined, ex. integer constants, **must not**
222 be shimmed
223* Public method names **must** match platform method names
224* Public methods **must** be static and take `PlatformClass` as first
225 parameter
226* Implementation _may_ delegate to `PlatformClass` methods when available
227
228#### Sample {#static-shim-sample}
229
230The following sample provides static helper methods for the platform class
231`android.os.Process`.
232
233```java
234/**
235 * Helper for accessing features in {@link Process}.
236 */
237public final class ProcessCompat {
238 private ProcessCompat() {
239 // This class is non-instantiable.
240 }
241
242 /**
243 * [Docs should match platform docs.]
244 *
245 * Compatibility behavior:
246 * <ul>
247 * <li>SDK 24 and above, this method matches platform behavior.
248 * <li>SDK 16 through 23, this method is a best-effort to match platform behavior, but may
249 * default to returning {@code true} if an accurate result is not available.
250 * <li>SDK 15 and below, this method always returns {@code true} as application UIDs and
251 * isolated processes did not exist yet.
252 * </ul>
253 *
254 * @param [match platform docs]
255 * @return [match platform docs], or a value based on platform-specific fallback behavior
256 */
257 public static boolean isApplicationUid(int uid) {
258 if (Build.VERSION.SDK_INT >= 24) {
259 return Api24Impl.isApplicationUid(uid);
260 } else if (Build.VERSION.SDK_INT >= 17) {
261 return Api17Impl.isApplicationUid(uid);
262 } else if (Build.VERSION.SDK_INT == 16) {
263 return Api16Impl.isApplicationUid(uid);
264 } else {
265 return true;
266 }
267 }
268
269 @RequiresApi(24)
270 static class Api24Impl {
271 static boolean isApplicationUid(int uid) {
272 // In N, the method was made public on android.os.Process.
273 return Process.isApplicationUid(uid);
274 }
275 }
276
277 @RequiresApi(17)
278 static class Api17Impl {
279 private static Method sMethod_isAppMethod;
280 private static boolean sResolved;
281
282 static boolean isApplicationUid(int uid) {
283 // In JELLY_BEAN_MR2, the equivalent isApp(int) hidden method moved to public class
284 // android.os.UserHandle.
285 try {
286 if (!sResolved) {
287 sResolved = true;
288 sMethod_isAppMethod = UserHandle.class.getDeclaredMethod("isApp",int.class);
289 }
290 if (sMethod_isAppMethod != null) {
291 return (Boolean) sMethod_isAppMethod.invoke(null, uid);
292 }
293 } catch (Exception e) {
294 e.printStackTrace();
295 }
296 return true;
297 }
298 }
299
300 ...
301}
302```
303
304### Wrapper (ex. [AccessibilityNodeInfoCompat](https://developer.android.com/reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html)) {#wrapper}
305
306When to use?
307
308* Platform class may not exist at module's `minSdkVersion`
309* Compatibility implementation may need to store additional metadata
310* Needs to integrate with platform APIs as return value or method argument
311* **Note:** Should be avoided when possible, as using wrapper classes makes it
312 very difficult to deprecate classes and migrate source code when the
313 `minSdkVersion` is raised
314
315#### Sample {#wrapper-sample}
316
317The following sample wraps a hypothetical platform class `ModemInfo` that was
318added to the platform SDK in API level 23:
319
320```java
321public final class ModemInfoCompat {
322 // Only guaranteed to be non-null on SDK_INT >= 23. Note that referencing the
323 // class itself directly is fine -- only references to class members need to
324 // be pushed into static inner classes.
325 private final ModemInfo wrappedObj;
326
327 /**
328 * [Copy platform docs for matching constructor.]
329 */
330 public ModemInfoCompat() {
331 if (SDK_INT >= 23) {
332 wrappedObj = Api23Impl.create();
333 } else {
334 wrappedObj = null;
335 }
336 ...
337 }
338
339 @RequiresApi(23)
340 private ModemInfoCompat(@NonNull ModemInfo obj) {
341 mWrapped = obj;
342 }
343
344 /**
345 * Provides a backward-compatible wrapper for {@link ModemInfo}.
346 * <p>
347 * This method is not supported on devices running SDK < 23 since the platform
348 * class will not be available.
349 *
350 * @param info platform class to wrap
351 * @return wrapped class, or {@code null} if parameter is {@code null}
352 */
353 @RequiresApi(23)
354 @NonNull
355 public static ModemInfoCompat toModemInfoCompat(@NonNull ModemInfo info) {
356 return new ModemInfoCompat(obj);
357 }
358
359 /**
360 * Provides the {@link ModemInfo} represented by this object.
361 * <p>
362 * This method is not supported on devices running SDK < 23 since the platform
363 * class will not be available.
364 *
365 * @return platform class object
366 * @see ModemInfoCompat#toModemInfoCompat(ModemInfo)
367 */
368 @RequiresApi(23)
369 @NonNull
370 public ModemInfo toModemInfo() {
371 return mWrapped;
372 }
373
374 /**
375 * [Docs should match platform docs.]
376 *
377 * Compatibility behavior:
378 * <ul>
379 * <li>API level 23 and above, this method matches platform behavior.
380 * <li>API level 18 through 22, this method ...
381 * <li>API level 17 and earlier, this method always returns false.
382 * </ul>
383 *
384 * @return [match platform docs], or platform-specific fallback behavior
385 */
386 public boolean isLteSupported() {
387 if (SDK_INT >= 23) {
388 return Api23Impl.isLteSupported(mWrapped);
389 } else if (SDK_INT >= 18) {
390 // Smart fallback behavior based on earlier APIs.
391 ...
392 }
393 // Default behavior.
394 return false;
395 }
396
397 // All references to class members -- including the constructor -- must be
398 // made on an inner class to avoid soft-verification errors that slow class
399 // loading and prevent optimization.
400 @RequiresApi(23)
401 private static class Api23Impl {
402 @NonNull
403 static ModemInfo create() {
404 return new ModemInfo();
405 }
406
407 static boolean isLteSupported(PlatformClass obj) {
408 return obj.isLteSupported();
409 }
410 }
411}
412```
413
414Note that libraries written in Java should express conversion to and from the
415platform class differently than Kotlin classes. For Java classes, conversion
416from the platform class to the wrapper should be expressed as a `static` method,
417while conversion from the wrapper to the platform class should be a method on
418the wrapper object:
419
420```java
421@NonNull
422public static ModemInfoCompat toModemInfoCompat(@NonNull ModemInfo info);
423
424@NonNull
425public ModemInfo toModemInfo();
426```
427
428In cases where the primary library is written in Java and has an accompanying
429`-ktx` Kotlin extensions library, the following conversion should be provided as
430an extension function:
431
432```kotlin
433fun ModemInfo.toModemInfoCompat() : ModemInfoCompat
434```
435
436Whereas in cases where the primary library is written in Kotlin, the conversion
437should be provided as an extension factory:
438
439```kotlin
440class ModemInfoCompat {
441 fun toModemInfo() : ModemInfo
442
443 companion object {
444 @JvmStatic
445 @JvmName("toModemInfoCompat")
446 fun ModemInfo.toModemInfoCompat() : ModemInfoCompat
447 }
448}
449```
450
451#### API guidelines {#wrapper-api-guidelines}
452
453##### Naming {#wrapper-naming}
454
455* Class name **must** be `<PlatformClass>Compat`
456* Package name **must** be `androidx.core.<platform.package>`
457* Superclass **must not** be `<PlatformClass>`
458
459##### Construction {#wrapper-construction}
460
461* Class _may_ have public constructor(s) to provide parity with public
462 `PlatformClass` constructors
463 * Constructor used to wrap `PlatformClass` **must not** be public
464* Class **must** implement a static `PlatformClassCompat
465 toPlatformClassCompat(PlatformClass)` method to wrap `PlatformClass` on
466 supported SDK levels
467 * If class does not exist at module's `minSdkVersion`, method must be
468 annotated with `@RequiresApi(<sdk>)` for SDK version where class was
469 introduced
470
471#### Implementation {#wrapper-implementation}
472
473* Class **must** implement a `PlatformClass toPlatformClass()` method to
474 unwrap `PlatformClass` on supported SDK levels
475 * If class does not exist at module's `minSdkVersion`, method must be
476 annotated with `@RequiresApi(<sdk>)` for SDK version where class was
477 introduced
478* Implementation _may_ delegate to `PlatformClass` methods when available (see
479 below note for caveats)
480* To avoid runtime class verification issues, all operations that interact
481 with the internal structure of `PlatformClass` must be implemented in inner
482 classes targeted to the SDK level at which the operation was added.
483 * See the [sample](#wrapper-sample) for an example of interacting with a
484 method that was added in SDK level 23.
485
486### 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}
487
488When to use?
489
490* Platform class may exist at module's `minSdkVersion`
491* Does not need to integrate with platform APIs
492* Does not need to coexist with platform class, ex. no potential `import`
493 collision due to both compatibility and platform classes being referenced
494 within the same source file
495
496Implementation requirements
497
498* Class name **must** be `<PlatformClass>`
499* Package name **must** be `androidx.<platform.package>`
500* Superclass **must not** be `<PlatformClass>`
501* Class **must not** expose `PlatformClass` in public API
AndroidX Core Teamee1457a2021-02-25 16:13:10 +0000502 * In exceptional cases, a _released_ standalone class may add conversion
503 between itself and the equivalent platform class; however, _new_ classes
504 that support conversion should follow the [Wrapper](#wrapper)
505 guidelines. In these cases, use a `toPlatform<PlatformClass>` and
506 `static toCompat<PlatformClass>` method naming convention.
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000507* Implementation _may_ delegate to `PlatformClass` methods when available
508
509### Standalone JAR library (no Android dependencies) {#standalone-jar-library-no-android-dependencies}
510
511When to use
512
513* General purpose library with minimal interaction with Android types
514 * or when abstraction around types can be used (e.g. Room's SQLite
515 wrapper)
516* Lib used in parts of app with minimal Android dependencies
517 * ex. Repository, ViewModel
518* When Android dependency can sit on top of common library
519* Clear separation between android dependent and independent parts of your
520 library
521* Clear that future integration with android dependencies can be layered
522 separately
523
524**Examples:**
525
526The **Paging Library** pages data from DataSources (such as DB content from Room
527or network content from Retrofit) into PagedLists, so they can be presented in a
528RecyclerView. Since the included Adapter receives a PagedList, and there are no
529other Android dependencies, Paging is split into two parts - a no-android
530library (paging-common) with the majority of the paging code, and an android
531library (paging-runtime) with just the code to present a PagedList in a
532RecyclerView Adapter. This way, tests of Repositories and their components can
533be tested in host-side tests.
534
535**Room** loads SQLite data on Android, but provides an abstraction for those
536that want to use a different SQL implementation on device. This abstraction, and
537the fact that Room generates code dynamically, means that Room interfaces can be
538used in host-side tests (though actual DB code should be tested on device, since
539DB impls may be significantly different on host).
540
541## Implementing compatibility {#compat}
542
543### Referencing new APIs {#compat-newapi}
544
545Generally, methods on extension library classes should be available to all
546devices above the library's `minSdkVersion`.
547
548#### Checking device SDK version {#compat-sdk}
549
550The most common way of delegating to platform or backport implementations is to
551compare the device's `Build.VERSION.SDK_INT` field to a known-good SDK version;
552for example, the SDK in which a method first appeared or in which a critical bug
553was first fixed.
554
555Non-reflective calls to new APIs gated on `SDK_INT` **must** be made from
556version-specific static inner classes to avoid verification errors that
557negatively affect run-time performance. For more information, see Chromium's
558guide to
559[Class Verification Failures](https://chromium.googlesource.com/chromium/src/+/HEAD/build/android/docs/class_verification_failures.md).
560
561Methods in implementation-specific classes **must** be paired with the
562`@DoNotInline` annotation to prevent them from being inlined.
563
564```java {.good}
565public static void saveAttributeDataForStyleable(@NonNull View view, ...) {
566 if (Build.VERSION.SDK_INT >= 29) {
567 Api29Impl.saveAttributeDataForStyleable(view, ...);
568 }
569}
570
571@RequiresApi(29)
572private static class Api29Impl {
573 @DoNotInline
574 static void saveAttributeDataForStyleable(@NonNull View view, ...) {
575 view.saveAttributeDataForStyleable(...);
576 }
577}
578```
579
580Alternatively, in Kotlin sources:
581
582```kotlin {.good}
583@RequiresApi(29)
584object Api25 {
585 @DoNotInline
586 fun saveAttributeDataForStyleable(view: View, ...) { ... }
587}
588```
589
590When developing against pre-release SDKs where the `SDK_INT` has not been
591finalized, SDK checks **must** use `BuildCompat.isAtLeastX()` methods.
592
593```java {.good}
594@NonNull
595public static List<Window> getAllWindows() {
596 if (BuildCompat.isAtLeastR()) {
597 return ApiRImpl.getAllWindows();
598 }
599 return Collections.emptyList();
600}
601```
602
603#### Device-specific issues {#compat-oem}
604
605Library code may work around device- or manufacturer-specific issues -- issues
606not present in AOSP builds of Android -- *only* if a corresponding CTS test
607and/or CDD policy is added to the next revision of the Android platform. Doing
608so ensures that such issues can be detected and fixed by OEMs.
609
610#### Handling `minSdkVersion` disparity {#compat-minsdk}
611
612Methods that only need to be accessible on newer devices, including
613`to<PlatformClass>()` methods, may be annotated with `@RequiresApi(<sdk>)` to
614indicate they will fail to link on older SDKs. This annotation is enforced at
615build time by Lint.
616
617#### Handling `targetSdkVersion` behavior changes {#compat-targetsdk}
618
619To preserve application functionality, device behavior at a given API level may
620change based on an application's `targetSdkVersion`. For example, if an app with
621`targetSdkVersion` set to API level 22 runs on a device with API level 29, all
622required permissions will be granted at installation time and the run-time
623permissions framework will emulate earlier device behavior.
624
625Libraries do not have control over the app's `targetSdkVersion` and -- in rare
626cases -- may need to handle variations in platform behavior. Refer to the
627following pages for version-specific behavior changes:
628
629* API level 29:
630 [Android Q behavior changes: apps targeting Q](https://developer.android.com/preview/behavior-changes-q)
631* API level 28:
632 [Behavior changes: apps targeting API level 28+](https://developer.android.com/about/versions/pie/android-9.0-changes-28)
633* API level 26:
634 [Changes for apps targeting Android 8.0](https://developer.android.com/about/versions/oreo/android-8.0-changes#o-apps)
635* API level 24:
636 [Changes for apps targeting Android 7.0](https://developer.android.com/about/versions/nougat/android-7.0-changes#n-apps)
637* API level 21:
638 [Android 5.0 Behavior Changes](https://developer.android.com/about/versions/android-5.0-changes)
639* API level 19:
640 [Android 4.4 APIs](https://developer.android.com/about/versions/android-4.4)
641
642#### Working around Lint issues {#compat-lint}
643
644In rare cases, Lint may fail to interpret API usages and yield a `NewApi` error
645and require the use of `@TargetApi` or `@SuppressLint('NewApi')` annotations.
646Both of these annotations are strongly discouraged and may only be used
647temporarily. They **must never** be used in a stable release. Any usage of these
648annotation **must** be associated with an active bug, and the usage must be
649removed when the bug is resolved.
650
651### Delegating to API-specific implementations {#delegating-to-api-specific-implementations}
652
653#### SDK-dependent reflection
654
655Starting in API level 28, the platform restricts which
656[non-SDK interfaces](https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces)
657can be accessed via reflection by apps and libraries. As a general rule, you
658will **not** be able to use reflection to access hidden APIs on devices with
659`SDK_INT` greater than `Build.VERSION_CODES.P` (28).
660
661On earlier devices, reflection on hidden platform APIs is allowed **only** when
662an alternative public platform API exists in a later revision of the Android
663SDK. For example, the following implementation is allowed:
664
665```java
666public AccessibilityDelegate getAccessibilityDelegate(View v) {
667 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
668 // Retrieve the delegate using a public API.
669 return v.getAccessibilityDelegate();
670 } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
671 // Retrieve the delegate by reflecting on a private field. If the
672 // field does not exist or cannot be accessed, this will no-op.
673 if (sAccessibilityDelegateField == null) {
674 try {
675 sAccessibilityDelegateField = View.class
676 .getDeclaredField("mAccessibilityDelegate");
677 sAccessibilityDelegateField.setAccessible(true);
678 } catch (Throwable t) {
679 sAccessibilityDelegateCheckFailed = true;
680 return null;
681 }
682 }
683 try {
684 Object o = sAccessibilityDelegateField.get(v);
685 if (o instanceof View.AccessibilityDelegate) {
686 return (View.AccessibilityDelegate) o;
687 }
688 return null;
689 } catch (Throwable t) {
690 sAccessibilityDelegateCheckFailed = true;
691 return null;
692 }
693 } else {
694 // There is no way to retrieve the delegate, even via reflection.
695 return null;
696 }
697```
698
699Calls to public APIs added in pre-release revisions *must* be gated using
700`BuildCompat`:
701
702```java
703if (BuildCompat.isAtLeastQ()) {
704 // call new API added in Q
705} else if (Build.SDK_INT.VERSION >= Build.VERSION_CODES.SOME_RELEASE) {
706 // make a best-effort using APIs that we expect to be available
707} else {
708 // no-op or best-effort given no information
709}
710```
711
712### Inter-process communication {#inter-process-communication}
713
714Protocols and data structures used for IPC must support interoperability between
715different versions of libraries and should be treated similarly to public API.
716
717#### Data structures
718
719**Do not** use Parcelable for any class that may be used for IPC or otherwise
720exposed as public API. The data format used by Parcelable does not provide any
721compatibility guarantees and will result in crashes if fields are added or
722removed between library versions.
723
724**Do not** design your own serialization mechanism or wire format for disk
725storage or inter-process communication. Preserving and verifying compatibility
726is difficult and error-prone.
727
728If you expose a `Bundle` to callers that can cross processes, you should
729[prevent apps from adding their own custom parcelables](https://android.googlesource.com/platform/frameworks/base/+/6cddbe14e1ff67dc4691a013fe38a2eb0893fe03)
730as top-level entries; if *any* entry in a `Bundle` can't be loaded, even if it's
731not actually accessed, the receiving process is likely to crash.
732
733**Do** use protocol buffers or, in some simpler cases, `VersionedParcelable`.
734
735#### Communication protocols
736
737Any communication prototcol, handshake, etc. must maintain compatibility
738consistent with SemVer guidelines. Consider how your protocol will handle
739addition and removal of operations or constants, compatibility-breaking changes,
740and other modifications without crashing either the host or client process.
741
742## Deprecation and removal
743
744While SemVer's binary compatibility guarantees restrict the types of changes
745that may be made within a library revision and make it difficult to remove an
746API, there are many other ways to influence how developers interact with your
747library.
748
749### Deprecation (`@deprecated`)
750
751Deprecation lets a developer know that they should stop using an API or class.
752All deprecations must be marked with a `@Deprecated` Java annotation as well as
753a `@deprecated <migration-docs>` docs annotation explaining how the developer
754should migrate away from the API.
755
756Deprecation is an non-breaking API change that must occur in a **major** or
757**minor** release.
758
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +0000759APIs that are added during a pre-release cycle and marked as `@Deprecated`
760within the same cycle, e.g. added in `alpha01` and deprecated in `alpha06`,
761[must be removed](versioning.md#beta-checklist) before moving to `beta01`.
762
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000763### Soft removal (@removed)
764
765Soft removal preserves binary compatibility while preventing source code from
766compiling against an API. It is a *source-breaking change* and not recommended.
767
768Soft removals **must** do the following:
769
770* Mark the API as deprecated for at least one stable release prior to removal.
771* Mark the API with a `@RestrictTo(LIBRARY)` Java annotation as well as a
772 `@removed <reason>` docs annotation explaining why the API was removed.
773* Maintain binary compatibility, as the API may still be called by existing
774 dependent libraries.
775* Maintain behavioral compatibility and existing tests.
776
777This is a disruptive change and should be avoided when possible.
778
779Soft removal is a source-breaking API change that must occur in a **major** or
780**minor** release.
781
782### Hard removal
783
784Hard removal entails removing the entire implementation of an API that was
785exposed in a public release. Prior to removal, an API must be marked as
786`@deprecated` for a full **minor** version (`alpha`->`beta`->`rc`->stable),
787prior to being hard removed.
788
789This is a disruptive change and should be avoided when possible.
790
791Hard removal is a binary-breaking API change that must occur in a **major**
792release.
793
794### For entire artifacts
795
796We do not typically deprecate or remove entire artifacts; however, it may be
797useful in cases where we want to halt development and focus elsewhere or
798strongly discourage developers from using a library.
799
800Halting development, either because of staffing or prioritization issues, leaves
801the door open for future bug fixes or continued development. This quite simply
802means we stop releasing updates but retain the source in our tree.
803
804Deprecating an artifact provides developers with a migration path and strongly
805encourages them -- through Lint warnings -- to migrate elsewhere. This is
806accomplished by adding a `@Deprecated` and `@deprecated` (with migration
807comment) annotation pair to *every* class and interface in the artifact.
808
809The fully-deprecated artifact will be released as a deprecation release -- it
810will ship normally with accompanying release notes indicating the reason for
811deprecation and migration strategy, and it will be the last version of the
812artifact that ships. It will ship as a new minor stable release. For example, if
813`1.0.0` was the last stable release, then the deprecation release will be
814`1.1.0`. This is so Android Studio users will get a suggestion to update to a
815new stable version, which will contain the `@deprecated` annotations.
816
817After an artifact has been released as fully-deprecated, it can be removed from
818the source tree.
819
820## Resources {#resources}
821
822Generally, follow the official Android guidelines for
823[app resources](https://developer.android.com/guide/topics/resources/providing-resources).
824Special guidelines for library resources are noted below.
825
826### Defining new resources
827
828Libraries may define new value and attribute resources using the standard
829application directory structure used by Android Gradle Plugin:
830
831```
832src/main/res/
833 values/
834 attrs.xml Theme attributes and styleables
835 dimens.xml Dimensional values
836 public.xml Public resource definitions
837 ...
838```
839
840However, some libraries may still be using non-standard, legacy directory
841structures such as `res-public` for their public resource declarations or a
842top-level `res` directory and accompanying custom source set in `build.gradle`.
843These libraries will eventually be migrated to follow standard guidelines.
844
845#### Naming conventions
846
847Libraries follow the Android platform's resource naming conventions, which use
848`camelCase` for attributes and `underline_delimited` for values. For example,
849`R.attr.fontProviderPackage` and `R.dimen.material_blue_grey_900`.
850
851#### Attribute formats
852
853At build time, attribute definitions are pooled globally across all libraries
854used in an application, which means attribute `format`s *must* be identical for
855a given `name` to avoid a conflict.
856
857Within Jetpack, new attribute names *must* be globally unique. Libraries *may*
858reference existing public attributes from their dependencies. See below for more
859information on public attributes.
860
861When adding a new attribute, the format should be defined *once* in an `<attr
862/>` element in the definitions block at the top of `src/main/res/attrs.xml`.
863Subsequent references in `<declare-styleable>` elements *must* not include a
864`format`:
865
866`src/main/res/attrs.xml`
867
868```xml
869<resources>
870 <attr name="fontProviderPackage" format="string" />
871
872 <declare-styleable name="FontFamily">
873 <attr name="fontProviderPackage" />
874 </declare-styleable>
875</resources>
876```
877
878### Public resources
879
880Library resources are private by default, which means developers are discouraged
881from referencing any defined attributes or values from XML or code; however,
882library resources may be declared public to make them available to developers.
883
884Public library resources are considered API surface and are thus subject to the
885same API consistency and documentation requirements as Java APIs.
886
887Libraries will typically only expose theme attributes, ex. `<attr />` elements,
888as public API so that developers can set and retrieve the values stored in
889styles and themes. Exposing values -- such as `<dimen />` and `<string />` -- or
890images -- such as drawable XML and PNGs -- locks the current state of those
891elements as public API that cannot be changed without a major version bump. That
892means changing a publicly-visible icon would be considered a breaking change.
893
894#### Documentation
895
896All public resource definitions should be documented, including top-level
897definitions and re-uses inside `<styleable>` elements:
898
899`src/main/res/attrs.xml`
900
901```xml
902<resources>
903 <!-- String specifying the application package for a Font Provider. -->
904 <attr name="fontProviderPackage" format="string" />
905
906 <!-- Attributes that are read when parsing a <fontfamily> tag. -->
907 <declare-styleable name="FontFamily">
908 <!-- The package for the Font Provider to be used for the request. This is
909 used to verify the identity of the provider. -->
910 <attr name="fontProviderPackage" />
911 </declare-styleable>
912</resources>
913```
914
915`src/main/res/colors.xml`
916
917```xml
918<resources>
919 <!-- Color for Material Blue-Grey 900. -->
920 <color name="material_blue_grey_900">#ff263238</color>
921</resources>
922```
923
924#### Public declaration
925
926Resources are declared public by providing a separate `<public />` element with
927a matching type:
928
929`src/main/res/public.xml`
930
931```xml
932<resources>
933 <public name="fontProviderPackage" type="attr" />
934 <public name="material_blue_grey_900" type="color" />
935</resources>
936```
937
938#### More information
939
940See also the official Android Gradle Plugin documentation for
941[Private Resources](https://developer.android.com/studio/projects/android-library#PrivateResources).
942
943### Manifest entries (`AndroidManifest.xml`) {#resources-manifest}
944
945#### Metadata tags (`<meta-data>`) {#resources-manifest-metadata}
946
947Developers **must not** add `<application>`-level `<meta-data>` tags to library
948manifests or advise developers to add such tags to their application manifests.
949Doing so may _inadvertently cause denial-of-service attacks against other apps_.
950
951Assume a library adds a single item of meta-data at the application level. When
952an app uses the library, that meta-data will be merged into the resulting app's
953application entry via manifest merger.
954
955If another app attempts to obtain a list of all activities associated with the
956primary app, that list will contain multiple copies of the `ApplicationInfo`,
957each of which in turn contains a copy of the library's meta-data. As a result,
958one `<metadata>` tag may become hundreds of KB on the binder call to obtain the
959list -- resulting in apps hitting transaction too large exceptions and crashing.
960
961```xml {.bad}
962<manifest xmlns:android="http://schemas.android.com/apk/res/android"
963 package="androidx.librarypackage">
964 <application>
965 <meta-data
966 android:name="keyName"
967 android:value="@string/value" />
968 </application>
969</manifest>
970```
971
972Instead, developers may consider adding `<metadata>` nested inside of
973placeholder `<service>` tags.
974
975```xml {.good}
976<manifest xmlns:android="http://schemas.android.com/apk/res/android"
977 package="androidx.librarypackage">
978 <application>
979 <service
980 android:name="androidx.librarypackage.MetadataHolderService"
981 android:enabled="false"
982 android:exported="false">
983 <meta-data
984 android:name="androidx.librarypackage.MetadataHolderService.KEY_NAME"
985 android:resource="@string/value" />
986 </service>
987 </application>
988```
989
990```java {.good}
991package androidx.libraryname.featurename;
992
993/**
994 * A placeholder service to avoid adding application-level metadata. The service
995 * is only used to expose metadata defined in the library's manifest. It is
996 * never invoked.
997 */
998public final class MetadataHolderService {
999 private MetadataHolderService() {}
1000
1001 @Override
1002 public IBinder onBind(Intent intent) {
1003 throw new UnsupportedOperationException();
1004 }
1005}
1006```
1007
1008## Dependencies {#dependencies}
1009
1010Generally, Jetpack libraries should avoid dependencies that negatively impact
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001011developers without providing substantial benefit.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001012
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001013### System health {#dependencies-health}
1014
1015Libraries should consider the system health implications of their dependencies,
1016including:
1017
1018- Large dependencies where only a small portion is needed (e.g. APK bloat)
1019- Dependencies that slow down build times through annotation processing or
1020 compiler overhead
1021
1022#### Kotlin {#dependencies-kotlin}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001023
AndroidX Core Team43201242021-01-26 21:38:01 +00001024Kotlin is _strongly recommended_ for new libraries; however, it's important to
1025consider its size impact on clients. Currently, the Kotlin stdlib adds a minimum
1026of 40kB post-optimization. It may not make sense to use Kotlin for a library
1027that targets Java-only clients or space-constrained (ex. Android Go) clients.
1028
1029Existing Java-based libraries are _strongly discouraged_ from using Kotlin,
1030primarily because our documentation system does not currently provide a
1031Java-facing version of Kotlin API reference docs. Java-based libraries _may_
1032migrate to Kotlin, but they must consider the docs usability and size impacts on
1033existing Java-only and space-constrained clients.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001034
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001035#### Kotlin coroutines {#dependencies-coroutines}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001036
1037Kotlin's coroutine library adds around 100kB post-shrinking. New libraries that
1038are written in Kotlin should prefer coroutines over `ListenableFuture`, but
1039existing libraries must consider the size impact on their clients. See
1040[Asynchronous work with return values](#async-return) for more details on using
1041Kotlin coroutines in Jetpack libraries.
1042
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001043#### Guava {#dependencies-guava}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001044
1045The full Guava library is very large and *must not* be used. Libraries that
1046would like to depend on Guava's `ListenableFuture` may instead depend on the
1047standalone `com.google.guava:listenablefuture` artifact. See
1048[Asynchronous work with return values](#async-return) for more details on using
1049`ListenableFuture` in Jetpack libraries.
1050
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001051#### Java 8 {#dependencies-java8}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001052
AndroidX Core Team95cd3da2021-01-14 11:47:43 -05001053NOTE All Jetpack libraries will migrate to Java 8 as soon as Android Studio 4.2
1054launches to stable. Until then, new dependencies on Java 8 should weigh the pros
1055and cons as documented here.
1056
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001057Libraries that take a dependency on a library targeting Java 8 must _also_
1058target Java 8, which will incur a ~5% build performance (as of 8/2019) hit for
1059clients. New libraries targeting Java 8 may use Java 8 dependencies; however,
1060existing libraries targeting Java 7 should not.
1061
1062The default language level for `androidx` libraries is Java 8, and we encourage
1063libraries to stay on Java 8. However, if you have a business need to target Java
10647, you can specify Java 7 in your `build.gradle` as follows:
1065
1066```Groovy
1067android {
1068 compileOptions {
1069 sourceCompatibility = JavaVersion.VERSION_1_7
1070 targetCompatibility = JavaVersion.VERSION_1_7
1071 }
1072}
1073```
1074
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001075### Open-source compatibility {#dependencies-aosp}
1076
1077[Jetpack Principles](principles.md) require that libraries consider the
1078open-source compatibility implications of their dependencies, including:
1079
1080- Closed-source or proprietary libraries or services that may not be available
1081 on AOSP devices
1082- Dependencies that may prevent developers from effectively isolating their
1083 tests from third-party libraries or services
1084
1085Primary artifacts, e.g. `workmanager`, **must not** depend on closed-source
1086components including libraries and hard-coded references to packages,
1087permissions, or IPC mechanisms that may only be fulfulled by closed-source
1088components.
1089
1090Optional artifacts, e.g. `workmanager-gcm`, _may_ depend on closed-source
1091components or configure a primary artifact to be backed by a closed-source
1092component via service discovery or initialization.
1093
1094Some examples of safely depending on closed-source components include:
1095
1096- WorkManager's GCM Network Manager integration, which uses manifest metadata
1097 for service discovery and provides an optional artifact exposing the
1098 service.
1099- Ads Identifier's Play Services integration, which provides a default backend
1100 and uses `Intent` handling as a service discovery mechanism for Play
1101 Services.
1102- Downloadable Fonts integration with Play Services, which plugs in via a
1103 `ContentProvider` as a service discovery mechanism with developer-specified
1104 signature verification for additional security.
1105
1106Note that in all cases, the developer is not _required_ to use GCM or Play
1107Services and may instead use another compatible service implementing the same
1108publicly-defined protocols.
1109
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001110## More API guidelines {#more-api-guidelines}
1111
1112### Annotations {#annotation}
1113
1114#### Annotation processors {#annotation-processor}
1115
1116Annotation processors should opt-in to incremental annotation processing to
1117avoid triggering a full recompilation on every client source code change. See
1118Gradle's
1119[Incremental annotation processing](https://docs.gradle.org/current/userguide/java_plugin.html#sec:incremental_annotation_processing)
1120documentation for information on how to opt-in.
1121
alanvf5ca4b92021-02-10 13:07:47 -08001122### Experimental `@RequiresOptIn` APIs {#experimental-api}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001123
1124Jetpack libraries may choose to annotate API surfaces as unstable using either
1125Kotlin's
alanvf5ca4b92021-02-10 13:07:47 -08001126[`@RequiresOptIn` annotation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-requires-opt-in/)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001127for APIs written in Kotlin or Jetpack's
alanvf5ca4b92021-02-10 13:07:47 -08001128[`@RequiresOptIn` annotation](https://developer.android.com/reference/kotlin/androidx/annotation/RequiresOptIn)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001129for APIs written in Java.
1130
1131In both cases, API surfaces marked as experimental are considered alpha and will
1132be excluded from API compatibility guarantees. Due to the lack of compatibility
alanvf5ca4b92021-02-10 13:07:47 -08001133guarantees, stable libraries *must never* call experimental APIs exposed by
1134other libraries outside of their
1135[same-version group](#same-version-atomic-groups) and *may not* use the `@OptIn`
1136annotation except in the following cases:
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001137
1138* A library within a same-version group *may* call an experimental API exposed
1139 by another library **within its same-version group**. In this case, API
1140 compatibility guarantees are covered under the same-version group policies
alanvf5ca4b92021-02-10 13:07:47 -08001141 and the library *may* use the `@OptIn` annotation to prevent propagation of
1142 the experimental property. **Library owners must exercise care to ensure
1143 that post-alpha APIs backed by experimental APIs actually meet the release
1144 criteria for post-alpha APIs.**
1145* An `alpha` library may use experimental APIs from outside its same-version
1146 group. These usages must be removed when the library moves to `beta`.
1147
1148NOTE JetBrains's own usage of `@RequiresOptIn` in Kotlin language libraries
1149varies and may indicate binary instability, functional instability, or simply
1150that an API is really difficult to use. Jetpack libraries should treat instances
1151of `@RequiresOptIn` in JetBrains libraries as indicating **binary instability**
1152and avoid using them outside of `alpha`; however, teams are welcome to obtain
1153written assurance from JetBrains regarding binary stability of specific APIs.
1154`@RequiresOptIn` APIs that are guaranteed to remain binary compatible _may_ be
1155used in `beta`, but usages must be removed when the library moves to `rc`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001156
1157#### How to mark an API surface as experimental
1158
alanvf5ca4b92021-02-10 13:07:47 -08001159All libraries using `@RequiresOptIn` annotations *must* depend on the
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001160`androidx.annotation:annotation-experimental` artifact regardless of whether
1161they are using the `androidx` or Kotlin annotation. This artifact provides Lint
1162enforcement of experimental usage restrictions for Kotlin callers as well as
1163Java (which the Kotlin annotation doesn't handle on its own, since it's a Kotlin
1164compiler feature). Libraries *may* include the dependency as `api`-type to make
alanvf5ca4b92021-02-10 13:07:47 -08001165`@OptIn` available to Java clients; however, this will also unnecessarily expose
1166the `@RequiresOptIn` annotation.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001167
1168```java
1169dependencies {
1170 implementation(project(":annotation:annotation-experimental"))
1171}
1172```
1173
1174See Kotlin's
alanvf5ca4b92021-02-10 13:07:47 -08001175[opt-in requirements documentation](https://kotlinlang.org/docs/reference/opt-in-requirements.html)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001176for general usage information. If you are writing experimental Java APIs, you
1177will use the Jetpack
alanvf5ca4b92021-02-10 13:07:47 -08001178[`@RequiresOptIn` annotation](https://developer.android.com/reference/kotlin/androidx/annotation/RequiresOptIn)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001179rather than the Kotlin compiler's annotation.
1180
1181#### How to transition an API out of experimental
1182
1183When an API surface is ready to transition out of experimental, the annotation
1184may only be removed during an alpha pre-release stage since removing the
1185experimental marker from an API is equivalent to adding the API to the current
1186API surface.
1187
1188When transitioning an entire feature surface out of experimental, you *should*
1189remove the associated annotations.
1190
1191When making any change to the experimental API surface, you *must* run
1192`./gradlew updateApi` prior to uploading your change.
1193
1194### Restricted APIs {#restricted-api}
1195
1196Jetpack's library tooling supports hiding Java-visible (ex. `public` and
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001197`protected`) APIs from developers using a combination of the `@RestrictTo`
1198source annotation, and the `@hide` docs annotation (`@suppress` in Kotlin).
1199These annotations **must** be paired together when used, and are validated as
1200part of presubmit checks for Java code (Kotlin not yet supported by Checkstyle).
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001201
1202The effects of hiding an API are as follows:
1203
1204* The API will not appear in documentation
1205* Android Studio will warn the developer not to use the API
1206
1207Hiding an API does *not* provide strong guarantees about usage:
1208
1209* There are no runtime restrictions on calling hidden APIs
1210* Android Studio will not warn if hidden APIs are called using reflection
1211* Hidden APIs will still show in Android Studio's auto-complete
1212
1213#### When to use `@hide` {#restricted-api-usage}
1214
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001215In other cases, avoid using `@hide` / `@suppress`. These annotations indicates
1216that developers should not call an API that is _technically_ public from a Java
1217visibility perspective. Hiding APIs is often a sign of a poorly-abstracted API
1218surface, and priority should be given to creating public, maintainable APIs and
1219using Java visibility modifiers.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001220
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001221*Do not* use `@hide`/`@suppress` to bypass API tracking and review for
1222production APIs; instead, rely on API+1 and API Council review to ensure APIs
1223are reviewed on a timely basis.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001224
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001225*Do not* use `@hide`/`@suppress` for implementation detail APIs that are used
1226between libraries and could reasonably be made public.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001227
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001228*Do* use `@hide`/`@suppress` paired with `@RestrictTo(LIBRARY)` for
1229implementation detail APIs used within a single library (but prefer Java
1230language `private` or `default` visibility).
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001231
1232#### `RestrictTo.Scope` and inter- versus intra-library API surfaces {#private-api-types}
1233
1234To maintain binary compatibility between different versions of libraries,
1235restricted API surfaces that are used between libraries (inter-library APIs)
1236must follow the same Semantic Versioning rules as public APIs. Inter-library
1237APIs should be annotated with the `@RestrictTo(LIBRARY_GROUP)` source
1238annotation.
1239
1240Restricted API surfaces used within a single library (intra-library APIs), on
1241the other hand, may be added or removed without any compatibility
1242considerations. It is safe to assume that developers _never_ call these APIs,
1243even though it is technically feasible. Intra-library APIs should be annotated
1244with the `@RestrictTo(LIBRARY)` source annotation.
1245
1246The following table shows the visibility of a hypothetical API within Maven
1247coordinate `androidx.concurrent:concurrent` when annotated with a variety of
1248scopes:
1249
1250<table>
1251 <tr>
1252 <td><code>RestrictTo.Scope</code></td>
1253 <td>Visibility by Maven coordinate</td>
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001254 <td>Versioning</td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001255 </tr>
1256 <tr>
1257 <td><code>LIBRARY</code></td>
1258 <td><code>androidx.concurrent:concurrent</code></td>
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001259 <td>No compatibility gurantees (same as private)</td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001260 </tr>
1261 <tr>
1262 <td><code>LIBRARY_GROUP</code></td>
1263 <td><code>androidx.concurrent:*</code></td>
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001264 <td>Semantic versioning (including deprecation)</td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001265 </tr>
1266 <tr>
1267 <td><code>LIBRARY_GROUP_PREFIX</code></td>
1268 <td><code>androidx.*:*</code></td>
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001269 <td>Semantic versioning (including deprecation)</td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001270 </tr>
1271</table>
1272
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001273#### `@IntDef` `@StringDef` and `@LongDef` and visibility
1274
1275All `@IntDef`, `@StringDef`, and `@LongDef` will be stripped from resulting
1276artifacts to avoid issues where compiler inlining constants removes information
1277as to which `@IntDef` defined the value of `1`. The annotations are extracted
1278and packaged separately to be read by Android Studio and lint which enforces the
1279types in application code.
1280
1281* Libraries _must_ `@hide` all `@IntDef`, `@StringDef`, and `@LongDef`
1282 declarations.
1283* Libraries _must_ expose constants used to define the `@IntDef` etc at the
1284 same Java visibility as the hidden `@IntDef`
1285* Libraries _should_ also use @RestrictTo to create a warning when the type
1286 used incorrectly.
1287
1288Here is a complete example of an `@IntDef`
1289
1290```java
1291// constants match Java visibility of ExifStreamType
1292// code outside this module interacting with ExifStreamType uses these constants
1293public static final int STREAM_TYPE_FULL_IMAGE_DATA = 1;
1294public static final int STREAM_TYPE_EXIF_DATA_ONLY = 2;
1295
1296/** @hide */
1297@RestrictTo(RestrictTo.Scope.LIBRARY) // Don't export ExifStreamType outside module
1298@Retention(RetentionPolicy.SOURCE)
1299@IntDef({
1300 STREAM_TYPE_FULL_IMAGE_DATA,
1301 STREAM_TYPE_EXIF_DATA_ONLY,
1302})
1303public @interface ExifStreamType {}
1304```
1305
1306Java visibilty should be set as appropriate for the code in question (`private`,
1307`package` or `public`) and is unrelated to hiding.
1308
1309For more, read the section in
1310[Android API Council Guidelines](https://android.googlesource.com/platform/developers/docs/+/refs/heads/master/api-guidelines/index.md#no-public-typedefs)
1311
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001312### Constructors {#constructors}
1313
1314#### View constructors {#view-constructors}
1315
1316The four-arg View constructor -- `View(Context, AttributeSet, int, int)` -- was
1317added in SDK 21 and allows a developer to pass in an explicit default style
1318resource rather than relying on a theme attribute to resolve the default style
1319resource. Because this API was added in SDK 21, care must be taken to ensure
1320that it is not called through any < SDK 21 code path.
1321
1322Views _may_ implement a four-arg constructor in one of the following ways:
1323
13241. Do not implement.
13251. Implement and annotate with `@RequiresApi(21)`. This means the three-arg
1326 constructor **must not** call into the four-arg constructor.
1327
1328### Asynchronous work {#async}
1329
1330#### With return values {#async-return}
1331
1332Traditionally, asynchronous work on Android that results in an output value
1333would use a callback; however, better alternatives exist for libraries.
1334
1335Kotlin libraries should prefer
1336[coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) and
1337`suspend` functions, but please refer to the guidance on
1338[allowable dependencies](#dependencies-coroutines) before adding a new
1339dependency on coroutines.
1340
1341Java libraries should prefer `ListenableFuture` and the
1342[`CallbackToFutureAdapter`](https://developer.android.com/reference/androidx/concurrent/futures/CallbackToFutureAdapter)
1343implementation provided by the `androidx.concurrent:concurrent-futures` library.
1344
1345Libraries **must not** use `java.util.concurrent.CompletableFuture`, as it has a
1346large API surface that permits arbitrary mutation of the future's value and has
1347error-prone defaults.
1348
1349See the [Dependencies](#dependencies) section for more information on using
1350Kotlin coroutines and Guava in your library.
1351
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001352#### Cancellation
1353
1354Libraries that expose APIs for performing asynchronous work should support
1355cancellation. There are _very few_ cases where it is not feasible to support
1356cancellation.
1357
1358Libraries that use `ListenableFuture` must be careful to follow the exact
1359specification of
1360[`Future.cancel(boolean mayInterruptIfRunning)`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html?is-external=true#cancel-boolean-)
1361behavior.
1362
1363```java {.bad}
1364@Override
1365public boolean cancel(boolean mayInterruptIfRunning) {
1366 // Does not support cancellation.
1367 return false;
1368}
1369```
1370
1371```java {.bad}
1372@Override
1373public boolean cancel(boolean mayInterruptIfRunning) {
1374 // Aggressively does not support cancellation.
1375 throw new UnsupportedOperationException();
1376}
1377```
1378
1379```java {.good}
1380@Override
1381public boolean cancel(boolean mayInterruptIfRunning) {
1382 // Pseudocode that ignores threading but follows the spec.
1383 if (mCompleted
1384 || mCancelled
1385 || mRunning && !mayInterruptIfRunning) {
1386 return false;
1387 }
1388 mCancelled = true;
1389 return true;
1390}
1391```
1392
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001393#### Avoid `synchronized` methods
1394
1395Whenever multiple threads are interacting with shared (mutable) references those
1396reads and writes must be synchronized in some way. However synchronized blocks
1397make your code thread-safe at the expense of concurrent execution. Any time
1398execution enters a synchronized block or method any other thread trying to enter
1399a synchronized block on the same object has to wait; even if in practice the
1400operations are unrelated (e.g. they interact with different fields). This can
1401dramatically reduce the benefit of trying to write multi-threaded code in the
1402first place.
1403
1404Locking with synchronized is a heavyweight form of ensuring ordering between
1405threads, and there are a number of common APIs and patterns that you can use
1406that are more lightweight, depending on your use case:
1407
1408* Compute a value once and make it available to all threads
1409* Update Set and Map data structures across threads
1410* Allow a group of threads to process a stream of data concurrently
1411* Provide instances of a non-thread-safe type to multiple threads
1412* Update a value from multiple threads atomically
1413* Maintain granular control of your concurrency invariants
1414
1415### Kotlin {#kotlin}
1416
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001417#### Nullability from Java (new APIs)
1418
1419All new Java APIs should be annotated either `@Nullable` or `@NonNull` for all
1420reference parameters and reference return types.
1421
1422```java
1423 @Nullable
1424 public Object someNewApi(@NonNull Thing arg1, @Nullable List<WhatsIt> arg2) {
1425 if(/** something **/) {
1426 return someObject;
1427 } else {
1428 return null;
1429 }
1430```
1431
1432#### Nullability from Java (existing APIs)
1433
1434Adding `@Nullable` or `@NonNull` annotations to existing APIs to document their
1435existing nullability is OK. This is a source breaking change for Kotlin
1436consumers, and you should ensure that it's noted in the release notes and try to
1437minimize the frequency of these updates in releases.
1438
1439Changing the nullability of an API is a breaking change.
1440
1441#### Extending APIs that expose types without nullability annotations
1442
1443[Platform types](https://kotlinlang.org/docs/java-interop.html#null-safety-and-platform-types)
1444are exposed by Java types that do not have a `@Nullable` or `@NonNull`
1445annotation. In Kotlin they are indicated with the `!` suffix.
1446
1447When interacting with an Android platform API that exposes APIs with unknown
1448nullability follow these rules:
1449
14501. If wrapping the type in a new API, define and handle `@Nullable` or
1451 `@NonNull` in the library. Treat types with unknown nullability passed into
1452 or return from Android as `@Nullable` in the library.
14532. If extending an existing API (e.g. `@Override`), pass through the existing
1454 types with unknown nullability and annotate each with
1455 `@SuppressLint("UnknownNullness")`
1456
1457In Kotlin, a type with unknown nullability is exposed as a "platform type"
1458(indicated with a `!` suffix) which has unknown nullability in the type checker,
1459and may bypass type checking leading to runtime errors. When possible, do not
1460directly expose types with unknown nullability in new public APIs.
1461
1462#### Extending `@RecentlyNonNull` and `@RecentlyNullable` APIs
1463
1464Platform APIs are annotated in the platform SDK artifacts with fake annotations
1465`@RecentlyNonNull` and `@RecentlyNullable` to avoid breaking builds when we
1466annotated platform APIs with nullability. These annotations cause warnings
1467instead of build failures. The `RecentlyNonNull` and `RecentlyNullable`
1468annotations are added by Metalava and do not appear in platform code.
1469
1470When extending an API that is annotated `@RecentlyNonNull`, you should annotate
1471the override with `@NonNull`, and the same for `@RecentlyNullable` and
1472`@Nullable`.
1473
1474For example `SpannableStringBuilder.append` is annotated `RecentlyNonNull` and
1475an override should look like:
1476
1477```java
1478 @NonNull
1479 @Override
1480 public SpannableStringBuilder append(@SuppressLint("UnknownNullness") CharSequence text) {
1481 super.append(text);
1482 return this;
1483 }
1484```
1485
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001486#### Data classes {#kotlin-data}
1487
1488Kotlin `data` classes provide a convenient way to define simple container
1489objects, where Kotlin will generate `equals()` and `hashCode()` for you.
1490However, they are not designed to preserve API/binary compatibility when members
1491are added. This is due to other methods which are generated for you -
1492[destructuring declarations](https://kotlinlang.org/docs/reference/multi-declarations.html),
1493and [copying](https://kotlinlang.org/docs/reference/data-classes.html#copying).
1494
1495Example data class as tracked by metalava:
1496
1497<pre>
1498 public final class TargetAnimation {
1499 ctor public TargetAnimation(float target, androidx.animation.AnimationBuilder animation);
1500 <b>method public float component1();</b>
1501 <b>method public androidx.animation.AnimationBuilder component2();</b>
1502 <b>method public androidx.animation.TargetAnimation copy(float target, androidx.animation.AnimationBuilder animation);</b>
1503 method public androidx.animation.AnimationBuilder getAnimation();
1504 method public float getTarget();
1505 }
1506</pre>
1507
1508Because members are exposed as numbered components for destructuring, you can
1509only safely add members at the end of the member list. As `copy` is generated
1510with every member name in order as well, you'll also have to manually
1511re-implement any old `copy` variants as items are added. If these constraints
1512are acceptable, data classes may still be useful to you.
1513
1514As a result, Kotlin `data` classes are _strongly discouraged_ in library APIs.
1515Instead, follow best-practices for Java data classes including implementing
1516`equals`, `hashCode`, and `toString`.
1517
1518See Jake Wharton's article on
1519[Public API challenges in Kotlin](https://jakewharton.com/public-api-challenges-in-kotlin/)
1520for more details.
1521
1522#### Extension and top-level functions {#kotlin-extension-functions}
1523
1524If your Kotlin file contains any sybmols outside of class-like types
1525(extension/top-level functions, properties, etc), the file must be annotated
1526with `@JvmName`. This ensures unanticipated use-cases from Java callers don't
1527get stuck using `BlahKt` files.
1528
1529Example:
1530
1531```kotlin {.bad}
1532package androidx.example
1533
1534fun String.foo() = // ...
1535```
1536
1537```kotlin {.good}
1538@file:JvmName("StringUtils")
1539
1540package androidx.example
1541
1542fun String.foo() = // ...
1543```
1544
1545NOTE This guideline may be ignored for libraries that only work in Kotlin (think
1546Compose).
1547
1548## Testing Guidelines
1549
1550### [Do not Mock, AndroidX](do_not_mock.md)
1551
1552## Android Lint Guidelines
1553
1554### Suppression vs Baselines
1555
1556Lint sometimes flags false positives, even though it is safe to ignore these
1557errors (for example WeakerAccess warnings when you are avoiding synthetic
1558access). There may also be lint failures when your library is in the middle of a
1559beta / rc / stable release, and cannot make the breaking changes needed to fix
1560the root cause. There are two ways of ignoring lint errors:
1561
15621. Suppression - using `@SuppressLint` (for Java) or `@Suppress` annotations to
1563 ignore the warning per call site, per method, or per file. *Note
1564 `@SuppressLint` - Requires Android dependency*.
15652. Baselines - allowlisting errors in a lint-baseline.xml file at the root of
1566 the project directory.
1567
1568Where possible, you should use a **suppression annotation at the call site**.
1569This helps ensure that you are only suppressing the *exact* failure, and this
1570also keeps the failure visible so it can be fixed later on. Only use a baseline
1571if you are in a Java library without Android dependencies, or when enabling a
1572new lint check, and it is prohibitively expensive / not possible to fix the
1573errors generated by enabling this lint check.
1574
1575To update a lint baseline (lint-baseline.xml) after you have fixed issues, add
1576`-PupdateLintBaseline` to the end of your lint command. This will delete and
1577then regenerate the baseline file.
1578
1579```shell
1580./gradlew core:lintDebug -PupdateLintBaseline
1581```
1582
1583## Metalava API Lint
1584
1585As well as Android Lint, which runs on all source code, Metalava will also run
1586checks on the public API surface of each library. Similar to with Android Lint,
1587there can sometimes be false positives / intended deviations from the API
1588guidelines that Metalava will lint your API surface against. When this happens,
1589you can suppress Metalava API lint issues using `@SuppressLint` (for Java) or
1590`@Suppress` annotations. In cases where it is not possible, update Metalava's
1591baseline with the `updateApiLintBaseline` task.
1592
1593```shell
1594./gradlew core:updateApiLintBaseline
1595```
1596
1597This will create/amend the `api_lint.ignore` file that lives in a library's
1598`api` directory.
1599
1600## Build Output Guidelines
1601
1602In order to more easily identify the root cause of build failures, we want to
1603keep the amount of output generated by a successful build to a minimum.
1604Consequently, we track build output similarly to the way in which we track Lint
1605warnings.
1606
1607### Invoking build output validation
1608
1609You can add `-Pandroidx.validateNoUnrecognizedMessages` to any other AndroidX
1610gradlew command to enable validation of build output. For example:
1611
1612```shell
1613/gradlew -Pandroidx.validateNoUnrecognizedMessages :help
1614```
1615
1616### Exempting new build output messages
1617
1618Please avoid exempting new build output and instead fix or suppress the warnings
1619themselves, because that will take effect not only on the build server but also
1620in Android Studio, and will also run more quickly.
1621
1622If you cannot prevent the message from being generating and must exempt the
1623message anyway, follow the instructions in the error:
1624
1625```shell
1626$ ./gradlew -Pandroidx.validateNoUnrecognizedMessages :help
1627
1628Error: build_log_simplifier.py found 15 new messages found in /usr/local/google/workspace/aosp-androidx-git/out/dist/gradle.log.
1629
1630Please fix or suppress these new messages in the tool that generates them.
1631If you cannot, then you can exempt them by doing:
1632
1633 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
1634 2. modify the new lines to be appropriately generalized
1635```
1636
1637Each line in this exemptions file is a regular expressing matching one or more
1638lines of output to be exempted. You may want to make these expressions as
1639specific as possible to ensure that the addition of new, similar messages will
1640also be detected (for example, discovering an existing warning in a new source
1641file).
1642
1643## Behavior changes
1644
1645### Changes that affect API documentation
1646
1647Do not make behavior changes that require altering API documentation in a way
1648that would break existing clients, even if such changes are technically binary
1649compatible. For example, changing the meaning of a method's return value to
1650return true rather than false in a given state would be considered a breaking
1651change. Because this change is binary-compatible, it will not be caught by
1652tooling and is effectively invisible to clients.
1653
1654Instead, add new methods and deprecate the existing ones if necessary, noting
1655behavior changes in the deprecation message.
1656
1657### High-risk behavior changes
1658
1659Behavior changes that conform to documented API contracts but are highly complex
1660and difficult to comprehensively test are considered high-risk and should be
1661implemented using behavior flags. These changes may be flagged on initially, but
1662the original behaviors must be preserved until the library enters release
1663candidate stage and the behavior changes have been appropriately verified by
1664integration testing against public pre-release
1665revisions.
1666
1667It may be necessary to soft-revert a high-risk behavior change with only 24-hour
1668notice, which should be achievable by flipping the behavior flag to off.
1669
1670```java
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001671// Flag for whether to throw exceptions when the state is known to be bad. This
1672// is expected to be a high-risk change since apps may be working fine even with
1673// a bad state, so we may need to disable this as a hotfix.
1674private static final boolean FLAG_EXCEPTION_ON_BAD_STATE = false;
1675```
1676
1677```java
1678/**
1679 * Allows a developer to toggle throwing exceptions when the state is known to
1680 * be bad. This method is intended to give developers time to update their code.
1681 * It is temporary and will be removed in a future release.
1682 */
1683@TemporaryFeatureFlag
1684public void setExceptionOnBadStateEnabled(boolean enabled);
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001685```
1686
1687Avoid adding multiple high-risk changes during a feature cycle, as verifying the
1688interaction of multiple feature flags leads to unnecessary complexity and
1689exposes clients to high risk even when a single change is flagged off. Instead,
1690wait until one high-risk change has landed in RC before moving on to the next.
1691
1692#### Testing
1693
1694Relevant tests should be run for the behavior change in both the on and off
1695flagged states to prevent regressions.
1696
1697## Sample code in Kotlin modules
1698
1699### Background
1700
1701Public API can (and should!) have small corresponding code snippets that
1702demonstrate functionality and usage of a particular API. These are often exposed
1703inline in the documentation for the function / class - this causes consistency
1704and correctness issues as this code is not compiled against, and the underlying
1705implementation can easily change.
1706
1707KDoc (JavaDoc for Kotlin) supports a `@sample` tag, which allows referencing the
1708body of a function from documentation. This means that code samples can be just
1709written as a normal function, compiled and linted against, and reused from other
1710modules such as tests! This allows for some guarantees on the correctness of a
1711sample, and ensuring that it is always kept up to date.
1712
1713### Enforcement
1714
1715There are still some visibility issues here - it can be hard to tell if a
1716function is a sample, and is used from public documentation - so as a result we
1717have lint checks to ensure sample correctness.
1718
1719Primarily, there are three requirements when using sample links:
1720
17211. All functions linked to from a `@sample` KDoc tag must be annotated with
1722 `@Sampled`
17232. All sample functions annotated with `@Sampled` must be linked to from a
1724 `@sample` KDoc tag
17253. All sample functions must live inside a separate `samples` library
1726 submodule - see the section on module configuration below for more
1727 information.
1728
1729This enforces visibility guarantees, and make it easier to know that a sample is
1730a sample. This also prevents orphaned samples that aren't used, and remain
1731unmaintained and outdated.
1732
1733### Sample usage
1734
1735The follow demonstrates how to reference sample functions from public API. It is
1736also recommended to reuse these samples in unit tests / integration tests / test
1737apps / library demos where possible.
1738
1739**Public API:**
1740
1741```
1742/*
1743 * Fancy prints the given [string]
1744 *
1745 * @sample androidx.printer.samples.fancySample
1746 */
1747fun fancyPrint(str: String) ...
1748```
1749
1750**Sample function:**
1751
1752```
1753package androidx.printer.samples
1754
1755import androidx.printer.fancyPrint
1756
1757@Sampled
1758fun fancySample() {
1759 fancyPrint("Fancy!")
1760}
1761```
1762
1763**Generated documentation visible on d.android.com\***
1764
1765```
1766fun fancyPrint(str: String)
1767
1768Fancy prints the given [string]
1769
1770<code>
1771 import androidx.printer.fancyPrint
1772
1773 fancyPrint("Fancy!")
1774<code>
1775```
1776
1777\**still some improvements to be made to DAC side, such as syntax highlighting*
1778
1779### Module configuration
1780
1781The following module setups should be used for sample functions, and are
1782enforced by lint:
1783
1784**Group-level samples**
1785
1786For library groups with strongly related samples that want to share code.
1787
AndroidX Core Team0db91f02021-05-06 22:45:18 +00001788Gradle project name: `:foo-library:foo-library-samples`
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001789
1790```
1791foo-library/
1792 foo-module/
1793 bar-module/
1794 samples/
1795```
1796
1797**Per-module samples**
1798
1799For library groups with complex, relatively independent sub-libraries
1800
AndroidX Core Team0db91f02021-05-06 22:45:18 +00001801Gradle project name: `:foo-library:foo-module:foo-module-samples`
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001802
1803```
1804foo-library/
1805 foo-module/
1806 samples/
1807```
AndroidX Core Team0db91f02021-05-06 22:45:18 +00001808
1809**Samples module configuration**
1810
1811Samples modules are published to GMaven so that they are available to Android
1812Studio, which displays code in @Sample annotations as hover-over pop-ups.
1813
1814To achieve this, samples modules must declare the same MavenGroup and `publish`
1815as the library(s) they are samples for.