blob: eb657774ee4877ac1440c7b7dea2c4ee15d1cfab [file] [log] [blame] [view] [edit]
# Android API Guidelines
This document is intended to be a guide for developers to understand the general
principles that the API Council enforces in API reviews.
In addition to following these guidelines when writing APIs, developers should
run the [API Lint](#apilint) tool, which encodes many of these rules in checks
that it runs against APIs.
Think of this as the guide to the rules that are obeyed by that Lint tool, plus
general advice on rules that cannot be easily codified into that tool.
[TOC]
## API Lint tool {#apilint}
[API Lint](https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:tools/metalava/src/main/java/com/android/tools/metalava/ApiLint.kt)
is integrated into the Metalava static analysis tool and runs as part of the
platform build. You can run it manually from an
[AOSP platform checkout](https://source.android.com/setup/build/downloading)
using `m checkapi`. To run the tool from a Jetpack checkout, run the `./gradlew
checkApi` task.
## API rules {#rules}
One of the difficulties in concrete rules is applying them to a platform that
was developed without strict guidelines from the beginning, so some of the
existing APIs may not adhere. In some cases, the right choice might be to go
with what is consistent with APIs in the same general area of the code, rather
than in the ideal rules laid out herein.
The rules are a work in progress and will be added to in the future as other
patterns emerge from future API reviews.
## API basics <a name="basics"></a>
This category pertains to the core aspects of an Android API.
### All APIs must be implemented <a name="basics-implemented"></a>
Irrespective of an API's audience (public, `@SystemApi`, etc.), all API surfaces
must be implemented when merged or exposed as API. Merging API stubs with
implementation to come at a later date would be a violation of this guideline.
Unimplemented API surfaces have multiple issues:
- There is no guarantee that a proper or complete surface has been exposed.
Until an API is tested or used by clients, there is no way to verify a
client has the appropriate APIs to be able to use the feature.
- APIs without implementation cannot be tested in Developer Previews
- APIs without implementation cannot be tested in CTS
- By definition, APIs without implementation are not IC complete
### All APIs must be tested <a name="basics-tested"></a>
This is in line with CTS requirements and implementation expectation.
Testing API surfaces provides a base guarantee that the API surface is usable
and we've exposed all the necessary aspects. Testing for existence is not
sufficient; the API functionality itself must be tested.
A change that adds a new API should include corresponding CTS tests in the same
Gerrit topic. This is enforced by go/api-test-coverage presubmit.
APIs should also be *testable*. You should be able to answer the question, "How
will an app developer test code that uses your API?"
### All APIs must be documented <a name="basics-documented"></a>
Documentation is a key part of API usability. While the syntax of an API surface
may seem obvious, any new clients will not understand the semantics, behavior,
or context behind the API.
### All platform APIs must be associated with a flag <a name="basics-flagged"></a>
All platform APIs must be associated with a
[feature flag](http://go/android-flags) using the
[@FlaggedApi annotation][flaggedapi].
[flaggedapi]: https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:frameworks/libs/modules-utils/java/android/annotation/FlaggedApi.java?q=symbol%3A%5Cbandroid.annotation.FlaggedApi%5Cb%20case%3Ayes
Note: For FAQ on API flagging, please visit
[FAQ on API Flagging](/api-guidelines/faq.md)
page.
### All generated APIs must be compliant with the guidelines <a name="basics-auto-generated-code"></a>
APIs generated by tools must follow the API guidelines just the same as
hand-written code.
Tools that are discouraged for generating APIs:
- `AutoValue`: violates guidelines in various ways, e.g., there is no way to
implement final value classes nor final builders with the way AutoValue
works.
- [codegen](http://go/android-codegen):
[does not work well with `@FlaggedApi`](https://g3doc.corp.google.com/api-guidelines/faq.md#i-cannot-use-flaggedapi-with-data-classes-generated-by-codegen)
## Coding style [S] <a name="style"></a>
This category pertains to the general coding style that developers should use,
especially in the public API.
### Follow standard Java coding conventions, except where noted <a name="style-conventions"></a>
Android's platform coding conventions are documented for external contributors
here:
https://source.android.com/source/code-style.html
Overall, we tend to follow standard Java coding conventions.
Please also review the
[Kotlin-Java interop guide](https://developer.android.com/kotlin/interop) for
best practices related to writing Kotlin-friendly APIs in Java. Some of these
guidelines are reflected in the recommendations on this site; however, the link
may contain slightly newer information that has not yet been propagated.
### Acronyms should not be capitalized in method names <a name="acronyms-in-method-name"></a>
For example: method name should be `runCtsTests` and not `runCTSTests`.
### Names shouldn't end with `Impl` <a name="dont-end-with-impl"></a>
This exposes implementation details, avoid that.
<!--#include file="/api-guidelines/classes.md"-->
<!--#include file="/api-guidelines/methods.md"-->
<!--#include file="/api-guidelines/docs.md"-->
<!--#include file="/api-guidelines/framework.md"-->
## Services <a name="services"></a>
### Handling `Intent`s in system-bound developer services <a name="services-intents"></a>
Services that are intended to be extended by the developer and bound by the
system, for example abstract services like `NotificationListenerService`, may
respond to an `Intent` action from the system. Such services should meet the
following criteria:
1. Define a `SERVICE_INTERFACE` string constant on the class containing the
fully-qualified class name of the service. This constant must be annotated
with `@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)`.
1. Document on the class that a developer must add an `<intent-filter>` to
their `AndroidManifest.xml` in order to receive Intents from the platform.
1. Strongly consider adding a system-level permission to prevent rogue apps
from sending `Intent`s to developer services.
## Kotlin-Java interop <a name="kotin-interop"></a>
See the official Android
[Kotlin-Java interop guide](https://developer.android.com/kotlin/interop) for a
full list of guidelines. Select guidelines have been copied to this guide to
improve discoverability.
### API visibility
Some Kotlin APIs, like `suspend fun`s, aren't intended to be used by Java
developers; however, *do not* attempt to control language-specific visibility
using `@JvmSynthetic` as it has side-effects on how the API is presented in
debuggers that make debugging more difficult.
Please see the
[Kotlin-Java interop guide](https://developer.android.com/kotlin/interop) or
[Async guide](/api-guidelines/async.md) for
specific guidance.
### Companion objects
Kotlin uses `companion object` to expose static members. In some cases, these
will show up from Java on an inner class named `Companion` rather than on the
containing class. `Companion` classes may show as empty classes in API text
files -- that is working as intended.
To maximize compatibility with Java, annotate companion objects'
[non-`const` fields](https://developer.android.com/kotlin/interop#companion_constants)
with `@JvmField` and
[public functions](https://developer.android.com/kotlin/interop#companion_functions)
with `@JvmStatic` to expose them directly on the containing class.
```kotlin {.good .no-copy}
companion object {
@JvmField val BIG_INTEGER_ONE = BigInteger.ONE
@JvmStatic fun fromPointF(pointf: PointF) {
/* ... */
}
}
```
<!--#include file="/api-guidelines/evolution.md"-->
## XML schemas <a name="xml"></a>
If an XML schema serves as a stable interface between components, that schema
must be explicitly specified and must evolve in a backward-compatible manner,
similar to other Android APIs. For example, the structure of XML elements and
attributes must be preserved similar to how methods and variables are maintained
on other Android API surfaces.
NOTE API Council does not explicitly review XML schemas and AOSP does not have
tooling to automatically ensure compatibility for XML schemas or parsing.
Proceed with caution.
### Deprecation best-practices <a name="xml-deprecation"></a>
If you'd like to deprecate an XML element or attribute, you can add the
`xs:annotation` marker, but you must continue to support any existing XML files
by following the typical `@SystemApi` evolution lifecycle.
```xml {.no-copy}
<xs:element name="foo">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string">
<xs:annotation name="Deprecated"/>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
```
### Element types must be preserved <a name="xml-element-types"></a>
Schemas support the `sequence` element, `choice` element and `all` elements as
child elements of `complexType` element. However, these child elements differ in
the number and order of their child elements, so modifying an existing type
would be an incompatible change.
If you want to modify an existing type, the best-practice is to deprecate the
old type and introduce a new type to replace it.
```xml {.no-copy}
<!-- Original "sequence" value -->
<xs:element name="foo">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string">
<xs:annotation name="Deprecated"/>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- New "choice" value -->
<xs:element name="fooChoice">
<xs:complexType>
<xs:choice>
<xs:element name="name" type="xs:string"/>
</xs:choice>
</xs:complexType>
</xs:element>
```
<!--#include file="/api-guidelines/mainline.md"-->