← Back to Blogs

Android

Nearby Connection API

InnovationM Admin 16 Feb 2021 4 min read
Nearby Connection API

Nearby connections is a peer-to-peer networking API that allows apps to easily connect, discover and exchange data with the nearby device in real-time, regardless of network connectivity. In other words, we can say that Nearby connections enable advertising, discovery and connection between nearby devices in a fully offline peer-to-peer manner. The connection between devices is high-bandwidth, low-latency and fully encrypted to enable fast, secure data transfers. Nearby connections API uses a combination of Bluetooth, BLE and wifi hotspots.

Nearby Connection API implementations

We implement nearby connections API in two phases:

  1. Pre-Connection
  2. Post-Connection

In the pre-connection phase, the Advertiser device advertises itself, while discovers devices search the nearby advertiser devices 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.

How to advertise the device?

Advertisers begin by invoking startAdvertising(), passing in a ConnectionLifecycleCallback which will be notified whenever a Discoverer wants to connect via the onConnectionInitiated() callback.

How to discover devices?

Discoverers begin by invoking startDiscovery(), passing in an EndpointDiscoveryCallback which will be notified whenever a nearby Advertiser is found via the onEndpointFound() callback.

Steps for implementing Nearby Connection API:

There are following steps for implementing nearby connection API as follows:

1. Add dependency for nearby connections

dependencies {

implementation 'com.google.android.gms:play-services-nearby:17.0.0'

}

2. Add permission in Manifest.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" />

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- Optional: only required for FILE payloads -->

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

3. Advertise the advertiser devices

Task<Void> startAdvertisingResultPendingResult =

       Nearby.getConnectionsClient(context)

               .startAdvertising(userName, AppConstant.SERVICE_ID,

               connectionLifeCycleCallback, new AdvertisingOptions.Builder().setStrategy(Strategy.P2P_STAR).build());

startAdvertisingResultPendingResult.addOnSuccessListener(new OnSuccessListener<Void>() {

   @Override

   public void onSuccess(Void aVoid) {

   }

});

startAdvertisingResultPendingResult.addOnFailureListener(new OnFailureListener() {

   @Override

   public void onFailure(@NonNull Exception e) {

   }

});

4. Discover the advertiser devices

Task<Void> statusPendingResult =

       Nearby.getConnectionsClient(context).

               startDiscovery(AppConstant.SERVICE_ID, 

                     new endPointDiscoverCallback,

        new DiscoveryOptions.Builder().setStrategy(Strategy.P2P_STAR).build());

statusPendingResult.addOnSuccessListener(new OnSuccessListener<Void>() {

   @Override

   public void onSuccess(Void aVoid) {

   }

});

statusPendingResult.addOnFailureListener(new OnFailureListener() {

   @Override

   public void onFailure(@NonNull Exception e) {

   }

});

5. Create a connectionLifecycleCallback class

private final ConnectionLifecycleCallback connectionLifecycleCallback =

    new ConnectionLifecycleCallback () {   

   @Override

   public void onConnectionInitiated(final String endpointId, final ConnectionInfo connectionInfo) {      

   }

   @Override

   public void onConnectionResult(String endpointId, ConnectionResolution connectionResolution) {

      switch (connectionResolution.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;

          default:

            // Unknown status code

        }

   }   

   @Override

   public void onDisconnected(String endPointId) {

   }

}

6. Create a EndPointDiscoveryCallback

private final EndpointDiscoveryCallbacks endPointDiscoverCallback = 

    new EndpointDiscoveryCallback() {   

   @Override

   public void onEndpointFound(final String endpointId, final DiscoveredEndpointInfo discoveredEndpointInfo) {

       // An endpoint was found!

Task<Void> statusPendingResult =

       Nearby.getConnectionsClient(context).

               requestConnection(userName, endpointId

                       , connectionLifecycleCallback);

   }

   @Override

   public void onEndpointLost(String endpointId) {      

   }

}

7. Requesting to create a connection

Task<Void> statusPendingResult =

       Nearby.getConnectionsClient(context).

               requestConnection(userName, endpointId

                       , connectionLifecycleCallback);

8. Accepting a connection request

Nearby.getConnectionsClient(CachingManager.getAppContext())

       .acceptConnection(endpointId, genericPayloadCallback)

       .addOnSuccessListener(new OnSuccessListener<Void>() {

           @Override

           public void onSuccess(Void aVoid) {

           }

       })

       .addOnFailureListener(new OnFailureListener() {

           @Override

           public void onFailure(@NonNull Exception e) {                                                 

           }

       });

9. For rejecting the connection request

Nearby.getConnectionsClient(context).rejectConnection(endpointId))

10. For sending the data to the endpoint

Nearby.getConnectionsClient(context)

.sendPayload(endPoints,payload)

.addOnSuccessListener(resultCallback)

.addOnFailureListener(failureListener);

11. For receiving the data

protected class ReceiveBytesPayloadListener extends PayloadCallback {

  @Override

  public void onPayloadReceived(String endpointId, Payload payload) {

    // This always gets the full data of the payload. Will be null if it's not a BYTES

    // payload. You can check the payload type with payload.getType().

    byte[] receivedBytes = payload.asBytes();

  }

  @Override

  public void onPayloadTransferUpdate(String endpointId, PayloadTransferUpdate update) {

    // Bytes payloads are sent as a single chunk, so you'll receive a SUCCESS update immediately

    // after the call to onPayloadReceived().

  }

}

12. To stop all endpoints

Nearby.getConnectionsClient(context).stopAllEndpoints();

13. To disconnect from the endpoint

Nearby.getConnectionsClient(context).disconnectFromEndpoint(endpoint);

14. For stop advertising

Nearby.getConnectionsClient(context).stopAdvertising();

15. To stop discovering

Nearby.getConnectionsClient(context).stopDiscovery();

 

About the Author
InnovationM Admin

Contributor at InnovationM.

LinkedIn

We don't
predict
the future.
We build what
comes next.

Share your goals, challenges, or ideas, we'll help you turn them into scalable digital solutions.