blob: 94def054e7b22d34fa44fb58026de0dc521ca6d9 [file] [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 automatically
during validation in CI. You can run it manually from a local
[platform checkout](https://source.android.com/setup/build/downloading) using `m
checkapi` or a local AndroidX checkout using
`./gradlew :path:to:project:checkApi`.
## API rules {#rules}
The Android platform and many Jetpack libraries existed before this set of
guidelines was created, and the policies set forth below are continually
evolving to meet the needs of the Android ecosystem.
As a result, some existing APIs may not follow the guidelines. In other cases,
it might provide a better user experience for app developers if a new API stays
consistent with existing APIs rather than strictly adhere to the guidelines.
Use your judgement and reach out to API Council if there are difficult questions
about an API that need to be resolved or guidelines that need to be updated.
## 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. Do not merge API stubs with
implementation to come at a later date.
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 platform CTS requirements, AndroidX policies, and generally
the idea that APIs must be implemented.
Testing API surfaces provides a base guarantee that the API surface is usable
and we have addressed expected use cases. Testing for existence is not
sufficient; the API functionality itself must be tested.
A change that adds a new API should include corresponding tests in the same CL
or Gerrit topic. This is enforced in the platform 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 generated APIs must be compliant with the guidelines <a name="basics-auto-generated-code"></a>
APIs generated by tools must follow the same API guidelines 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.
## Coding style <a name="style"></a>
This category pertains to the general coding style that developers should use,
especially when writing public APIs.
### Follow standard coding conventions, except where noted <a name="style-conventions"></a>
Android coding conventions are documented for external contributors here:
https://source.android.com/source/code-style.html
Overall, we tend to follow standard Java and Kotlin coding conventions.
### 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 {#kotlin-interop-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-interop-companion}
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.
### XML deprecation <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"-->