By Tim Judkins | Principal Engineer
PendingIntent.FLAG_IMMUTABLE
must be used. However, if this flag is used for pending intents with geofences, the broadcast receiver will not have the information it needs to parse the GeofencingEvent
from the intent. This article provides code snippets for fixing this. It is based on the Google Codelabs geofence example on github. At the time of writing this, the example had not been updated to target Android 12.
To update the codelabs example to work when targeting Android 12, a few things need to be done. First, update the app’s gradle to target and compile against SDK 31.
To update the codelabs example to work when targeting Android 12, a few things need to be done. First, update the app’s gradle to target and compile against SDK 31.
android {
compileSdkVersion 31
defaultConfig {
targetSdkVersion 31
...
}
}
We also recommend updating gradle and switch jcenter() to mavenCentral() in the root build.gradle.
buildscript {
ext.kotlin_version = '1.5.30'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
apply plugin: 'kotlin-android-extensions'
statement from the app build.gradle since it is no longer needed.
This will cause a few errors and warnings that need to be fixed before addressing the pending intent immutability flags. Add the and set the android:exported="true"
attribute for the main activity in the AndroidManifest.xml.
Now, we need to address the pending intent immutability. For the geofence pending intent, we need to explicitly tell the OS that this pending intent can be modified by adding PendingIntent.FLAG_MUTABLE
. Since this flag is only supported on SDK31 and higher, we’ll need to do the following in the HuntMainActivity
.
private val geofencePendingIntent: PendingIntent by lazy {
val intent = Intent(this, GeofenceBroadcastReceiver::class.java)
intent.action = ACTION_GEOFENCE_EVENT
// Use FLAG_UPDATE_CURRENT so that you get the same pending intent back when calling
// addGeofences() and removeGeofences().
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
} else {
PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
}
@SuppressLint("UnspecifiedImmutableFlag")
The notification pending intent that is created in the NotificationUtils.kt
file needs the PendingIntent.FLAG_IMMUTABLE
since this intent should not be modified. To do so, update the sendGeofenceEnteredNotification
method as follows (note the PendingIntent.FLAG_IMMUTABLE
flag was introduced in SDK23):
@SuppressLint("UnspecifiedImmutableFlag")
fun NotificationManager.sendGeofenceEnteredNotification(context: Context, foundIndex: Int) {
val contentIntent = Intent(context, HuntMainActivity::class.java)
contentIntent.putExtra(GeofencingConstants.EXTRA_GEOFENCE_INDEX, foundIndex)
val contentPendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.getActivity(
context,
NOTIFICATION_ID,
contentIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
} else {
PendingIntent.getActivity(
context,
NOTIFICATION_ID,
contentIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
}
// … the rest of the method is the same
}
While it’s not clear from the documentation that geofence pending intents need to be mutable, hopefully this will help developers avoid issues when using geofences on Android 12. A fork of the codelabs examples with these changes is available at https://github.com/RadiusNetworks/android-kotlin-geo-fences
Flybuy Notify
Brands leverage Flybuy Notify to send proximity-triggered notifications to their app users as they approach and/or enter a store. Flybuy Notify can prompt loyalty and rewards, send special offers, and push mobile ordering when a customer is nearing a point of interest. Learn more about Flybuy Notify.
About the Flybuy Platform
Radius Networks is a location technology company that helps companies save time for customers and staff by streamlining operations and the user experience. The Flybuy SaaS platform is leveraged by restaurants, retailers, hospitality, and grocers around the world and includes: Flybuy Pickup for curbside, delivery, and in-store pickup; Flybuy Pay for mobile payment optimization; Flybuy Drive-Thru for loyalty identification and offer redemption; and Flybuy Tableside for innovative dine-in experiences.