# location
[![location on pub.dev][location_badge]][location_link]
[![code style][leancode_lint_badge]][leancode_lint_link]
[![powered by][docs_page_badge]][docs_page_link]
[![codecov][codecov_badge]][codecov_link]
This plugin for [Flutter](https://flutter.dev)
handles getting a location across Android, iOS, macOS, web, Windows and Linux.
It also provides callbacks when the location is changed.
| Android | iOS | macOS | Web | Windows | Linux |
| :-----: | :-: | :---: | :-: | :-----: | :---: |
| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Background mode is available on Android and iOS. Windows relies on
`Windows.Devices.Geolocation` and Linux on GeoClue2 (over D-Bus); both require
the system location service to be enabled.
[Web demo](https://lyokone.github.io/flutterlocation) (more features available on Android/iOS)
## Getting Started
Add this to your package's `pubspec.yaml` file:
```yaml
dependencies:
location: ^10.0.0
```
### Android
To use location background mode on Android, you have to use the enableBackgroundMode({bool enable}) API before accessing location in the background and adding necessary permissions. You should place the required permissions in your applications /android/app/src/main/AndroidManifest.xml:
```xml
```
Remember that the user has to accept the location permission to `always allow` to use the background location. The Android 11 option to `always allow` is not presented on the location permission dialog prompt. The user has to enable it manually from the app settings. This should be explained to the user on a separate UI that redirects the user to the app's location settings managed by the operating system. More on that topic can be found on [Android developer](https://developer.android.com/training/location/permissions#request-background-location) pages.
### iOS
And to use it in iOS, you have to add this permission in Info.plist :
```
// This is probably the only one you need. Background location is supported
// by this -- the caveat is that a blue badge is shown in the status bar
// when the app is using location service while in the background.
NSLocationWhenInUseUsageDescription
// Deprecated, use NSLocationAlwaysAndWhenInUseUsageDescription instead.
NSLocationAlwaysUsageDescription
// Use this very carefully. This key is required only if your iOS app
// uses APIs that access the user’s location information at all times,
// even if the app isn't running.
NSLocationAlwaysAndWhenInUseUsageDescription
```
To receive location when application is in background, to Info.plist you have to add property list key :
```xml
UIBackgroundModes
```
with string value:
```xml
location
```
### Web
Nothing to do, the plugin works directly out of box.
### macOS
Ensure that the application is properly "sandboxed" and that the location is enabled. You can do this in Xcode with the following steps:
1. In the project navigator, click on your application's target. This should bring up a view with tabs such as "General", "Capabilities", "Resource Tags", etc.
1. Click on the "Capabilities" tab. This will give you a list of items such as "App Groups", "App Sandbox", and so on. Each item will have an "On/Off" button.
1. Turn on the "App Sandbox" item and press the ">" button on the left to show the sandbox stuff.
1. In the "App Data" section, select "Location".
Add this permission in Info.plist :
```xml
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
```
### Windows
Nothing to do. The plugin uses the `Windows.Devices.Geolocation` APIs, which
prompt the user for location access on first use. Make sure Location is enabled
in the Windows privacy settings.
### Linux
The plugin talks to [GeoClue2](https://gitlab.freedesktop.org/geoclue/geoclue)
over D-Bus, so a running `geoclue` service is required (it ships with most
desktop distributions). No extra dependency needs to be bundled with your app.
## Usage
Then you just have to import the package with
```dart
import 'package:location/location.dart';
```
In order to request location, you should always check Location Service status and Permission status manually
```dart
Location location = Location();
bool serviceEnabled;
PermissionStatus permissionGranted;
LocationData locationData;
serviceEnabled = await location.serviceEnabled();
if (!serviceEnabled) {
serviceEnabled = await location.requestService();
if (!serviceEnabled) {
return;
}
}
permissionGranted = await location.hasPermission();
if (permissionGranted == PermissionStatus.denied) {
permissionGranted = await location.requestPermission();
if (permissionGranted != PermissionStatus.granted) {
return;
}
}
locationData = await location.getLocation();
```
You can also get continuous callbacks when your position is changing:
```dart
location.onLocationChanged.listen((LocationData currentLocation) {
// Use current location
});
```
To receive location when application is in background you have to enable it:
```dart
location.enableBackgroundMode(enable: true)
```
`enableBackgroundMode(enable: true)` is a standalone call: you can invoke it
**before** you start listening to `onLocationChanged`. On Android it also
requests the `ACCESS_BACKGROUND_LOCATION` permission when it has not been granted
yet, so you can use it to prompt for background permission independently, without
having to activate a location stream first.
**This only keeps tracking location while your app process is alive** — on
Android via a foreground service, on iOS via a background execution exemption.
Neither survives the user manually killing the app (swiping it away from the
recent-apps list) or the OS terminating it outright; there is no way for any
Flutter plugin to run Dart code once the process itself no longer exists. If
you need tracking that resumes after the app is killed/terminated, look at a
plugin built around native background services designed for that, such as
[`flutter_background_geolocation`](https://pub.dev/packages/flutter_background_geolocation).
Be sure to check the example project to get other code samples.
On Android, a foreground notification is displayed with information that location service is running in the background.
On iOS, while the app is in the background and gets the location, the blue system bar notifies users about updates. Tapping on this bar moves the User back to the app.
## Public Methods Summary
| Return | Description |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Future\ | **requestPermission()**
Request the Location permission. Returns a `PermissionStatus` to know if the permission has been granted. |
| Future\ | **hasPermission()**
Returns a `PermissionStatus` to know the state of the location permission. |
| Future\ | **isBackgroundPermissionGranted()**
Whether background ("Allow all the time"/Always) location access has been granted, separately from foreground access. Always `false` on web. |
| Future\ | **serviceEnabled()**
Returns a boolean to know if the Location Service is enabled or if the user manually deactivated it. |
| Future\ | **requestService()**
Show an alert dialog to request the user to activate the Location Service. On iOS, will only display an alert due to Apple Guidelines, the user having to manually go to Settings. Returns a boolean to know if the Location Service has been activated (always `false` on iOS). |
| Future\ | **changeSettings({accuracy, interval, distanceFilter, pausesLocationUpdatesAutomatically, backgroundInterval})**
Changes the settings of future requests. `interval`/`distanceFilter`/`backgroundInterval` are Android-only; `pausesLocationUpdatesAutomatically` is iOS/macOS-only. See [settings](https://docs.page/Lyokone/flutterlocation/features/settings) for details. |
| Future\ | **getLocation()**
Gets a one-time position of the user. Requests permission if not already granted, and throws a `PERMISSION_DENIED` error if permission still isn't granted. |
| Future\ | **getLastKnownLocation()**
Returns the most recently cached location immediately (or `null` if none is available), without waiting for a fresh fix. Always `null` on web. |
| Stream\ | **onLocationChanged**
Stream of the user's location. Requests permission if not already granted, and throws a `PERMISSION_DENIED` error if permission still isn't granted. |
| Future\ | **isBackgroundModeEnabled()**
Checks whether background mode is currently enabled. |
| Future\ | **enableBackgroundMode({enable, requireBackgroundPermission})**
Enables or disables retrieving location events in the background (Android/iOS only). `requireBackgroundPermission` (Android only, default `true`) controls whether `ACCESS_BACKGROUND_LOCATION` is required. |
| Future\ | **changeNotificationOptions({channelName, title, iconName, imageName, iconBytes, imageBytes, subtitle, description, color, onTapBringToFront})**
Customizes the Android background-mode notification. See [notifications](https://docs.page/Lyokone/flutterlocation/features/notification). |
You should try to manage permission manually with `requestPermission()` to avoid error, but plugin will try handle some cases for you.
## Objects
```dart
class LocationData {
final double latitude; // Latitude, in degrees
final double longitude; // Longitude, in degrees
final double? accuracy; // Estimated horizontal accuracy of this location, radial, in meters
final double? verticalAccuracy; // Estimated vertical accuracy of altitude, in meters
final double? altitude; // In meters above the WGS 84 reference ellipsoid
final double? speed; // In meters/second
final double? speedAccuracy; // In meters/second. Not available on web
final double? heading; // Horizontal direction of travel of this device, in degrees
final double? time; // Timestamp of the LocationData
final bool? isMock; // Is the location currently mocked
final bool? isProducedByAccessory; // Whether the fix came from a connected accessory (e.g. external GPS). iOS/macOS only
final double? headingAccuracy; // Estimated bearing accuracy, in degrees. Android only
final double? elapsedRealtimeNanos; // Time of this fix, in elapsed real-time since system boot. Android only
final double? elapsedRealtimeUncertaintyNanos; // Uncertainty of elapsedRealtimeNanos. Android only
final int? satelliteNumber; // Number of satellites used to derive the fix. Android only
final String? provider; // Name of the provider that generated this fix. Android only
}
enum LocationAccuracy {
powerSave, // To request best accuracy possible with zero additional power consumption
low, // To request "city" level accuracy
balanced, // To request "block" level accuracy
high, // To request the most accurate locations available
navigation, // To request location for navigation usage (affects only iOS)
reduced, // Maps to kCLLocationAccuracyReduced on iOS 14+; equivalent to `low` elsewhere
}
// Status of a permission request to use location services.
enum PermissionStatus {
/// The permission to use location services has been granted for high accuracy.
granted,
/// The permission has been granted but for low (approximate) accuracy only.
grantedLimited,
/// The permission to use location services has been denied by the user. May have been denied forever on iOS.
denied,
/// The permission to use location services has been denied forever by the user. No dialog will be displayed on permission request.
deniedForever
}
```
`LocationData` also has `toJson()`/`fromJson()` and `copyWith()` for serialization and copying.
Note: you can convert the timestamp into a `DateTime` with: `DateTime.fromMillisecondsSinceEpoch(locationData.time!.toInt())`
## Feedback
Please feel free to [give me any feedback](https://github.com/Lyokone/flutterlocation/issues)
helping support this plugin !
[location_badge]: https://img.shields.io/pub/v/location?label=location
[location_link]: https://pub.dev/packages/location
[leancode_lint_badge]: https://img.shields.io/badge/code%20style-leancode__lint-black
[leancode_lint_link]: https://pub.dev/packages/leancode_lint
[docs_page_badge]: https://img.shields.io/badge/documentation-docs.page-34C4AC.svg?style
[docs_page_link]: https://docs.page
[codecov_badge]: https://codecov.io/gh/Lyokone/flutterlocation/branch/master/graph/badge.svg
[codecov_link]: https://codecov.io/gh/Lyokone/flutterlocation