Get User Location in Flutter: geolocator package

Get User Location in Flutter: geolocator package

The User Location may be required in many cases where you don't want to get the wrong/incorrect address or any other cases. The Flutter geolocation plugin which provides easy access to platform-specific location services makes the task easier.

We will learn how to get the user's location in Flutter using the geolocation package. Geolocation is the process of identifying the geographical location of a device. This information can be used to provide location-based services like weather forecasts, local news, and nearby shops and restaurants.

To get the user's location in Flutter, we will use the geolocator package. This package provides an easy-to-use interface for accessing the device's location.

Installation of the package

Either install the package with the Flutter command line by running the following command:

flutter pub add geolocator

Add the geolocation package under dependencies as follows:

dependencies:
  geolocator: ^9.0.2

For iOS

On iOS, you'll need to add the following entries to your Info.plist file (located under ios/Runner) in order to access the device's location. Simply open your Info.plist file and add the following (make sure you update the description so it is meaningful in the context of your App):

<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when open.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to location when in the background.</string>

f you would like to receive updates when your App is in the background, you'll also need to add the Background Modes capability to your XCode project (Project > Signing and Capabilities > "+ Capability" button) and select Location Updates. Be careful with this, you will need to explain in detail to Apple why your App needs this when submitting your App to the AppStore. If Apple isn't satisfied with the explanation your App will be rejected.

When using the requestTemporaryFullAccuracy({purposeKey: "PurposeKey"}) method, a dictionary should be added to the Info.plist file.

<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
  <key>YourPurposeKey</key>
  <string>The example App requires temporary access to the device&apos;s precise location.</string>
</dict>

The second key (in this example called PurposeKey) should match the purposeKey that is passed in the requestTemporaryFullAccuracy() method. It is possible to define multiple keys for different features in your app.

For Android

AndroidX

Geolocator is dependent on AndroidX. Make sure to include the following settings to 'android/gradle.properties':

android.useAndroidX=true
android.enableJetifier=true

Make sure you set the compileSdkVersion in your "android/app/build.gradle" file to 33:

android {
  compileSdkVersion 33

  ...
}

There are two kinds of location permission in Android: "coarse" and "fine". Coarse location will allow getting approximate location based on sensors like the Wifi, while fine location returns the most accurate location using GPS (in addition to coarse).

You need to declare one of the two permissions in android/app/src/main/AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  <!-- or -->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>

Note that ACCESS_FINE_LOCATION permission includes ACCESS_COARSE_LOCATION.

For macOS

On macOS, you'll need to add the following entries to your Info.plist file (located under macOS/Runner) in order to access the device's location. Simply open your Info.plist file and add the following (make sure you update the description so it is meaningful in the context of your App):

<key>NSLocationUsageDescription</key>
<string>This app needs access to location.</string>

You will also have to add the following entry to the DebugProfile.entitlements and Release.entitlements files. This will declare that your App wants to make use of the device's location services and adds it to the list in the "System Preferences" -> "Security & Privacy" -> "Privacy" settings.

<key>com.apple.security.personal-information.location</key>
<true/>

When using the requestTemporaryFullAccuracy({purposeKey: "YourPurposeKey"}) method, a dictionary should be added to the Info.plist file.

<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
  <key>YourPurposeKey</key>
  <string>The example App requires temporary access to the device&apos;s precise location.</string>
</dict>

For Web

To use the Geolocator plugin on the web you need to be using Flutter 1.20 or higher. Flutter will automatically add the endorsed geolocator_web package to your application when you add the geolocator: ^6.2.0 dependency to your pubspec.yaml.

For Windows

To use the Geolocator plugin on Windows you need to be using Flutter 2.10 or higher. Flutter will automatically add the endorsed geolocator_windows package to your application when you add the geolocator: ^8.1.0 dependency to your pubspec.yaml.

Import the Package

import 'package:geolocator/geolocator.dart';

Example

After the installation of the package and importing it, we can fetch the location of the device.

Requesting the Location Permissions

The geolocation package will manage the location services when required. We use the following code to request permission.

_checkLocationService() async {
    // Check if location services are enabled.
    bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) {
      // Location services are not enabled don't continue
      // accessing the position and request users of the
      // App to enable the location services.
      _showSnackBar('Location services are disabled.', Colors.red);
      return false;
    }
    _showSnackBar('Location services are enabled.', Colors.green);
    return true;
  }

Get current location

To query the current location of the device simply make a call to the getCurrentPosition method. You can finetune the results by specifying the following parameters:

  • desiredAccuracy: the accuracy of the location data that your app wants to receive;

  • timeLimit: the maximum amount of time allowed to acquire the current location. When the time limit is passed a TimeOutException will be thrown and the call will be cancelled. By default, no limit is configured.

_getCurrentLocation() async {
    // Check if location services are enabled.
    bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) {
      _showSnackBar('Location services are disabled.', Colors.red);
      return;
    }
    LocationPermission permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) {
        _showSnackBar('Location permissions are denied', Colors.red);
        return;
      }
    }

    if (permission == LocationPermission.deniedForever) {
      // Permissions are denied forever, handle appropriately.
      _showSnackBar(
          'Location permissions are permanently denied, we cannot request permissions.',
          Colors.red);
      return;
    }

    // When we reach here, permissions are granted and we can
    // continue accessing the position of the device.

    Position position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.high);
    log(position.toString());
    _showMaterialBanner(position.toString(), Colors.green);
  }

Get Last Location

The last known location can be retrieved and stored on the device you can use the getLastKnownPosition method (note that this can result in a null value when no location details are available):

_getLastLocation() async {
  // Check if location services are enabled.
  bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
  if (!serviceEnabled) {
    _showSnackBar('Location services are disabled.', Colors.red);
    return;
  }
  LocationPermission permission = await Geolocator.checkPermission();
  if (permission == LocationPermission.denied) {
    permission = await Geolocator.requestPermission();
    if (permission == LocationPermission.denied) {
      _showSnackBar('Location permissions are denied', Colors.red);
      return;
    }
  }

  if (permission == LocationPermission.deniedForever) {
    // Permissions are denied forever, handle appropriately.
    _showSnackBar(
        'Location permissions are permanently denied, we cannot request permissions.',
        Colors.red);
    return;
  }

  // When we reach here, permissions are granted and we can
  // continue accessing the position of the device.

  Position? position = await Geolocator.getLastKnownPosition();
  if (position == null) {
    _showSnackBar('No location data available.', Colors.red);
    return;
  }
  log(position.toString());
  _showMaterialBanner(position.toString(), Colors.green);
}

For macOS

On macOS, you'll need to add the following entries to your Info.plist file (located under macOS/Runner) in order to access the device's location. Simply open your Info.plist file and add the following (make sure you update the description so it is meaningful in the context of your App):

<key>NSLocationUsageDescription</key>
<string>This app needs access to location.</string>

You will also have to add the following entry to the DebugProfile.entitlements and Release.entitlements files. This will declare that your App wants to make use of the device's location services and adds it to the list in the "System Preferences" -> "Security & Privacy" -> "Privacy" settings.

<key>com.apple.security.personal-information.location</key>
<true/>

When using the requestTemporaryFullAccuracy({purposeKey: "YourPurposeKey"}) method, a dictionary should be added to the Info.plist file.

<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
  <key>YourPurposeKey</key>
  <string>The example App requires temporary access to the device&apos;s precise location.</string>
</dict>

For Web

To use the Geolocator plugin on the web you need to be using Flutter 1.20 or higher. Flutter will automatically add the endorsed geolocator_web package to your application when you add the geolocator: ^6.2.0 dependency to your pubspec.yaml.

For Windows

To use the Geolocator plugin on Windows you need to be using Flutter 2.10 or higher. Flutter will automatically add the endorsed geolocator_windows package to your application when you add the geolocator: ^8.1.0 dependency to your pubspec.yaml.

Import the Package

import 'package:geolocator/geolocator.dart';

Example

After the installation of the package and importing it, we can fetch the location of the device.

Requesting the Location Permissions

The geolocation package will manage the location services when required. We use the following code to request permission.

_checkLocationService() async {
    // Check if location services are enabled.
    bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) {
      // Location services are not enabled don't continue
      // accessing the position and request users of the
      // App to enable the location services.
      _showSnackBar('Location services are disabled.', Colors.red);
      return false;
    }
    _showSnackBar('Location services are enabled.', Colors.green);
    return true;
  }

Get current location

To query the current location of the device simply make a call to the getCurrentPosition method. You can finetune the results by specifying the following parameters:

  • desiredAccuracy: the accuracy of the location data that your app wants to receive;

  • timeLimit: the maximum amount of time allowed to acquire the current location. When the time limit is passed a TimeOutException will be thrown and the call will be cancelled. By default, no limit is configured.

_getCurrentLocation() async {
    // Check if location services are enabled.
    bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) {
      _showSnackBar('Location services are disabled.', Colors.red);
      return;
    }
    LocationPermission permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) {
        _showSnackBar('Location permissions are denied', Colors.red);
        return;
      }
    }

    if (permission == LocationPermission.deniedForever) {
      // Permissions are denied forever, handle appropriately.
      _showSnackBar(
          'Location permissions are permanently denied, we cannot request permissions.',
          Colors.red);
      return;
    }

    // When we reach here, permissions are granted and we can
    // continue accessing the position of the device.

    Position position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.high);
    log(position.toString());
    _showMaterialBanner(position.toString(), Colors.green);
  }

Get Last Location

The last known location can be retrieved and stored on the device you can use the getLastKnownPosition method (note that this can result in a null value when no location details are available):

_getLastLocation() async {
  // Check if location services are enabled.
  bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
  if (!serviceEnabled) {
    _showSnackBar('Location services are disabled.', Colors.red);
    return;
  }
  LocationPermission permission = await Geolocator.checkPermission();
  if (permission == LocationPermission.denied) {
    permission = await Geolocator.requestPermission();
    if (permission == LocationPermission.denied) {
      _showSnackBar('Location permissions are denied', Colors.red);
      return;
    }
  }

  if (permission == LocationPermission.deniedForever) {
    // Permissions are denied forever, handle appropriately.
    _showSnackBar(
        'Location permissions are permanently denied, we cannot request permissions.',
        Colors.red);
    return;
  }

  // When we reach here, permissions are granted and we can
  // continue accessing the position of the device.

  Position? position = await Geolocator.getLastKnownPosition();
  if (position == null) {
    _showSnackBar('No location data available.', Colors.red);
    return;
  }
  log(position.toString());
  _showMaterialBanner(position.toString(), Colors.green);
}

Location Updates

We can get location updates also. We can finetune the results by specifying the following parameters:

  • accuracy: the accuracy of the location data that your app wants to receive;

  • distanceFilter: the minimum distance (measured in meters) a device must move horizontally before an update event is generated;

  • timeLimit: the maximum amount of time allowed between location updates. When the time limit is passed a TimeOutException will be thrown and the stream will be cancelled. By default, no limit is configured.

_getLocationUpdates() async {
  // Check if location services are enabled.
  bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
  if (!serviceEnabled) {
    _showSnackBar('Location services are disabled.', Colors.red);
    return;
  }
  LocationPermission permission = await Geolocator.checkPermission();
  if (permission == LocationPermission.denied) {
    permission = await Geolocator.requestPermission();
    if (permission == LocationPermission.denied) {
      _showSnackBar('Location permissions are denied', Colors.red);
      return;
    }
  }

  if (permission == LocationPermission.deniedForever) {
    // Permissions are denied forever, handle appropriately.
    _showSnackBar(
        'Location permissions are permanently denied, we cannot request permissions.',
        Colors.red);
    return;
  }

  const LocationSettings locationSettings = LocationSettings(
    accuracy: LocationAccuracy.high,
    distanceFilter: 100,
  );
  StreamSubscription<Position> positionStream =
      Geolocator.getPositionStream(locationSettings: locationSettings)
          .listen((Position position) {
    log(position.toString());
    _showMaterialBanner(position.toString(), Colors.green);
  });
}

Full Working Example and Output

Here is the output

Here is the full working code. Here we have used MaterialBanner and Snackbar to alert the users. You can learn them from the attached link on the website.

import 'dart:async';
import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'GeoLocation Tutorial',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const GeoLocationTutorial(),
    );
  }
}

class GeoLocationTutorial extends StatefulWidget {
  const GeoLocationTutorial({Key? key}) : super(key: key);

  @override
  State<GeoLocationTutorial> createState() => _GeoLocationTutorialState();
}

class _GeoLocationTutorialState extends State<GeoLocationTutorial> {
  _showSnackBar(String message, Color color) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(message),
        backgroundColor: color,
      ),
    );
  }

  _showMaterialBanner(String message, Color color) {
    ScaffoldMessenger.of(context).showMaterialBanner(
      MaterialBanner(
        content: Text(message),
        backgroundColor: color,
        actions: [
          TextButton(
            onPressed: () {
              ScaffoldMessenger.of(context).hideCurrentMaterialBanner();
            },
            child: const Text('OK'),
          ),
        ],
      ),
    );
  }

  _checkLocationService() async {
    // Check if location services are enabled.
    bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) {
      // Location services are not enabled don't continue
      // accessing the position and request users of the
      // App to enable the location services.
      _showSnackBar('Location services are disabled.', Colors.red);
      return false;
    }
    _showSnackBar('Location services are enabled.', Colors.green);
    return true;
  }

  _getCurrentLocation() async {
    // Check if location services are enabled.
    bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) {
      _showSnackBar('Location services are disabled.', Colors.red);
      return;
    }
    LocationPermission permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) {
        _showSnackBar('Location permissions are denied', Colors.red);
        return;
      }
    }

    if (permission == LocationPermission.deniedForever) {
      // Permissions are denied forever, handle appropriately.
      _showSnackBar(
          'Location permissions are permanently denied, we cannot request permissions.',
          Colors.red);
      return;
    }

    // When we reach here, permissions are granted and we can
    // continue accessing the position of the device.

    Position position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.high);
    log(position.toString());
    _showMaterialBanner(position.toString(), Colors.green);
  }

  _getLastLocation() async {
    // Check if location services are enabled.
    bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) {
      _showSnackBar('Location services are disabled.', Colors.red);
      return;
    }
    LocationPermission permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) {
        _showSnackBar('Location permissions are denied', Colors.red);
        return;
      }
    }

    if (permission == LocationPermission.deniedForever) {
      // Permissions are denied forever, handle appropriately.
      _showSnackBar(
          'Location permissions are permanently denied, we cannot request permissions.',
          Colors.red);
      return;
    }

    // When we reach here, permissions are granted and we can
    // continue accessing the position of the device.

    Position? position = await Geolocator.getLastKnownPosition();
    if (position == null) {
      _showSnackBar('No location data available.', Colors.red);
      return;
    }
    log(position.toString());
    _showMaterialBanner(position.toString(), Colors.green);
  }

  _getLocationUpdates() async {
    // Check if location services are enabled.
    bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) {
      _showSnackBar('Location services are disabled.', Colors.red);
      return;
    }
    LocationPermission permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) {
        _showSnackBar('Location permissions are denied', Colors.red);
        return;
      }
    }

    if (permission == LocationPermission.deniedForever) {
      // Permissions are denied forever, handle appropriately.
      _showSnackBar(
          'Location permissions are permanently denied, we cannot request permissions.',
          Colors.red);
      return;
    }

    const LocationSettings locationSettings = LocationSettings(
      accuracy: LocationAccuracy.high,
      distanceFilter: 100,
    );
    StreamSubscription<Position> positionStream =
        Geolocator.getPositionStream(locationSettings: locationSettings)
            .listen((Position position) {
      log(position.toString());
      _showMaterialBanner(position.toString(), Colors.green);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('GeoLocation Tutorial allaboutflutter.com'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            ElevatedButton(
              onPressed: () {
                _checkLocationService();
              },
              child: const Text('Check Location Service'),
            ),
            ElevatedButton(
              onPressed: _getCurrentLocation,
              child: const Text('Get Current Location'),
            ),
            ElevatedButton(
              onPressed: _getLastLocation,
              child: const Text('Get Last Location'),
            ),
            ElevatedButton(
              onPressed: _getLocationUpdates,
              child: const Text('Get Location Updates'),
            ),
          ],
        ),
      ),
    );
  }
}

Did you find this article valuable?

Support All About Flutter | Flutter and Dart by becoming a sponsor. Any amount is appreciated!