Geofence in Android

Kaushal Vasava
9 min readJun 2, 2024

--

I will give you information about Geofence, implementation in android, testing, best practices, use-cases and example project.

What is Geofence?

Geofencing uses your current location and your proximity to specific places to create virtual boundaries, or “fences,” around areas of interest. To set up a geofence, you specify a location using its latitude and longitude, and you set a radius to define the size of the fenced area.

You can have up to 100 active geofences per app, per user. For each geofence, you can request notifications when someone enters or exits the area. You can also set a wait time before triggering an event after entering the geofence. Additionally, you can set a time limit for how long the geofence should remain active. Once this time limit expires, the geofence is automatically removed.

ENTER: It is used to detect when entering into geofence area.

DWELL: It is used to check how much time you spend in the geofence area

EXIT: It is used to detect when you leave geofence area.

Set up for geofence monitoring

The first step in requesting geofence monitoring is to request the necessary permissions. To use geofencing, your app must request the following:

To learn more, see the guide on how to request location permissions.

If you want to use a BroadcastReceiver to listen for geofence transitions, add an element specifying the service name. This element must be a child of the <application> element:

<application
android:allowBackup="true">
...
<receiver
android:name=".GeofenceBroadcastReceiver"
android:enabled="true"
android:exported="true"/>
<application/>

To access the location APIs, you need to create an instance of the Geofencing client. To learn how to connect your client:

lateinit var geofencingClient: GeofencingClient
override fun onCreate(savedInstanceState: Bundle?) {
// ...
geofencingClient = LocationServices.getGeofencingClient(this)
}

Create and add geofences

To create and add geofences in your Android app, follow these steps using the location API’s builder class:

  1. Define Geofences: Use the builder class to create geofence objects.
  2. Add Geofences: Use the convenience class to add geofences to the app.
  3. Handle Geofence Transitions: Define a PendingIntent to manage the intents sent from Location Services when geofence transitions occur.

Note: On single-user devices, there is a limit of 100 geofences per app. For multi-user devices, the limit is 100 geofences per app per device user.

Create geofence objects

First, use Geofence.Builder to create a geofence, setting the desired radius, duration, and transition types for the geofence. For example, to populate a list object:

val geofence = Geofence.Builder()
// Set the request ID of the geofence. This is a string to identify this
// geofence.
.setRequestId(requestId)

// Set the circular region of this geofence.
.setCircularRegion(
latitude,
longitude,
Constants.GEOFENCE_RADIUS_IN_METERS
)

// Set the expiration duration of the geofence. This geofence gets automatically
// removed after this period of time.
.setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)

// Set the transition types of interest. Alerts are only generated for these
// transition. We track entry and exit transitions in this sample.
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT)

// Create the geofence.
.build()

geofenceList.add(geofence)

Specify geofences and initial triggers

The following snippet uses the GeofencingRequest class and its nested GeofencingRequestBuilder class to specify the geofences to monitor and to set how related geofence events are triggered:

 fun getGeofencingRequest(geofence: Geofence?): GeofencingRequest {
return GeofencingRequest.Builder()
.addGeofence(geofenceList)
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.build()
}

This example shows the use of two geofence triggers. The GEOFENCE_TRANSITION_ENTER transition triggers when a device enters a geofence, and the GEOFENCE_TRANSITION_EXIT transition triggers when a device exits a geofence. Specifying INITIAL_TRIGGER_ENTER tells Location services that GEOFENCE_TRANSITION_ENTER should be triggered if the device is already inside the geofence.

Optimizing Geofences:

  1. Use INITIAL_TRIGGER_DWELL:
  • This triggers events only when the user stays within a geofence for a set duration.
  • Helps reduce excessive notifications from brief entries and exits.

2. Set a Minimum Radius of 100 Meters:

  • Accounts for typical Wi-Fi location accuracy.
  • Helps reduce power consumption.

Define a broadcast receiver for geofence transitions and Handling Geofence Transitions

1. Do Not Start Activities or Fragments:

  • Intents from Location Services should not make components visible immediately.
  • Activities and fragments should only appear in response to user actions.

2. Use a BroadcastReceiver:

  • A good way to handle geofence transitions.
  • Receives updates when events like entering or exiting a geofence occur.
  • Can start long-running background tasks.

The following snippet shows how to define a PendingIntent that starts a BroadcastReceiver:

    val geofencePendingIntent: PendingIntent by lazy {
val intent = Intent(base, GeofenceBroadcastReceiver::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.getBroadcast(base, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
} else {
PendingIntent.getBroadcast(base, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
}

Add geofences

To add geofences, use the GeofencingClient.addGeofences() method. Provide the GeofencingRequest object, and the PendingIntent. The following snippet demonstrates processing the results:

geofencingClient?.addGeofences(getGeofencingRequest(), geofencePendingIntent)?.run {
addOnSuccessListener {
// Geofences added
// ...
}
addOnFailureListener {
// Failed to add geofences
// ...
}
}

Handling Geofence Transitions

  1. Intent Handling:
  • When a user enters or exits a geofence, Location Services sends an Intent.
  • This Intent is part of the PendingIntent you included in your geofence request.

2. BroadcastReceiver:

  • GeofenceBroadcastReceiver detects the Intent.
  • It gets the geofencing event from the Intent, determines the transition type, and identifies the triggered geofence.
  • It can then start background work or send a notification.

3. Background Location Limits (Android 8.0+):

  • If your app is in the background, the device checks for geofence events every few minutes.
  • Adapt your app to handle these limits by following the guidelines in Background Location Limits.

The following snippet shows how to define a BroadcastReceiver that posts a notification when a geofence transition occurs. When the user clicks the notification, the app's main activity appears:

class GeofenceBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {

val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent!!.hasError()) {
val errorMessage = GeofenceStatusCodes
.getStatusCodeString(geofencingEvent.errorCode)
Log.e(TAG, errorMessage)
return
}

val geofenceList = geofencingEvent.triggeringGeofences
for (geofence in geofenceList!!) {
Log.d(TAG, "onReceive: " + geofence.requestId)
}

// Get the transition type.
val transitionType = geofencingEvent.geofenceTransition
Log.d(TAG, "onReceive: $transitionType")

// Get the geofences that were triggered. A single event can trigger
// multiple geofences.
val triggeringGeofences = geofencingEvent.triggeringGeofences

// Get the transition details as a String.
val geofenceTransitionDetails = getGeofenceTransitionDetails(
this,
geofenceTransition,
triggeringGeofences
)

// Send notification and log the transition details.
sendNotification(geofenceTransitionDetails)

when (transitionType) {
Geofence.GEOFENCE_TRANSITION_ENTER -> {
Log.d(TAG, "onReceive: Enter")
Toast.makeText(context.applicationContext, "GEOFENCE_TRANSITION_ENTER", Toast.LENGTH_SHORT).show()
}

Geofence.GEOFENCE_TRANSITION_DWELL -> {
Log.d(TAG, "onReceive: DWELL")
Toast.makeText(context.applicationContext, "GEOFENCE_TRANSITION_DWELL", Toast.LENGTH_SHORT).show()
}

Geofence.GEOFENCE_TRANSITION_EXIT -> {
Log.d(TAG, "onReceive: EXIT")
Toast.makeText(context.applicationContext, "GEOFENCE_TRANSITION_EXIT", Toast.LENGTH_SHORT).show()
}
}
}

companion object {
private const val TAG = "GeofenceBroadcastReceiver"
}
}

After detecting the transition event via the PendingIntent, the BroadcastReceiver gets the geofence transition type and tests whether it is one of the events the app uses to trigger notifications -- either GEOFENCE_TRANSITION_ENTER or GEOFENCE_TRANSITION_EXIT in this case. The service then sends a notification and logs the transition details.

Stop geofence monitoring

Stopping geofence monitoring when it is no longer needed or desired can help save battery power and CPU cycles on the device. You can stop geofence monitoring in the main activity used to add and remove geofences; removing a geofence stops it immediately. The API provides methods to remove geofences either by request IDs, or by removing geofences associated with a given PendingIntent.

Stopping geofence monitoring when it’s no longer needed helps save battery and CPU usage. You can stop monitoring in the main activity where you manage geofences.

The following snippet removes geofences by PendingIntent, stopping all further notification when the device enters or exits previously added geofences:

geofencingClient?.removeGeofences(geofencePendingIntent)?.run {
addOnSuccessListener {
// Geofences removed
// ...
}
addOnFailureListener {
// Failed to remove geofences
// ...
}
}

You can combine geofencing with other location-aware features, such as periodic location updates. For more information, see the other lessons in this class.

Testing

To test geofence in your emulator you have to,

  • Firstly, add geofence area in the map using long press.
  • Set your current location using extended controls (location -> single points).
  • Open google map app in the emulator and also open your app to test this feature. (If you don’t open map app then it’s not working, but in real device we don’t need to open map app.)
  • Debugging, log, notification, toast of Geofence Broadcast Receiver to test your functionality.
Circular geofence
Google Map with current user location
Extended Controls of your emulator with single points to set your location

Best Practices for Geofencing in Android Apps

1. Reduce Power Consumption

  • Set Notification Responsiveness Higher: Increase the time interval for checking geofence events (e.g., check every 5 minutes instead of every few seconds). This reduces power usage.
  • Use Larger Geofence Radius: For places where users spend a lot of time (like home or work), use a larger radius. This reduces the frequency of entrance and exit checks.

2. Choose the Optimal Radius

  • Minimum Radius: Set between 100–150 meters for best results.
  • With Wi-Fi: Accuracy is 20–50 meters, or even 5 meters indoors.
  • Without Wi-Fi: In rural areas, accuracy can be several hundred meters to kilometers. Use a larger radius in these cases.

3. Explain Geofencing to Users

  • User Transparency: Clearly explain why your app needs geofencing to help users understand and accept background location access.

4. Reduce Alert Spam

  • Use Dwell Transition: Instead of triggering alerts immediately upon entering a geofence, use the dwell transition type. This sends alerts only when a user stays within a geofence for a specified time.

5. Re-register Geofences Only When Required

  • Automatic Handling: Geofences are maintained through system events like updates and restarts of Google Play services.
  • Manual Re-registration: Re-register geofences after device reboot, app reinstallation, or when app data/Google Play services data is cleared.

6. Troubleshoot Geofence Events

  • Ensure Proper Registration: Verify that geofences are registered correctly.
  • Location Accuracy: Geofences might not work if location accuracy is poor. Enable Wi-Fi for better accuracy.
  • Wi-Fi Enabled: If Wi-Fi is off, location accuracy decreases. Use “Wi-Fi scan only mode” to improve accuracy even if Wi-Fi is disabled.
  • Network Connectivity: Reliable network connectivity is necessary for generating alerts.
  • Expect Some Latency: Alerts may have a slight delay (typically under 2 minutes, up to 6 minutes if the device is stationary for a long time).

Following these best practices will help optimize your app’s performance and user experience when using geofencing.

Use Cases of Geofencing in Apps

Geofencing can enhance user experience by providing location-based services and notifications. Here are some common use cases:

1. Retail and Shopping:

  • Promotions and Offers: Notify customers of special deals or discounts when they enter a store or a shopping area.
  • Loyalty Programs: Automatically check in loyal customers and offer them personalized rewards.

2. Travel and Tourism:

  • Guided Tours: Provide information or audio guides when users enter specific landmarks or points of interest.
  • Transportation: Alert users about bus or train schedules, delays, or when they arrive at their destination.

3. Safety and Security:

  • Parental Control: Notify parents when their children enter or leave designated safe zones like home, school, or playgrounds.
  • Employee Safety: Ensure workers’ safety by monitoring their presence in hazardous areas and alerting them if they enter restricted zones.

4. Real Estate:

  • Property Alerts: Notify potential buyers about open houses or new listings when they are near a property for sale.
  • Home Automation: Trigger home automation events like turning on lights or adjusting the thermostat when the homeowner is near.

5. Fitness and Health:

  • Activity Tracking: Start or stop tracking a workout when users enter or leave a gym or a running trail.
  • Health Reminders: Remind users to take medication or hydrate when they enter specific locations, like home or office.

6. Event Management:

  • Event Check-In: Automatically check attendees into an event when they arrive at the venue.
  • Venue Navigation: Provide navigation assistance or information about different sections of the venue.

7. Transportation and Logistics:

  • Fleet Management: Monitor the location of delivery trucks and alert drivers about upcoming stops.
  • Ridesharing Services: Notify drivers and passengers when they are near pickup or drop-off points.

8. Personal Productivity:

  • Task Reminders: Remind users to perform tasks when they enter relevant locations, like grocery shopping reminders when near a store.
  • Geotagging: Automatically geotag notes, photos, or other content based on the user’s location.

Example project:

Thank you for reading. Hope you learn something new.🙌🙏✌.

Don’t forget to clap 👏 to support me and follow me for more such useful articles about Android Development, Kotlin & KMP.

If you need any help related to Android, Kotlin and KMP. I’m always happy to help you.

Follow me on:

Medium, LinkedIn, Twitter, GitHub, and Instagram.

--

--

Kaushal Vasava

Android Developer | Kotlin | Jetpack Compose | Kotlin MultiPlatform | LinkedIn's Top Voice (3K+ Followers) | Apps with 100K+ Downloads on the Playstore