How To Track Your Location In A Flutter App

Flutter category image

Introduction

Here is a deep dive into GPS, permissions, and manifests. Learn how to track your location in a Flutter app. Find out how to collect location data while your app is in the background. There are also tips included to prevent the OS from terminating your app after some time.

Working with location data in mobile-aware apps is a common use case in the current app ecosystem. In this deep dive I will show you everything you need to know about how to track your location in a Flutter app. No matter if you want a to put a pin on a map with the current location or track a device continuously for hours, everything is possible.

Set up and preparations

There are different Flutter packages available that do the heavy lifting for us. The two most advanced ones are location and geolocator. They have a similar feature set and if you know how to handle one, you also will have no problem with the other. However, this article will rely on the package geolocator.

To install the package, add it to your pubspec.yaml manually or with the command flutter pub add geolocator. For more information about how to add packages in Flutter apps, read this article.

Android

Your Android app needs to declare certain capabilities to access location data. Those are defined in the AndroidManifest.xml. Navigate to the android\app\src\main\ folder, open the file, and add the following permissions inside the manifest tag:

XML
import 'package:geolocator/geolocator.dart';

final hasPermission = await Geolocator.checkPermission();

if (hasPermission == LocationPermission.deniedForever) {
  print("The permission to access the device location was denied forever!");
  return;
}

if (hasPermission == LocationPermission.denied){
	final hasFinalPermission = await Geolocator.requestPermission();
	if (hasFinalPermission == LocationPermission.denied ||
	    hasFinalPermission == LocationPermission.deniedForever) {
	  print("The permission to access the device location was denied!");
	  return false;
	}
}

if (!await Geolocator.isLocationServiceEnabled()) {
  print("The location services of the device are not enabled!");
  return;
}

final subscription = Geolocator.getPositionStream().listen((pos) {
	print("${pos.latitude}, ${pos.longitude}");
});

The first step is to verify the permission. If it was denied, we ask again. This opens a dialog for the user to select the permission for our app.

In addition, we check if location services are enabled. If everything is fine, we subscribe to the position stream to get location updates.

Configure location settings

You can configure the location settings of the location stream. Therefor, you can either use the base class LocationSettings or specialized classes for the mobile platforms, AndroidSettings and AppleSettings.

The most basic configuration values are a distance filter and an accuracy setting. The distance filter filters location updates that are too close to the last position. It is specified in meters. The accuracy setting describes how precise the location should be retrieved. This can range from a few 100 meters to as close as 1 or 2 meters.

The classes AndroidSettings and AppleSettings contain platform-specific settings.

Dart
final settings = LocationSettings(...);

final subscription = Geolocator
		.getPositionStream(locationSettings: settings)
		.listen((pos) {
	print("${pos.latitude}, ${pos.longitude}");
});

Want More Flutter Content?

Join my bi-weekly newsletter that delivers small Flutter portions right in your inbox. A title, an abstract, a link, and you decide if you want to dive in!


Background updates

Sometimes, you might want to get location updates even if your app is not running in the foreground. Geolocator can be configured to also work under these circumstances.

🔔 Terminology

We assume an app has three states: Foreground, background, and terminated.

Foreground means that the app is open and visible on the device screen. Background means the app was started previously but is not visible. A terminated is not running anymore because it was terminated by the user or by the operating system.

To support background updates, we need to add more permissions in the AndroidManifest.xml and the Info.plist.

Here is the updated AndroidManifest.xml:

XML
final settings = AndroidSettings(
          foregroundNotificationConfig: ForegroundNotificationConfig(
                  notificationText: "Doing some heavy work ... please stand by!",
                  notificationTitle: "Background Service"));
    
final subscription = Geolocator
		.getPositionStream(locationSettings: settings)
		.listen(...);
Screenshot of the Android notification for an app running in the background
Screenshot of the Android notification for an app running in the background

In case, your notification is not visible, try the following approaches from this thread:

Add a new permission for notifications to the AndroidManifest.xml file:

XML
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

Then, add permission_handler and request the permission for notifications in your app.

Dart
await Permission.notification.request();

If it still doesn’t work, try the package flutter_local_notifications. The code below recreates the notification channel so that the permanent notification should now be visible.

Dart
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

const AndroidNotificationChannel backgroundLocationChannel = AndroidNotificationChannel(
  'geolocator_channel_01', // id
  'Background Location', // name
  description: 'Background Location Notification Channel', // description
  importance: Importance.min,
);
final FlutterLocalNotificationsPlugin plugin = FlutterLocalNotificationsPlugin();
await plugin
    .resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
    ?.createNotificationChannel(backgroundLocationChannel);

Set appropriate activitiy type (iOS)

The AppleSettings class in the geolocator package has a property activityType. With that you can tell the operating system what type of app you build so that the system can decide how to handle background updates.

Conclusion

In this article you learned everything you about how to track your location in a Flutter app. By using established packages and following the setup instructions, you shouldn’t run into problems. For more advanced use cases, we also talked about background operations and how you can ensure that your app is not terminated by the operating system.


Want More Flutter Content?

Join my bi-weekly newsletter that delivers small Flutter portions right in your inbox. A title, an abstract, a link, and you decide if you want to dive in!