Geofencing API Tutorial for Android

In this geofence tutorial, you’ll learn how to use Android’s Geofencing API to build an app with custom geofences. By Fernando Sproviero.

4.5 (12) · 1 Review

Download materials
Save for later
Share

Geofences are a powerful tool in a developer’s arsenal of location tricks to use on Android. Geofences give devices the power to monitor a circular area in the world, and let the device inform you whenever it enters or exits that area.

This has enormous benefits for apps that want to leverage location as a trigger. A retail company could send a special notification to a customer near one of their stores with a special discount to tempt them in. A holiday resort could welcome its customers via its app whenever they enter the resort. With a limit of 100 geofences per device, the possibilities are nearly endless!

In this tutorial on geofencing, you’ll learn how to use Android’s geofencing API to build custom geofences in your very own app called Remind Me There. Let’s get to it!

Getting Started

The project you’ll work with, Remind Me There, is an app to create reminders based on geofences. You’ll set up custom geofences and messages; then, as you travel into a geofenced area, you’ll receive your custom message as a notification on your device.

Use the Download materials button at the top or bottom of this tutorial to download the starter project.

Once downloaded, open the starter project in Android Studio 3.2 or later.

Obtaining a Google Maps API Key

Because this app uses Google Maps, you’ll need to obtain an API key.

Feel free to leave the Project Name as is. You won’t need the name going forward. Leave the default value for Location. Select Create.

  1. Open Google Cloud Platform and create a new project.
  2. Select APIs & Services ▸ Library from the navigation menu.
  3. Select Maps SDK for Android.
  4. Click Enable, or Manage if already enabled.
  5. Click on Credentials, Credentials in the API Manager, Create credentials and then choose API key.
  6. Copy your API key value. In your project, open debug/res/values/google_maps_api.xml and replace YOUR_KEY_HERE with the copied value.
Note: To release an app to the Google Play Store, you should create a separate project and, when you click on Create credentials▸API key, choose Restrict Key. Keys without restrictions are generic and are not limited to certain APIs. Set this key in release/res/values/google_maps_api.xml.

Building and Running the Starter Project

You can run the sample project on an Android device or emulator. For the emulator, you’ll need to make sure you have an emulator setup with Google APIs in order to show map information.

When you build and run the app, you’ll see the following screens:

Currently, tapping on the + button will let you create the reminder. However, the actual geofence is not yet being created. You’ll write code to create the geofence.

Review the project to get familiar with the files:

  • MainActivity.kt: Shows the reminders in a map.
  • NewReminderActivity.kt: This activity contains the code to create a new reminder, providing latitude/longitude, radius and a message to be shown in the notification.
  • Reminder.kt: A model class used to store the reminder. It has an id, a latitude/longitude, a radius and a message. You’ll use this later to build a geofence.
  • ReminderRepository.kt: This file saves the reminders that you create that will be shown in the MainActivity. You’ll also add code to create the geofences, here.
  • BaseActivity.kt: This is the parent activity of MainActivity and NewReminderActivity. It provides common access to the ReminderRepository.
  • ReminderApp.kt: When the app is launched, it creates the ReminderRepository.
  • Utils.kt: Here, you’ll find a few generic functions useful for the app – for example, a function to hide the keyboard, show a notification, etc.

Using geofences requires the play-services-location library added to your project. To do that, open the build.gradle file for the app module and add the following dependency:

implementation 'com.google.android.gms:play-services-location:16.0.0'

Your app also requires the device location to know when to trigger a reminder. You do this by requesting the ACCESS_FINE_LOCATION permission.

This permission is set up in AndroidManifest.xml. It’s classified as a dangerous permission — that is, a permission that could potentially affect the user’s privacy. For Android 6 and later, it’s necessary to check and request this permission during runtime.

Because the starter project shows a map and the user location, the permission and runtime check were both already set up for you in AndroidMainfest.xml and MainActivity.kt.

Creating a Geofence

To manipulate geofences, you need to use the GeofencingClient, so open ReminderRepository.kt and add a new property:

private val geofencingClient = LocationServices.getGeofencingClient(context)

You’ll also need to import com.google.android.gms.location.LocationServices.

Note: Going forward, when you receive an import warning, you can import with your cursor over the warning by pressing option+return on a Mac or Alt+Enter on a PC.

If you look at the add() method, you’ll see that, currently, it just saves the reminder to SharedPreferences. First, you’ll change this behavior to create the geofence, using the GeofencingClient. Then, only if the geofence creation is successful, you’ll save the reminder to SharedPreferences.

Change the add() method to the following:

fun add(reminder: Reminder,
        success: () -> Unit,
        failure: (error: String) -> Unit) {
  // 1
  val geofence = buildGeofence(reminder)
  if (geofence != null
      && ContextCompat.checkSelfPermission(
          context,
          Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
    // 2
    geofencingClient
        .addGeofences(buildGeofencingRequest(geofence), geofencePendingIntent)
        // 3
        .addOnSuccessListener {
          saveAll(getAll() + reminder)
          success()
        }
        // 4
        .addOnFailureListener {
          failure("Error")
        }
  }
}

Use the hotkeys you learned above to import ContextCompat and Manifest. Don’t worry about the other errors. Those are methods that you’ll build, soon. Take a minute to have a look at what you have just added:

  1. You create the geofence model using the data from the reminder.
  2. You use the GeofencingClient to add the geofence that you’ve just built with a geofencing request and a pending intent. More on this later.
  3. If the geofence is added successfully, you save the reminder and call the success argument.
  4. If there’s an error, you call the failure argument (without saving the reminder).

Building the Geofence

A geofence is defined by a latitude, a longitude and a radius. It’s a circular area at a specific location that an app can use to trigger particular behaviors when a device enters, exits or stays for a certain amount of time within geofence boundaries.

You’re going to build a geofence that behaves this way right now. To build your geofence, add the following method to ReminderRepository.kt:

private fun buildGeofence(reminder: Reminder): Geofence? {
  val latitude = reminder.latLng?.latitude
  val longitude = reminder.latLng?.longitude
  val radius = reminder.radius

  if (latitude != null && longitude != null && radius != null) {
    return Geofence.Builder()
        // 1
        .setRequestId(reminder.id)
        // 2
        .setCircularRegion(
            latitude,
            longitude,
            radius.toFloat()
        )
        // 3
        .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
        // 4
        .setExpirationDuration(Geofence.NEVER_EXPIRE)
        .build()
  }

  return null
}

Take a look at the Geofence.Builder code in your new method:

  1. RequestId: This id uniquely identifies the geofence within your app. You obtain this from the reminder model.
  2. latitude, longitude and radius: You also get these from the reminder model at the top of the new method.
  3. TransitionType: To trigger an event when the user enters the geofence, use GEOFENCE_TRANSITION_ENTER. Other options are GEOFENCE_TRANSITION_EXIT and GEOFENCE_TRANSITION_DWELL. You can learn more about transition options here.
  4. ExpirationDuration: Use NEVER_EXPIRE so this geofence will exist until the user removes it. The other option is to enter a duration (ms) after which the geofence will expire.