Location and geofences
Geofences are only available in select Braze packages. For access, create a support ticket or speak with your Braze customer success manager.
To support geofences for Android:
- Your integration must support background push notifications.
- Braze geofences or location collection must be enabled.
Step 1: Update build.gradle
Add android-sdk-location
to your app-level build.gradle
. Also, add the Google Play Services location package using the Google Play Services setup guide:
1
2
3
4
dependencies {
implementation "com.braze:android-sdk-location:+"
implementation "com.google.android.gms:play-services-location:${PLAY_SERVICES_VERSION}"
}
Step 2: Update the manifest
Add boot, fine location, and background location permissions to your AndroidManifest.xml
:
1
2
3
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
The background location access permission was added in Android 10 and is required for Geofences to work while the app is in the background for all Android 10+ devices.
Add the Braze boot receiver to the application
element of your AndroidManifest.xml
:
1
2
3
4
5
<receiver android:name="com.braze.BrazeBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Step 3: Enable Braze location collection
If you have not yet enabled Braze location collection, update your braze.xml
file to include com_braze_enable_location_collection
and confirm its value is set to true
:
1
<bool name="com_braze_enable_location_collection">true</bool>
Starting with Braze Android SDK version 3.6.0, Braze location collection is disabled by default.
Braze geofences are enabled if Braze location collection is enabled. If you would like to opt-out of our default location collection but still want to use geofences, it can be enabled selectively by setting the value of key com_braze_geofences_enabled
to true
in braze.xml
, independently of the value of com_braze_enable_location_collection
:
1
<bool name="com_braze_geofences_enabled">true</bool>
Step 4: Obtain location permissions from the end user
For Android M and higher versions, you must request location permissions from the end user before gathering location information or registering geofences.
Add the following call to notify Braze when a user grants the location permission to your app:
1
Braze.getInstance(context).requestLocationInitialization();
1
Braze.getInstance(context).requestLocationInitialization()
This will cause the SDK to request geofences from Braze servers and initialize geofence tracking.
See RuntimePermissionUtils.java
in our sample application for an example implementation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class RuntimePermissionUtils {
private static final String TAG = BrazeLogger.getBrazeLogTag(RuntimePermissionUtils.class);
public static final int DROIDBOY_PERMISSION_LOCATION = 40;
public static void handleOnRequestPermissionsResult(Context context, int requestCode, int[] grantResults) {
switch (requestCode) {
case DROIDBOY_PERMISSION_LOCATION:
// In Android Q, we require both FINE and BACKGROUND location permissions. Both
// are requested simultaneously.
if (areAllPermissionsGranted(grantResults)) {
Log.i(TAG, "Required location permissions granted.");
Toast.makeText(context, "Required location permissions granted.", Toast.LENGTH_SHORT).show();
Braze.getInstance(context).requestLocationInitialization();
} else {
Log.i(TAG, "Required location permissions NOT granted.");
Toast.makeText(context, "Required location permissions NOT granted.", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
private static boolean areAllPermissionsGranted(int[] grantResults) {
for (int grantResult : grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
object RuntimePermissionUtils {
private val TAG = BrazeLogger.getBrazeLogTag(RuntimePermissionUtils::class.java!!)
val DROIDBOY_PERMISSION_LOCATION = 40
fun handleOnRequestPermissionsResult(context: Context, requestCode: Int, grantResults: IntArray) {
when (requestCode) {
DROIDBOY_PERMISSION_LOCATION ->
// In Android Q, we require both FINE and BACKGROUND location permissions. Both
// are requested simultaneously.
if (areAllPermissionsGranted(grantResults)) {
Log.i(TAG, "Required location permissions granted.")
Toast.makeText(context, "Required location permissions granted.", Toast.LENGTH_SHORT).show()
Braze.getInstance(context).requestLocationInitialization()
} else {
Log.i(TAG, "Required location permissions NOT granted.")
Toast.makeText(context, "Required location permissions NOT granted.", Toast.LENGTH_SHORT).show()
}
else -> {
}
}
}
private fun areAllPermissionsGranted(grantResults: IntArray): Boolean {
for (grantResult in grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
return false
}
}
return true
}
}
Using the preceding sample code is done via:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
boolean hasAllPermissions = PermissionUtils.hasPermission(getApplicationContext(), Manifest.permission.ACCESS_BACKGROUND_LOCATION)
&& PermissionUtils.hasPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION);
if (!hasAllPermissions) {
// Request both BACKGROUND and FINE location permissions
requestPermissions(new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION},
RuntimePermissionUtils.DROIDBOY_PERMISSION_LOCATION);
}
} else {
if (!PermissionUtils.hasPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION)) {
// Request only FINE location permission
requestPermissions(new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
RuntimePermissionUtils.DROIDBOY_PERMISSION_LOCATION);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val hasAllPermissions = PermissionUtils.hasPermission(applicationContext, Manifest.permission.ACCESS_BACKGROUND_LOCATION)
&& PermissionUtils.hasPermission(applicationContext, Manifest.permission.ACCESS_FINE_LOCATION)
if (!hasAllPermissions) {
// Request both BACKGROUND and FINE location permissions
requestPermissions(arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION),
RuntimePermissionUtils.DROIDBOY_PERMISSION_LOCATION)
}
} else {
if (!PermissionUtils.hasPermission(applicationContext, Manifest.permission.ACCESS_FINE_LOCATION)) {
// Request only FINE location permission
requestPermissions(arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
RuntimePermissionUtils.DROIDBOY_PERMISSION_LOCATION)
}
}
}
Step 5: Enable geofences on the dashboard
Android only allows up to 100 geofences to be stored for a given app. Braze locations products will use up to 20 geofence slots if available. To prevent accidental or unwanted disruption to other geofence-related functionality in your app, location geofences must be enabled for individual apps on the dashboard.
For Braze locations products to work correctly, confirm that your app is not using all available geofence spots.
Enable geofences from the locations page
Enable geofences from the settings page
Step 6: Manually request geofence updates (optional)
By default, Braze automatically retrieves the device’s location and requests geofences based on that collected location. However, you can manually provide a GPS coordinate that will be used to retrieve proximal Braze geofences instead. To manually request Braze Geofences, you must disable automatic Braze geofence requests and provide a GPS coordinate for requests.
Part 1: Disable automatic geofence requests
Automatic Braze geofence requests can be disabled in your braze.xml
file by setting com_braze_automatic_geofence_requests_enabled
to false
:
1
<bool name="com_braze_automatic_geofence_requests_enabled">false</bool>
This can additionally be done at runtime via:
1
2
3
BrazeConfig.Builder brazeConfigBuilder = new BrazeConfig.Builder()
.setAutomaticGeofenceRequestsEnabled(false);
Braze.configure(getApplicationContext(), brazeConfigBuilder.build());
1
2
3
val brazeConfigBuilder = BrazeConfig.Builder()
.setAutomaticGeofenceRequestsEnabled(false)
Braze.configure(applicationContext, brazeConfigBuilder.build())
Part 2: Manually request Braze geofence with GPS coordinate
Braze Geofences are manually requested via the requestGeofences()
method:
1
Braze.getInstance(getApplicationContext()).requestGeofences(latitude, longitude);
1
Braze.getInstance(applicationContext).requestGeofences(33.078947, -116.601356)
Geofences can only be requested once per session, either automatically by the SDK or manually with this method.
Push to sync
Note that Braze syncs geofences to devices using background push. In most cases, this will involve no code changes, as this feature requires no further integration on the part of the app.
However, note that if your application is stopped, receiving a background push will launch it in the background and its Application.onCreate()
method will be called. If you have a custom Application.onCreate()
implementation, you should defer automatic server calls and any other actions you would not want to be triggered by background push.