iBeacons scanning in Android

tudip-logo

Tudip

20 March 2020

iBeacons scanning in Android

Introduction:

Beacons are the Wireless Bluetooth Transmitters that transmit a small amount of data to connect to the devices Nearby. Beacons support Bluetooth Technology. Beacons transmit data to a range of approximately 70 meters.  Beacons are also used to get accurate location information. Beacons transmit data at regular intervals through Radio waves. Beacons are classified into different types based on the Beacon Protocol and location Technology.

Based on the Beacon Protocol, Beacons are classified into the following types:

  1. iBeacon (Apple)
  2. Eddystone (Google)
  3. AltBeacon (Radius Networks)
  4. GeoBeacon (Tecno-World)

iBeacon:

 iBeacons are invented by Apple and it is the first beacon protocol. It works in both ios and Android. Unlike ios, there is no Native support in Android. Since there is no Native implementation we need to integrate either the existing Library or create code that parses BLE packets to find the iBeacons. 

iBeacon UUID: 

UUID is the standard identifying system that generates the unique number for each device. It is used to distinguish the other iBeacons in a Network. iBeacon UUID consists of 32 hexadecimal digits which are splitted into 5 groups. Each group is separated from the other using the “-”. Some examples of valid iBeacon UUIDs:     

         FDA50693-A4E2-4FB1-AFCF-C6EB07647823

         FDA50693-A4E2-4FB1-AFCF-C6EB07647825

        12345609-uiof-cchh-abcd-1122aabb2160  

AltBeacon Library for scanning iBeacons in Android:

  Library version:

    implementation ‘org.altbeacon:android-beacon-library:2+’

Permissions:

We must request 2 Permissions from the user for connecting with Beacon:

  1. Bluetooth Permission
  2. Location Permission

The following permissions must be specified in the Manifest file:

    <uses-permission android:name = “android.permission.BLUETOOTH” />

    <uses-permission android:name = “android.permission.BLUETOOTH_ADMIN” />

    <uses-permission android:name = “android.permission.ACCESS_COARSE_LOCATION” />

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

    <uses-permission android:name =     “android.permission.ACCESS_BACKGROUND_LOCATION” />

  • Bluetooth Permission:

Android by default provides the Bluetooth Permission. We need to request the Bluetooth Permission Programmatically  using the requestPermission method. Before requesting Bluetooth Permission we need to check for whether Bluetooth is supported in the device or not.

    BluetoothAdapter bluetoothAdapter= BluetoothAdapter.getDefaultAdapter();

    if (bluetoothAdapter != null) {

           // Device support Bluetooth

    } else {

         // Device doesn’t support Bluetooth

    }

For enabling the Bluetooth:

If (!bluetoothAdapter.isEnabled()) {

       Intent bluetoothIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

       startActivityForResult(bluetoothIntent , REQUEST_ENABLE_BLUETOOTH);

    }

A popup displays requesting a user to enable Bluetooth. If the user clicks on Yes, then the system begins to enable Bluetooth.

  • Location Permission:

While requesting the Location Permission at runtime, there are 2 cases to consider:

  1. For TargetSDK =29 or higher

 If the Android version is greater than 9  then we need to request the Finelocation and BackgroundLocation permission from the user. To request the FineLocation and BackgroundLocation Permission we need to use requestPermission method.

     requestPermissions(new String[] {Manifest.permission.ACCESS_FINE_LOCATION, 
 
   Manifest.permission.ACCESS_BACKGROUND_LOCATION}, PERMISSION_REQUEST_LOCATION);

Once the Permissions are granted or denied the onRequestPermission is called and we need to add a check to know whether permission is granted or not, using the PackageManager. PERMISSION_GRANTED.

  1. For Target SDK = 23 to 28

If the Android version is above 6 and below 9 then we need to request the CoarseLocation Permission from the user. To request the CoarseLocation we need to specify the COARSE_LOCATION in requestPermission

    requestPermissions(new String[] {Manifest.permission.ACCESS_COARSE_LOCATION},

   PERMISSION_REQUEST_COARSE_LOCATION);

We need to override the onRequestPermissionResult method to know whether Location Permission is granted or not.

Binding the Beacon Service:

Before Binding the Beacon Service we need to implement the class with BeaconConsumer. Once we implement the BeaconConsumer we need to override the onBeaconServiceConnect method.

Binding BeaconService-

We need to create an instance of BeaconManger before binding the BeaconService.

    BeaconManager beaconManager = BeaconManager.getInstanceForApplication(this);   

    beaconManager.getBeaconParsers().add(new  BeaconParser().setBeaconLayout
("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));   

    beaconManager.bind(this);         

Ranging and Monitoring the Beacons:

 We need to declare the Region for the Beacons to scan and we need to pass the region for Ranging and Monitoring the Beacons.

Region:

The region is characterized by the same three values as beacons: UUID, Major, and Minor. Therefore, Region is also defined as the range of all beacons in this region.

Syntax:

    Region region = new BeaconRegion(region, UUID, major, minor);

For scanning all the Beacons in the Region, we need to declare Region as:

    Region region = new BeaconRegion(“region”, null, null, null);

For scanning any Particular beacon we need to declare region as,

    Region region = new BeaconRegion(“region”, Identifier.Parse(UUID), null, null);

Monitoring and RangingBeacons:

      Monitoring helps to detect movement in and out of range of the beacons, Ranging gives a list of beacons in range, along with the estimated proximity to each of them.

    beaconManager.startMonitoringBeaconsInRegion(region); //Monitoring

    beaconManager.startRangingBeaconsInRegion(region);  //Ranging

After enabling the Ranging or Monitoring of BeaconManager the onBeaconServiceConnect method is called in every one second.

In onBeaconServiceConnect we need to set the MonitorNotifier and RangeNotifier to know the Beacons Range and to get the Beacons List.

    @override

    public void onBeaconServiceConnect() {     

      beaconManager.setMonitorNotifier(new MonitorNotifier() {

      @override

       public void didEnterRegion(Region region) {      

              //  Called when Beacons are detected

       }  

      @override

       public void didExitRegion(Region region) {     

            //  Called when beacons are not in the Region specified

       }

      @override    

      public void didDetermineStateForRegion(int i, Region region) {     

           // Called when the beacons are visible in the Region 

      }

  });  

       beaconManager.setRangeNotifier(new RangeNotifier() {

       @override

           public void didRangeBeaconsInRegion(Collection beacons, Region region) {

           if (beacons.size() > 0) {

               Identifier beaconId = beacons.iterator().next().getId1(); // Gets Connected Beacon Id

               Double beaconDistance = beacons.iterator().next().getDistance(); // Beacon Distance

           }      

        }

    });

}

Unbindinding Beacon Service:

      It is important to Unbind the Beacon Service after completing the process so that the scanning can be stopped in Background. If we start the scanning process in an Activity then we can unbind in the onDestroy method.

      if (beaconManager != null) { 

          beaconManager.unbind(this); 

          beaconManager.removeAllRangeNotifiers();    

          beaconManager.removeAllMonitorNotifiers();

          beaconManager.stopMonitoringBeaconsInRegion(mBeaconRegion);

          beaconManager.stopRangingBeaconsInRegion(mBeaconRegion);

      }

    

Request a quote