Flutter: Getting a User's Location with the Geolocator Plugin

Paul Halliday

Ever wanted to get a user’s location within your Flutter application? We’re going to be building an application that does exactly that by taking advantage of the Geolocator plugin.

Creating a new Flutter project

As always, we’ll start off by setting up a new project and adding the plugin:

# New Flutter project
$ flutter create my_location_project

# Open this up inside of VS Code
$ cd my_location_project && code .

Adding the Geolocator plugin

Head over to your pubspec.yaml and add the following plugin:

dependencies:
  flutter:
    sdk: flutter

  geolocator: ^5.1.3

Note: You'll need to make sure that your Android project uses AndroidX for this. If you've created a Flutter application after version 1.7, this comes by default, if not, follow this guide: AndroidX Migration.

We’ll then need to add permissions to both Android and iOS by editing ios/Runner/Info.plist and android/app/src/main/AndroidManifest.xml.

iOS Permissions

Starting with iOS and the Info.plist, add the following key/value pairs and customize them to your liking:

<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>

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

If you don’t intend to support iOS applications older than iOS 10 and you don’t want to get user location when the application isn’t in use, you can forego the addition of NSLocationAlwaysUsageDescription and NSLocationAlwaysAndWhenInUseUsageDescription.

Android Permissions

For android, head on over to your AndroidManifest.xml and add either of these permissions:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

What’s the difference between these two? ACCESS_FINE_LOCATION is the most precise, whereas ACCESS_COARSE_LOCATION gives results equal to about a city block.

We’re now ready to get started!

Scaffolding our Project

We’ll update our main.dart file to contain our new HomePage widget found within home_page.dart:

import 'package:flutter/material.dart';

import 'home_page.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

Our HomePage widget will look something like this:

import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Location"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            FlatButton(
              child: Text("Get location"),
              onPressed: () {
                // Get location here
              },
            ),
          ],
        ),
      ),
    );
  }
}

Getting the Current Location

Now that we’ve established the basics for our project, let’s go ahead and update our HomePage widget to get the current location of a user.

We can do that by creating an instance of Geolocator and calling getCurrentPosition. This should ask the user whether they’re interested in using the Location feature, and if so, get the current location as a Position.

Here’s how it looks:

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

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  Position _currentPosition;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Location"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            if (_currentPosition != null)
              Text(
                  "LAT: ${_currentPosition.latitude}, LNG: ${_currentPosition.longitude}"),
            FlatButton(
              child: Text("Get location"),
              onPressed: () {
                _getCurrentLocation();
              },
            ),
          ],
        ),
      ),
    );
  }

  _getCurrentLocation() {
    final Geolocator geolocator = Geolocator()..forceAndroidLocationManager;

    geolocator
        .getCurrentPosition(desiredAccuracy: LocationAccuracy.best)
        .then((Position position) {
      setState(() {
        _currentPosition = position;
      });
    }).catchError((e) {
      print(e);
    });
  }
}

We should now be able to see the latitude and longitude on screen:

Geolocation

Converting this Into an Address

We don’t have to stop there though! We can get a Placemark which is essentially an approximation of the user’s current location from the latitude and longitude. Let’s see this in action:

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

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final Geolocator geolocator = Geolocator()..forceAndroidLocationManager;

  Position _currentPosition;
  String _currentAddress;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Location"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            if (_currentPosition != null) Text(_currentAddress),
            FlatButton(
              child: Text("Get location"),
              onPressed: () {
                _getCurrentLocation();
              },
            ),
          ],
        ),
      ),
    );
  }

  _getCurrentLocation() {
    geolocator
        .getCurrentPosition(desiredAccuracy: LocationAccuracy.best)
        .then((Position position) {
      setState(() {
        _currentPosition = position;
      });

      _getAddressFromLatLng();
    }).catchError((e) {
      print(e);
    });
  }

  _getAddressFromLatLng() async {
    try {
      List<Placemark> p = await geolocator.placemarkFromCoordinates(
          _currentPosition.latitude, _currentPosition.longitude);

      Placemark place = p[0];

      setState(() {
        _currentAddress =
            "${place.locality}, ${place.postalCode}, ${place.country}";
      });
    } catch (e) {
      print(e);
    }
  }
}

After getting the latitude and longitude, we’re now using _getAddressFromLatLng() to convert this into an address and display it on screen.

Here’s how it looks:

Geolocation with address

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#