Android Setup

Location and Proximity

The Location module brings Rover-powered geofence monitoring, Bluetooth Low Energy beacon monitoring, and general location tracking to your app, when your users grant location permission. This allows you to automate Rover, triggering on geographic events.


Initialization

By default, the Location module enables all three (geofences, beacon monitoring, and location tracking) by default. However, you can opt in or out by setting parameters on LocationAssembler as follows:

Rover.initialize(
    // ...,
    LocationAssembler(
        automaticGeofenceMonitoring = true,
        automaticBeaconMonitoring = true,
        automaticLocationTracking = true
    )
)

Requesting Permissions from your User

You then need, at an appropriate moment in your product’s user flow, prompt users to choose whether or not to grant your app ongoing location permission. You will use the Android permissions framework to do this.

On newer versions of Android, users will receive peridoic privacy reminders and are able to revoke the location permission at any time. Your app will need to account for reduced location accuracy as well as location permission only being granted while the app is open. It may be also be necessary to add a permission check in more than one area: for instance, if you include it in a shown-only-once on boarding area, it may be necessary to add it to your 'Home' screen as well. This is to gracefully handle any changes in the permission granted to your app, for example if the user decides to clean up the apps allowed to access their location in their system-wide privacy settings.

In order to track geofences and beacons, background location and fine location permissions are required. If the background location permission is not granted, geofences and beacons will not be tracked in the background. If fine location permission is not granted, geofences and beacons will not work. In addition, there are limits on location permissions in the background, outlined here. These limits must be taken into account.

Background location permission is optional if beacons and geofences are not used in your app. Coarse location permission alone is sufficent for segmenting users based on location..

Declare ACCESS_COARSE_LOCATION permission in app's mainfest. ACCESS_BACKGROUND_LOCATION and ACCESS_FINE_LOCATION can be added if your app requires geofence and beacon support:

<manifest ... >
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  <!-- Other permissions are optional. -->
  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>

Create a helper method for prompting for permission and override the Android callback template method onRequestPermissionsResult:

import android.Manifest
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import io.rover.sdk.core.Rover

private fun makePermissionsAttempt() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION),
                0
            )
    } else {
        // Permission has already been granted
        Rover.shared?.resolveSingletonOrFail(PermissionsNotifierInterface::class.java)?.permissionGranted(
            Manifest.permission.ACCESS_FINE_LOCATION
        )
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            Rover.shared?.resolveSingletonOrFail(PermissionsNotifierInterface::class.java)?.permissionGranted(
                Manifest.permission.ACCESS_BACKGROUND_LOCATION
            )
        } else {
            ActivityCompat.requestPermissions(this,
                arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION), 0
            )
        }
    }
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    val perms = permissions.zip(grantResults.toList()).associate { it }
    if(perms[Manifest.permission.ACCESS_FINE_LOCATION] == PackageManager.PERMISSION_GRANTED) {
        Rover.shared?.resolveSingletonOrFail(PermissionsNotifierInterface::class.java)?.permissionGranted(
            Manifest.permission.ACCESS_FINE_LOCATION
        )
    }
    if(perms[Manifest.permission.ACCESS_BACKGROUND_LOCATION] == PackageManager.PERMISSION_GRANTED) {
        Rover.shared?.resolveSingletonOrFail(PermissionsNotifierInterface::class.java)?.permissionGranted(
            Manifest.permission.ACCESS_BACKGROUND_LOCATION
        )
    }
}

Then you can call makePermissionsAttempt at the appropriate point in your user flow.

Rover will remember that the permission was granted across app restarts and will gracefully handle the permission being removed, but it remains prudent to continue checking each time from your main home screen or somewhere similarly appropriate.

More details on how to properly handle requesting app permissions can be found in the Android documentation: Request App Permissions.

Previous
Inbox