GPS has become a standard feature on modern smartphones. It's usually used by applications to get the device location. This tutorial shows you how to access device location in Flutter using GPS, including how to get permissions, get current location and continuous location update.
Dependencies
A Flutter package geolocator
provides geolocation functionalities. Add it in your pubspec.yaml
file and run Get Packages.
dependencies {
...
geolocator: ^3.0.1
...
}
Permissions
You need to add permissions to each platform. For Android, you need ACCESS_FINE_LOCATION
and ACCESS_COARSE_LOCATION. Add the following in
AndroidManifest.xml
.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
For iOS, you need NSLocationWhenInUseUsageDescription
permission. Add it in the Info.plist
file.
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when open.</string>
Code Example
Below is the code structure for this tutorial. We need to create an instance of Geolocator
and store the value of latest Position
. The application will use the Position
value to display the latitude and the longitude.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
class GeolocationExampleState extends State<GeolocationExample> {
Geolocator _geolocator;
Position _position;
@override
void initState() {
super.initState();
_geolocator = Geolocator();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Geolocation Example'),
),
body: Center(
child: Text(
'Latitude: ${_position != null ? _position.latitude.toString() : '0'},'
' Longitude: ${_position != null ? _position.longitude.toString() : '0'}'
)
),
);
}
}
Check Permission
If you've added the right permissions, the application will be granted with permissions to access the device location using GPS. In Android 6.0 and above, it will ask the user to grant the permission. But if you need to check whether the application has permission to access location, you can do it programatically. To do so, use checkGeolocationPermissionStatus
method which returns Future<GeolocationState>. Optionally, for iOS, you can check locationAlways
and locationWhenInUse
separately by passing locationPermission
optional parameter whose type is GeolocationPermission
void checkPermission() {
_geolocator.checkGeolocationPermissionStatus().then((status) { print('status: $status'); });
_geolocator.checkGeolocationPermissionStatus(locationPermission: GeolocationPermission.locationAlways).then((status) { print('always status: $status'); });
_geolocator.checkGeolocationPermissionStatus(locationPermission: GeolocationPermission.locationWhenInUse)..then((status) { print('whenInUse status: $status'); });
}
Get Current Location
Getting the current location is very simple. Just use getCurrentPosition
method which returns Future<Location>
. You can pass desiredAccuracy
option.
await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high)
Sometimes the process of getting current location may fail, for example if the user turns off the GPS sensor. If it has been turned of since the beginning, it may cause error, so we need to catch the error. There's also possible the GPS is turned off while the process of finding location is on going. On this case, it may cause the process stuck, and therefore it's better to add execution timeout.
void updateLocation() async {
try {
Position newPosition = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high)
.timeout(new Duration(seconds: 5));
setState(() {
_position = newPosition;
});
} catch (e) {
print('Error: ${e.toString()}');
}
}
Below are the descriptions of each LocationAccuracy
value.
Name | Description |
---|---|
lowest |
Location is accurate within a distance of 3000m on iOS and 500m on Android. |
low |
Location is accurate within a distance of 1000m on iOS and 500m on Android. |
medium |
Location is accurate within a distance of 10m on iOS and between 0m and 100m on Android. |
high |
Location is accurate within a distance of 10m on iOS and between 0m and 100m on Android. |
best |
Location is accurate within a distance of ~0m on iOS and between 0m and 100m on Android. |
bestForNavigation |
Location is accuracy is optimized for navigation on iOS and matches LocationAccuracy.best on Android. |
Location Update Stream
To get the updated location, actually you can put the code above in a while loop. But, there's a better and cleaner way. You can use getPositionStream
which returns Stream<Subscription>
. You can also set how much location change is needed before the listener is notified using distanceFilter
.
LocationOptions locationOptions = LocationOptions(accuracy: LocationAccuracy.high, distanceFilter: 1);
StreamSubscription positionStream = _geolocator.getPositionStream(locationOptions).listen(
(Position position) {
_position = position;
});
Below is the full code of this tutorial
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Geolocation',
home: GeolocationExample(),
);
}
}
class GeolocationExampleState extends State {
Geolocator _geolocator;
Position _position;
void checkPermission() {
_geolocator.checkGeolocationPermissionStatus().then((status) { print('status: $status'); });
_geolocator.checkGeolocationPermissionStatus(locationPermission: GeolocationPermission.locationAlways).then((status) { print('always status: $status'); });
_geolocator.checkGeolocationPermissionStatus(locationPermission: GeolocationPermission.locationWhenInUse)..then((status) { print('whenInUse status: $status'); });
}
@override
void initState() {
super.initState();
_geolocator = Geolocator();
LocationOptions locationOptions = LocationOptions(accuracy: LocationAccuracy.high, distanceFilter: 1);
checkPermission();
// updateLocation();
StreamSubscription positionStream = _geolocator.getPositionStream(locationOptions).listen(
(Position position) {
_position = position;
});
}
void updateLocation() async {
try {
Position newPosition = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high)
.timeout(new Duration(seconds: 5));
setState(() {
_position = newPosition;
});
} catch (e) {
print('Error: ${e.toString()}');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Startup Name Generator'),
),
body: Center(
child: Text(
'Latitude: ${_position != null ? _position.latitude.toString() : '0'},'
' Longitude: ${_position != null ? _position.longitude.toString() : '0'}'
)
),
);
}
}
class GeolocationExample extends StatefulWidget {
@override
GeolocationExampleState createState() => new GeolocationExampleState();
}
.