House advertise the availability and rates of their driveways, So your phone could scan for them and query all of them and book the one that makes more sense for you in a completely offline fashion.Taking it one step further, if you are late getting back, why can’t these houses then query your car, which will tell them that you are just a block away, so I can avoid being penalized or towed.Because implementing these features entails dealing with the vagaries of Bluetooth and Wi-Fi across the product, the range of Android os version out there and the variety of hardware out there.What these apps back then needed was a reliable performance proximity platform that abstracts away all this complexity and leaves them free so they can focus on just adding the features that matter to their users.
Nearby Connections API
Nearby Connections enables advertising and discovery of nearby devices, as well as high-bandwidth low-latency encrypted data transfers between these devices in a fully-offline P2P manner.It achieves this by using a combination of classic Bluetooth, BLE, and Wi-Fi hotspots.It leverages the strengths of each while supplementing their respective weaknesses.For instance, Bluetooth has low connection latency but also provides low bandwidth Wi-Fi hotspots have slightly higher connection latency, but also provide much higher bandwidth. So what it does is connect over Bluetooth and start transferring data instantly but in the background, it also brings up a Wi-Fi hotspot and when that’s ready, it seamlessly transfers your connection from Bluetooth to WiFi with absolutely no work required by the app developer.
Nearby API Flow
1.An advertiser calls startAdvertising()
, and sometime later, a discover calls startDiscovery()
. Soon enough, the discovery is alerted to the advertiser’s presence by means of the onEndpointFound()
callback. If the discoverer is interested, they can call requestConnection()
.This is the end of the asymmetric part of the API and from here on everything is completely symmetric.
2.Both sides get an onConnectionInitiated()
callback that gives them an authentication token they can use to verify they are indeed talking to each other.Upon out-of-band verification, they can both either call acceptConnection()
or rejectConnection()
.When each side gets the other’s response, it invokes the ConnectionLifecycleCallback.onConnectionResult()
callback.At this point, the connection is either established or it’s not.
3.From here, either side can send payload by calling the sendPayload()
method.This leads to the other side getting the PayloadCallback.onPayloadReceived()
callback, followed by both sides getting a series of PayloadCallback.onPayloadTransferUpdate()
callbacks up until the transfer reaches the final state of success or failure.
4.Finally, either side can disconnect at any time, and that leads to the other side getting the ConnectionLifecycleCallback.onDisconnected()
callback.
Payload
Nearby API support three kinds of payloads 1.Bytes, these are byte arrays of up to 32k, and they are typically used for sending metadata control messages.
2.Files, these represent files of the device’s storage and Nearby API make sure that it transfer from the application to the network interface with a minimal amount of copying across process boundaries.
3.Streams, this is good for when you need to generate data on the fly, and you don’t know the final size up front, as is the case with recorded audio or video.
Strategies
As I mentioned earlier, Nearby API uses multiple radio techniques to advertise, discover, and establish connections.The combinations of interactions of these techniques are qualified in its strategies.Strategies are named for how far they’ll cause their net to try and find a nearby device and what kind of connection topology they will enable.Right now, it has two of them, P2P_STAR
and P2P_CLUSTER
.
As the name might suggest, P2P_STAR
makes sense for when you want to enforce a star network with a 1-to-N connection topology.And P2P_CLUSTER
make sense when you want to allow for slightly looser M-to-M connection topologies.For example, a classroom app where the teacher wants to host a quiz for all the students, that would probably be best mounted over P2P_STAR
with the teacher as the one advertiser and the students at the end discovers and the same classroom app could have a mode that allows students to break out into ephemeral project groups.This mode,where students want to drift in and out of multiple groups,would be best served with P2P_CLUSTER
.
Now let’s see how all this can be put together in an undoubtedly harmless mock application.
Get Started
Before you start to code using the Nearby Connections API:
- Install the Google Play Services SDK.
dependencies { compile 'com.google.android.gms:play-services-nearby:11.8.0' }
Request Permissions
Before using Nearby Connections, your app must request the appropriate permissions for the Strategy you plan to use.
For example, in order to use the P2P_STAR
Strategy, add the specified permissions to your AndroidManifest.xml
:
<!-- Required for Nearby Connections --> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Since ACCESS_COARSE_LOCATION
is considered to be a dangerous system permission, in addition to adding it to your manifest, you must request the permission at runtime, as described in Requesting Permissions.
Advertise and Discover
Your app needs to begin to advertise and discover in order to find nearby devices.
1.On devices that will advertise, call startAdvertising()
with the desired Strategy
and a serviceId
parameter that identifies your app.
2.On devices that will discover nearby advertisers, call startDiscovery()
with the same Strategy
and serviceId
.
The serviceId
value must uniquely identify your app. As a best practice, use the package name of your app (for example, com.example.myapp
).
The following example shows how to advertise:
// Our handle to Nearby Connections private ConnectionsClient connectionsClient; connectionsClient = Nearby.getConnectionsClient(this); private void startAdvertising() { Nearby.getConnections(context).startAdvertising( getUserNickname(), SERVICE_ID, mConnectionLifecycleCallback, new AdvertisingOptions(STRATEGY)) .addOnSuccessListener( new OnSuccessListener<Void>() { @Override public void onSuccess(Void unusedResult) { // We're advertising! } }) .addOnFailureListener( new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // We were unable to start advertising. } }); }
The ConnectionLifecycleCallback
parameter is the callback that will be invoked when discoverers request to connect to the advertiser.
The following example shows how to discover:
private final EndpointDiscoveryCallback mEndpointDiscoveryCallback = new EndpointDiscoveryCallback() { @Override public void onEndpointFound( String endpointId, DiscoveredEndpointInfo discoveredEndpointInfo) { // An endpoint was found! } @Override public void onEndpointLost(String endpointId) { // A previously discovered endpoint has gone away. } }; private void startDiscovery() { Nearby.getConnections(context).startDiscovery( SERVICE_ID, mEndpointDiscoveryCallback, new DiscoveryOptions(STRATEGY)) .addOnSuccessListener( new OnSuccessListener<Void>() { @Override public void onSuccess(Void unusedResult) { // We're discovering! } }) .addOnFailureListener( new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // We were unable to start discovering. } }); }
Call stopAdvertising()
when you no longer need to advertise.
CallstopDiscovery()
when you no longer need to discover.
Initiate a connection
When nearby devices are found, the discoverer can initiate connections. The following example shows initiating a connection with a discovered device.
@Override public void onEndpointFound( String endpointId, DiscoveredEndpointInfo discoveredEndpointInfo) { Nearby.getConnections(context).requestConnection( getUserNickname(), endpointId, mConnectionLifecycleCallback) .addOnSuccessListener( new OnSuccessListener<Void>() { @Override public void onSuccess(Void unusedResult) { // We successfully requested a connection. Now both sides // must accept before the connection is established. } }) .addOnFailureListener( new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Nearby Connections failed to request the connection. } }); }
Depending on your use case, you may wish to instead display a list of discovered devices to the user, allowing them to choose which devices to connect to.
Accept or reject a connection
After the discoverer has requested a connection to an advertiser, both sides are notified of the connection initiation process via the onConnectionInitiated()
method of the ConnectionLifecycleCallback
callback. Note that this callback is passed in to startAdvertising()
on the advertiser and requestConnection()
on the discoverer, but from this point forward, the API is symmetric.
Now both sides must choose whether to accept or reject the connection via a call to acceptConnection()
or rejectConnection()
, respectively. The connection is fully established only when both sides have accepted. If one or both reject, the connection is discarded. Either way, the result is delivered toonConnectionResult()
.
The following code snippet shows how to implement this callback:
private final ConnectionLifecycleCallback mConnectionLifecycleCallback = new ConnectionLifecycleCallback() { @Override public void onConnectionInitiated( String endpointId, ConnectionInfo connectionInfo) { // Automatically accept the connection on both sides. Nearby.getConnections(context).acceptConnection(endpointId, mPayloadCallback); } @Override public void onConnectionResult(String endpointId, ConnectionResolution result) { switch (result.getStatus().getStatusCode()) { case ConnectionsStatusCodes.STATUS_OK: // We're connected! Can now start sending and receiving data. break; case ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED: // The connection was rejected by one or both sides. break; case ConnectionsStatusCodes.STATUS_ERROR: // The connection broke before it was able to be accepted. break; } } @Override public void onDisconnected(String endpointId) { // We've been disconnected from this endpoint. No more data can be // sent or received. } };
Exchange Data
Once connections are established between devices, you can exchange data by sending and receiving Payload
objects. A Payload
can represent a simple byte array, such as a short text message; a file, such as a photo or video; or a stream, such as the audio stream from the device’s microphone.
Payloads of the same type are guaranteed to arrive in the order they were sent, but there is no guarantee of preserving the ordering amongst payloads of different types. For example, if a sender sends a FILE
payload followed by a BYTE
payload, the receiver could get the BYTE
payload first, followed by the FILE
payload.
Send and Receive
To send payloads to a connected endpoint, call sendPayload()
.To receive payloads, implement the onPayloadReceived()
method of the PayloadCallback
that was passed to acceptConnection()
.
connectionsClient.sendPayload( opponentEndpointId, Payload.fromBytes(choice.name().getBytes(UTF_8))); // Callbacks for receiving payloads private final PayloadCallback payloadCallback = new PayloadCallback() { @Override public void onPayloadReceived(String endpointId, Payload payload) { } @Override public void onPayloadTransferUpdate(String endpointId, PayloadTransferUpdate update) { } };
Here are the slightly less bone-chilling uses of nearby Connections spotted in the wild.
The Weather channel is using Nearby Connections to build a pretty darn cool offline mesh to help spread urgent weather updates and warnings, especially in the wake of natural disasters.
Sendanywhere is a South Korean app that allows sharing files intelligently in the most efficient manner possible, regardless of whether you’re online or not.They’re using Nearby Connections for their offline modality.
Pocket Casts have been a great partner for Nearby Messages.They now want to enable people sharing and discovering podcasts in a completely offline manner. For example, when you’re stuck in an aircraft and are looking to cloud so what’s your options for entertainment?
GameInsight is a leading game developer, and they’re using Nearby Connections to not only find nearby players but also to run their games completely offline. Again, being stuck in the inside of an aircraft comes to mind.
Hotstar is India’s fastest growing streaming network.They’re using nearby connections to allow offline sharing of downloaded movies and TV shows.So you don’t need to have access to the internet.You only need access to friend who does.
Android TV is about to launch a new remote control app where they use Nearby Connections to not only set up your new Android TV and configure it to be on your Wi-Fi network, but also to serve interactive second stream content in a streaming fashion.