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();

 

Leave a Reply