Geofences and iBeacons

With Accengage, you are able to trigger notifications based on your users real-time location, as they enter (or exit) a specific zone, even if the application is closed and the device locked.

Real-time notifications based on beacons or geofencing can be setup thanks to Scheduled Alarms or In-App Messages within the Accengage dashboard (Actions > Scheduled Alarms (or In-App messages) > Triggers)

In order to benefit from these features, the Accengage library provides two location-aware technologies : Geofences and iBeacons.

To get more information about Geofencing and iBeacons, you can also check out User Guide

Principles

The Geofencing uses the GPS, and doesn't need any hardware deployment, which is making it very easy and quick to setup.

The iBeacons, however, use Bluetooth devices but allow to locate your users even more precisely, and are perfect for indoor targeting. You can send them personalized Push Notifications in the right context.

If you want to discover Geofencing, a sample is available on Github: https://github.com/urbanairship/accengage-android-sdk-samples/tree/master/AccGeofences

And for the iBeacons too : https://github.com/urbanairship/accengage-android-sdk-samples/tree/master/AccBeacons

Take advantage of geolocation to broadcast messages based on users' real-time location data. The library provides two location-aware technologies: Geofencing and Beacons.

Permissions

For the Geofences, the geolocation permission is already asked in the Plugin Google Play Services so it's not necessary to write it again in the AndroidManifest.

For the iBeacons, the Bluetooth permission is already asked in the plugin, but if for some reasons you don't use our iBeacons plugin, you need to use Bluetooth permissions :

AndroidManifest.xml

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

Geofences

To get to know more about Geofencing check out the User Guide.

Integration

To integrate Geofencing, add the dependency for  google-play-services-geofence  to your app-level build.gradle  file:

implementation('com.ad4screen.sdk:plugin-play-services-geofence:x.y.z')

Retrieve Geofences from BroadcastReceiver

Each time a user enters or exits a geofence zone defined in the Accengage User Interface, your app may receive their specific information (like latitude, longitude, etc).

Create a BroadcastReceiver

To receive them, you should first create a BroadcastReceiver: 

GeofenceReceiver.java

public class GeofenceReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle bundle = intent.getExtras();
        Bundle geofenceData = bundle.getBundle(Constants.EXTRA_GEOFENCE_PAYLOAD);

        //Retrieve ids of geofences triggered
        String[] geofencesIds = geofenceData.getStringArray("ids");
        //Retrieve transition code (1 == enter, 0 == exit)
        int transitionCode = geofenceData.getInt("transition");

        //Retrieve the geolocation that has triggered these geofences
        //(Note : you will have to parse it as a JSONObject)
        //Keys are : provider, latitude, longitude, altitude, accuracy, bearing, speed, time
        String location = geofenceData.getString("triggeringLocation");

        //Do anything you want, for example : start an activity..
    }
}

Modify your AndroidManifest.xml

Now, we have to add our “GeofenceReceiver” class to the AndroidManifest.xml in order to allow the SDK to trigger it when needed:

AndroidManifest.xml

<receiver
    android:name="my-package.GeofenceReceiver"
    android:permission="yourpackage.permission.A4S_SEND">
    <intent-filter>
        <action android:name="com.ad4screen.sdk.intent.action.TRIGGER" />
        <category android:name="com.ad4screen.sdk.intent.category.GEOFENCE_NOTIFICATIONS" />
    </intent-filter>
</receiver>

Retrieving Geofences from ContentProvider

Since version 3.5.0 geofences can be retrieved from ContentProvider using A4SContract with specified URI. The code snippet instantiating a CursorLoader is shown below:

From version 3.5.0

private static final String[] PROJECTION = {
        A4SContract.Geofences._ID,
        A4SContract.Geofences.SERVER_ID,
        A4SContract.Geofences.EXTERNAL_ID,
        A4SContract.Geofences.NAME,
        A4SContract.Geofences.LATITUDE,
        A4SContract.Geofences.LONGITUDE,
        A4SContract.Geofences.RADIUS,
        A4SContract.Geofences.DETECTED_TIME,
        A4SContract.Geofences.NOTIFIED_TIME,
        A4SContract.Geofences.DETECTED_COUNT,
        A4SContract.Geofences.DEVICE_LATITUDE,
        A4SContract.Geofences.DEVICE_LONGITUDE,
        A4SContract.Geofences.DISTANCE
};

@Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
    mSortingField = getGeofenceSortingField();
    Log.debug("GeofencesFragment|onCreateLoader sorting by " + mSortingField);
    switch (loaderId) {
        case URL_LOADER:
            return new CursorLoader(getActivity(),
                    A4SContract.Geofences.getContentUri(getContext()), PROJECTION,
                    null, null, mSortingField);
        default:
            return null;
    }
}

For more details please see A4SGeofences sample (v3.5.0 is required) allowing to list geofences and sort them by name, distance, radius, detected count,... in ascending/descending order.

  

Region monitoring

This functionality allows you to customize the number of geofence regions that would be monitored by the SDK. It’s useful if you have your own geofences to supervise. Note that by default the SDK monitors all the 100 regions allowed by Android system, and in these 100 regions, 1 region is inevitably dedicated to the global monitoring.

From version 3.8.0

 A4S.get(context).setMonitoredRegionCount(35);

Here you can see the current number of regions monitored by the SDK.

From version 3.8.0

A4S.get(context).getMonitoredRegionCount(new A4S.Callback<Integer>() {
    @Override
    public void onResult(Integer result) {
        // result : current value of Region monitored
    }

    @Override
    public void onError(int error, String errorMessage) {
        // handle error
    }
});

Sample

A sample is available on Github: https://github.com/urbanairship/accengage-android-sdk-samples/tree/master/AccGeofences

iBeacons

Beacons are Bluetooth Low Energy  (BLE) devices that broadcast their identifier to nearby portable electronic devices using iBeacon protocol.

The beacon technology enables you to deliver hyper-contextual content based on location, whether it is indoor or outdoor. These small bluetooth proximity sensors communicate with mobile devices to locate users from a few centimeters to a 30-meter radius.

Before using the beacon service, make sure that all of your beacon devices share the same UUID.

To be able to listen to beacons and trigger specific actions, like displaying an InApp message or scheduling Local Notifications,  by detecting a programmed beacon you need to use Beacons plugin.

Don't forget to add the Bluetooth permissions in your AndroidManifest, look at the section Permissions for more details.

Integration

To integrate Beacons, add the dependency for Beacons to your app-level build.gradle file:

implementation 'com.ad4screen.sdk:A4SSDK-Plugin-Beacons:x.y.z'

If your application has a min-sdk prior to 18, you will have this error:

> Manifest merger failed : uses-sdk:minSdkVersion 9 cannot be smaller than version 18 declared in library [:A4SSDK-Plugin-Beacons-1.2.0:]
    Suggestion: use tools:overrideLibrary="com.ad4screen.sdk.plugins.beacons" to force usage

You can safely add the line in your AndroidManifest.xml (inside tag) to ignore minSdkVeirsion:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          package="your-app-package">
 
    <uses-sdk tools:overrideLibrary="com.ad4screen.sdk.plugins.beacons" />
 
</manifest>

Retrieving Beacon information with a BroadcastReceiver

Each time our SDK detects a beacon defined on the Accengage dashboard, your app may receive their specific information.

Create a BroadcastReceiver

To receive them, you should first create a BroadcastReceiver: 

BeaconReceiver.java

public class BeaconReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        //This receiver will be called each time one or more beacons are detected.
        //This means that this method could be triggered at a maximum rate of once every 10 seconds

        //Retrieve the bundle containing detected beacons
        Bundle beacons = bundle.getBundle(Constants.EXTRA_BEACON_PAYLOAD);

        //Get and process each beacon
        Set<String> triggeredBeacons = beacons.keySet();
        for (String beaconId : triggeredBeacons) {
            Bundle beaconDetails = beacons.getBundle(beaconId);
            //Transition
            int transition = beaconDetails.getInt("transition") == 1 ? "Enter":"Exit";
            //A4S Beacon Id
            //(unique for each beacon but can be null if we were not able to identify this beacon, please do not rely only on it)
            String id = beaconDetails.getString("id");
            //UUID (Can be shared between multiple beacons)
            String uuid = beaconDetails.getString("uuid");
            //Major
            int maj = beaconDetails.getInt("maj");
            //Minor
            int min = beaconDetails.getInt("min");

            //You should distinguish each beacon using UUID + MAJOR + MINOR

            //Distance in meters
            Double distance = beaconDetails.getDouble("dist");
            //Accuracy. Can be : unknown,far,near or immediate
            String accuracy = beaconDetails.getString("acc");

            //Do things
        }
    }
}

Modify your AndroidManifest.xml

Now, we have to add our “BeaconReceiver” class to the AndroidManifest.xml in order to allow the SDK to trigger it when needed:

AndroidManifest.xml

<receiver
    android:name=".BeaconReceiver"
    android:permission="com.ad4screen.coffeesample.internal.permission.A4S_SEND" >
    <intent-filter>
        <action android:name="com.ad4screen.sdk.intent.action.TRIGGER" />
        <category android:name="com.ad4screen.sdk.intent.category.BEACON_NOTIFICATIONS" />
    </intent-filter>
</receiver>