Android V2

Implementation Guide

The implementation of this SDK is extremely similar to the “old” Sensorberg Beacon SDK.

The SDK requires fine location permission, please refer to the official docs about Request App Permissions

Gradle configuration

Make sure you have set the sensorberg repository

allprojects {
    repositories {
        maven { url "https://maven.sensorberg.io/artifactory/smartspaces/" }
    }
}

and add the Sensorberg Notifications SDK as a dependency

implementation 'com.sensorberg.notifications:sdk:VERSION'

Initialise the SDK.

Initialise the SDK as a singleton during Application.onCreate()

notificationsSdk = NotificationsSdk
                        .with(this)             // the Application object
                        .setApiKey(KEY)         // required, the API key as registered on `portal.sensorberg.com` (or individual backend instance)
                        .setBaseUrl(BASE_URL)   // optional, use in case executing on a different backend instance
                        .enableHttpLogs()       // optional, only use for debugging
                        .build()                // build the instance of the SDK, keep it as a Singleton

It’s very important to be initialised as a singleton, multiple instances will not work.
It’s very important to be initialised during Application.onCreate(), because the SDK uses Services and BroadcastReceivers that can be executed without an Activity.
Be carefull with lazily injecting the NotificationsSDK!

Receiving Actions

Actions are delivered via BroadcastReceivers.

Create the BroadcastReceiver class

// Kotlin
class ActionReceiver : AbstractActionReceiver() {
    override fun onAction(context: Context, action: Action) {
        // action.subject, action.body, action.url, action.payload
    }
}

// Java
public class ActionReceiver extends AbstractActionReceiver {
	@Override public void onAction(@NotNull Context context, @NotNull Action action) {
		// action.getSubject(), action.getBody(), action.getUrl(), action.getPayload()
	}
}

Alternatively, one can use a direct instance of BroadcastReceivers and call the helper method to extract the action:

// Kotlin
val action = NotificationsSdk.extractAction(intent)

// Java
Action action = NotificationsSdk.Companion.extractAction(intent);

The Action class is Parcelable, which allows it to be passed to Intent/Bundle/etc.

Action.payload

Besides the basic action fields (subject/body/url) some of the backend meta-data is injected in the action JSON payload.

val jsonPayload = Json(action.payload)
/*
actionType can be: 1) notification 2) website 3) in-app 4) silent
actionTrigger can be: 1) enter 2) exit
*/
val actionType = jsonPayload.getInt('com.sensorberg.notifications.sdk.backend.v2.meta.action_type')
val actionTrigger = jsonPayload.getInt('com.sensorberg.notifications.sdk.backend.v2.meta.action_trigger')

Register the BroadcastReceiver on the manifest

Add the action receiver class to the manifest under the application tag as follows.

<receiver
    android:name=".ActionReceiver"
    android:exported="false">
    <intent-filter>
        <action android:name="com.sensorberg.notifications.sdk.ACTION_RECEIVER"/>
    </intent-filter>
</receiver>

Do not register more than once, only one will receive the action.

Conversion, advertisement-id, and attributes

  • Conversion

User conversion can be registered by calling the appropriate method on the SDK instance

// preferred way is to use the action object
notificationsSdk.setConversion(action, Conversion.Success)

// Alternatively, the action.instanceId can be used. Be sure to use the correct "id"
notificationsSdk.setConversion(action.instanceId, Conversion.Success)
  • advertisement-id and attributes

Backend filtering can be added to the SDK via advertisement-id and attributes by calling the appropriate methods on the SDK instance

// set advertisement ID
notificationsSdk.setAdvertisementId(adId) // ad-id could be, for example, from Google Play Service advertise ID

// set attributes
val attributes = mutableMapOf<String, String>()
attributes.put("age", "20_30")
attributes.put("locale", "de")
sdk.setAttributes(attributes
notificationsSdk.setAttributes(attributes)

Valid attributes are only alphanumerical characters and underscore.
Advertisement ID and attributes are stored internally and don’t need to be set every time.
Call the methods with null to clear them out.
When those parameters change, the SDK will soon synchronize the data with the backend.

Important differences from “old” Sensorberg Beacon SDK

  • The broadcast receiver has a new action name. If upgrading, make sure to update it.
  • The old SDK required a different process to execute, this is not the case anymore. If you’re upgrading to this SDK remove the process check from Application.onCreate() and from the broadcast receiver
  • It’s not necessary to register a background detector anymore.
  • This SDK optimizes for battery efficiency and does not scan all the time. Please refer to the testing guide below.

Internal working

This SDK operates by registering beacons, geofences and push notifications (soon) to Google Play Services to deliver one unified and battery efficient experience.

For recurrent operations (synchronize and upload data) and for delayed action delivery this SDK uses the WorkManager.
In case your application also uses WorkManager, remember than using workManager.cancelAllWork() will also cancel the operations scheduled for this SDK.

Caveats and known edge cases

Beacons Missed exit

Under a very specific rare case scenario there might be a lost exit event.
That is an extremely rare possibility that we could never reproduce, but nonetheless, it’s possible.

The order of events for this missed exit is:

  • syncronization and beacon registration happened normally sometime before
  • Google Play Services scans bluetooth and find “beacon A”
  • “beacon A” gets properly processed by the SDK and the action is executed
  • user walks away from “beacon A” area.
  • a new synchronization happens
  • cancellation of previous beacons on Google Play Services happen normaly
  • but registration for newly received beacons fail
  • even with future correct subscription on Google Play Services, it won’t receive the exit

To compensate for this case, this SDK allows for a repeated enter if more than 24 hours have passed since the last enter event.

Google Play Services Beacon Scanning

Google Play Services “assumes” a beacon is no longer visible, if it is not able to scan for anything.
That means any previously visible beacon will receive an exit event case:

  • bluetooth is turned off
  • location services is turned off
  • android device is being turned off

The same beacon will receive an enter event when the conditions for scanning are back and the beacon is scanned.
To compensate for this behavior from Google Play Services, this SDK postpone exit events by 3 minutes.
During processing of events if bluetooth is off, or location is off, the SDK will postpone the processing.
After bluetooth and location are on again, processing will occur and appropriate actions will be executed.

Geofences

Geofences have to re-registered with Google Play Services on certain situations.
One of those situations is when location services is turned off by the user.
But unfortunately there’s no reliable way on Android to detect when location services is turned on again.
Our SDK works around this by scheduling the re-registration of the fences with an exponential back off until the registration is successful.
That means the geofences will not be operational immediately after location services are turned on, but only after the scheduled registration executes.

Debugging

The SDK is logging information using Timber logger.
To see those logs simply plant a tree on Timber, e.g.: Timber.plant(new Timber.DebugTree()).
The optional builder parameter .enableHttpLogs() will enable all the HTTP communication logging on the VERBOSE level.

Testing Guide

After SDK is correctly integrated into the Android App and a campaign setup on the backend, the easiest way to test it is:

  • Open the app and make sure to accept the location permission for the application
  • Await a few seconds to make sure the data have been synchronized with the backend
  • After that the app can stay opened or be closed, it doesn’t matter

Beacons

  • Turn off the device screen
  • Insert battery in the beacon
  • Turn on the device screen
  • A broadcast should be sent in a few seconds if an “on_enter” action have been configured
  • Turn off the device screen
  • Remove the battery from the beacon
  • Turn on the device screen
  • A broadcast should be sent in about 3 minutes if an “on_exit” action have been configured

Geofences

Use a location mock app to “move the device” in and out of the geofenced area.
We’ve are using Mock GPS and it works well.