Nearby Connections is a peer-to-peer networking API that allows apps to easily
discover, connect to, and exchange data with nearby devices in real-time,
regardless of network connectivity. The API is located in the
Some example use cases:
- Collaborative whiteboard: Jot ideas down with nearby participants on a shared virtual whiteboard.
- Local multiplayer gaming: Set up a multiplayer game and invite other users nearby to join.
- Multi-screen gaming: Use a phone or tablet as a game controller to play games displayed on a nearby large-screen Android device, such as Android TV.
- Offline file transfers: Share photos, videos, or any other type of data quickly and without requiring a network connection.
Nearby Connections enables advertising, discovery, and connections between nearby devices in a fully-offline peer-to-peer manner. Connections between devices are high-bandwidth, low-latency, and fully encrypted to enable fast, secure data transfers.
A primary goal of this API is to provide a platform that is simple, reliable, and performant. Under the hood, the API uses a combination of Bluetooth, BLE, and Wifi hotspots, leveraging the strengths of each while circumventing their respective weaknesses. This effectively abstracts the vagaries of Bluetooth and Wifi across a range of Android OS versions and hardware, allowing developers to focus on the features that matter to their users.
As a convenience, users are not prompted to turn on Bluetooth or Wifi — Nearby Connections enables these features as they are required, and restores the device to its prior state once the app is done using the API, ensuring a smooth user experience.
Usage of the API falls into two phases: pre-connection, and post-connection.
In the pre-connection phase, Advertisers advertise themselves, while Discoverers discover nearby Advertisers and send connection requests. A connection request from a Discoverer to an Advertiser initiates a symmetric authentication flow that results in both sides independently accepting (or rejecting) the connection request.
After a connection request is accepted by both sides, the connection is considered to be established and the devices enter the post-connection phase, during which both sides can exchange data.
Advertising and Discovery
Advertisers begin by invoking
startAdvertising(), passing in a
ConnectionLifecycleCallback which will be notified whenever a Discoverer wants
to connect via the
Discoverers begin by invoking
startDiscovery(), passing in an
EndpointDiscoveryCallback which will be notified whenever a nearby Advertiser
is found via the
When a Discoverer wishes to connect to a nearby Advertiser, the Discoverer
requestConnection(), passing in a
ConnectionLifecycleCallback of its
Both sides are then notified of the connection initiation process via the
ConnectionLifecycleCallback.onConnectionInitiated() callback, and both must
now choose whether to accept or reject the connection via a call to
At this point, apps can optionally prompt the user to accept the connection. See Authenticate a connection to learn more.
Once both sides have responded, each will be notified of the result via the
ConnectionLifecycleCallback.onConnectionResult() callback. If both sides
accepted the connection, then the
ConnectionResolution provided in the
callback will be successful, the connection is considered established, and the
transfer of Payloads can then begin.
After a connection is established, further API usage is symmetrical, so there’s no longer a distinction between Advertiser and Discoverer.
Both sides can now exchange data as
Payload objects. There are 3 types of
BYTESByte arrays limited to 32k; these are good for sending things such as metadata or control messages.
FILEFiles of any size; these are transferred from the app to the network interface with minimal copying across process boundaries.
STREAMA stream of data that is generated on the fly, as in the case of recorded audio/video, with no final size known beforehand.
Senders use the
sendPayload() method to send a Payload. This method can be
invoked multiple times, but since we guarantee in-order delivery, the second
Payload onwards will be queued for sending until the first Payload is done.
Receivers can expect the
PayloadCallback.onPayloadReceived() callback to be
invoked when a new incoming Payload is received.
Senders and Receivers both can expect the
PayloadCallback.onPayloadTransferUpdate() callback to be invoked to update
them about the progress of outgoing and incoming Payloads, respectively.
The connections established are full-duplex, which means that Advertisers and Discoverers can simultaneously send and receive Payloads.
disconnectFromEndpoint() disconnects from a particular remote
stopAllEndpoints() disconnects from all connected endpoints.
Remote endpoints are notified of disconnection via the