grappuslocation 2.4.0

  • Readme
  • Changelog
  • Example
  • Installing
  • 59

Flutter Location Plugin pub package #

This plugin for Flutter handles getting location on Android and iOS. It also provides callbacks when location is changed.

Demo App

✨ New experimental feature ✨ #

To get location updates even your app is closed, you can see this wiki post.

Getting Started #

Android #

In order to use this plugin in Android, you have to add this permission in AndroidManifest.xml :

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

Update your file with this:


Please also make sure that you have those dependencies in your build.gradle:

  dependencies {
      classpath ''
      classpath ''
  compileSdkVersion 28

iOS #

And to use it in iOS, you have to add this permission in Info.plist :


Warning: there is a currently a bug in iOS simulator in which you have to manually select a Location several in order for the Simulator to actually send data. Please keep that in mind when testing in iOS simulator.

The OnNmeaMessageListener property is only available for minimum SDK of 24.

Example App #

The example app uses Google Maps Flutter Plugin, add your API Key in the AndroidManifest.xml and in AppDelegate.m to use the Google Maps plugin.

Sample Code #

Then you just have to import the package with

import 'package:location/location.dart';

Look into the example for utilisation, but a basic implementation can be done like this for a one time location :

var currentLocation = LocationData;

var location = new Location();

// Platform messages may fail, so we use a try/catch PlatformException.
try {
  currentLocation = await location.getLocation();
} on PlatformException catch (e) {
  if (e.code == 'PERMISSION_DENIED') {
    error = 'Permission denied';
  currentLocation = null;

You can also get continuous callbacks when your position is changing:

var location = new Location();

location.onLocationChanged().listen((LocationData currentLocation) {

Public Method Summary #

In this table you can find the different functions exposed by this plugin:

Request the Location permission. Return a boolean to know if the permission has been granted.
Return a boolean to know the state of the location permission.
Return a boolean to know if the Location Service is enabled or if the user manually deactivated it.
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. Return a boolean to know if the Location Service has been activated (always false on iOS).
Future<bool>changeSettings(LocationAccuracy accuracy = LocationAccuracy.HIGH, int interval = 1000, double distanceFilter = 0)
Will change the settings of futur requests. accuracywill describe the accuracy of the request (see the LocationAccuracy object). interval will set the desired interval for active location updates, in milliseconds (only affects Android). distanceFilter set the minimum displacement between location updates in meters.
Allow to get a one time position of the user. It will try to request permission if not granted yet and will throw a PERMISSION_DENIED error code if permission still not granted.
Get the stream of the user's location. It will try to request permission if not granted yet and will throw a PERMISSION_DENIED error code if permission still not granted.

You should try to manage permission manually with requestPermission() to avoid error, but plugin will try handle some cases for you.

Objects #

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 altitude; // In meters above the WGS 84 reference ellipsoid
  final double speed; // In meters/second
  final double speedAccuracy; // In meters/second, always 0 on iOS
  final double heading; //Heading is the horizontal direction of travel of this device, in degrees
  final double time; //timestamp of the LocationData

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 (affect only iOS)

Note: you can convert the timestamp into a DateTime with: DateTime.fromMillisecondsSinceEpoch(locationData.time.toInt())

Feedback #

Please feel free to give me any feedback helping support this plugin !

[2.4.0] 14th Februarty 2020 #

  • Align timestamp in Android and iOS, previously the iOS timestamp was in seconds instead of milliseconds. Thanks to 781flyingdutchman.

[2.3.7] 08th January 2020 #

  • Fix bug where requestPermission is called after the user has already denied the system location dialog, then this method call would never return.

[2.3.6] 07th January 2020 #

  • Fix ClassCastException errors on some Android phones when requesting Location status.

[2.3.5] 10th April 2019 #

  • Fix incompatibily with headless plugins thanks to ehhc
  • Fix error with iOS when permission already given
  • Add Google maps example

[2.3.4] 8th April 2019 #

  • Fix error on Android 21 API thanks to noordawod
  • Update Google API version

[2.3.3] 31th March 2019 #

  • Align altitude on Sea Level when available on Android (matching iOS altitude).

[2.3.2] 27th March 2019 #

  • Remove GPS limitation on Android

[2.3.1] 25th March 2019 #

  • Fixes README
  • Fixes requestPermission not responding the correct result on iOS

[2.3.0] 22nd March 2019 #

  • Update example App with proper cancel
  • Add possibility to set accuracy, interval and minimum notification ditance of the requests.
  • Add LocationAccuracy object

[2.2.0] 19th March 2019 #

  • Actually updating locatino when using getLocation (not only relying on LastLocation)
  • Add timestamp to LocationData
  • Add serviceEnabled method to check whether Location Service is enabled.
  • Add requestService method to ask the user to activate the location service.
  • Fix continuous callback heading

[2.1.0] 16th Match 2019 #

  • iOS permission should be closer to Android permission behaviour thanks to PerrchicK
  • Adding requestPermission(), to manually request permission
  • Several feature fixed for less crash when using the plugin
  • Code Cleanup
  • Update Readme and add a warning for the location bug in iOS simulator

[2.0.0] 25th January 2019 #

  • Code cleanup
  • BREAKING CHANGE: Change Dart API to return structured data rather than a map.

[1.4.0] 21st August 2018 #

  • Add lazy permission request thanks to yathit
  • Add hasPermission() thanks to vagrantrobbie
  • Bug correction thanks to jalpedersen
  • Add more examples

[1.3.4] 4th June 2018 #

  • Fix crash for Android API pre 27 thanks to matthewtsmith.

[1.3.3] 30th May 2018 #

  • Correct implementation of iOS plugin to match Android behaviour. No need to call getLocation to get permissions for location callbacks.

[1.3.2] 30th May 2018 #

  • Change implementation to api in build.gradle in order to solve incompatibilities between GMS versions thanks to luccascorrea

[1.3.1] 29th May 2018 #

  • Added speed and speed_accuracy (only Android truly discover speed accuracy, so its always 0 for now on iOS)
  • Solved a crash

[1.3.0] 27th May 2018 #

  • Make it compatible with Firebase thanks to quangIO
  • Resolve runtime error exception thanks to jharrison902
  • Update gitignore thanks to bcko

[1.2.0] 5th April 2018 #

  • Permissions denied on Android handled thanks to g123k
  • Dart 2 update thanks to efortuna

[1.1.6] - 19th Octobre 2017. #

  • iOS code from Swift to Objective-C thanks to fluff

[1.1.1] - 20th July 2017. #

  • Fixes for iOS result's format.

[1.1.0] - 17th July 2017. #

  • Added permission check for Android 6+ (thanks netdur). Still no callback when permissions granted so aiming SDK 21 is safer.

[1.0.0] - 7th July 2017. #

  • Initial Release.


import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:location/location.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

//import 'config.dart';

void main() {
  runApp(new MyApp());

class MyApp extends StatefulWidget {
  _MyAppState createState() => new _MyAppState();

class _MyAppState extends State<MyApp> {
  LocationData _startLocation;
  LocationData _currentLocation;

  StreamSubscription<LocationData> _locationSubscription;

  Location _locationService  = new Location();
  bool _permission = false;
  String error;

  bool currentWidget = true;

  Completer<GoogleMapController> _controller = Completer();
  static final CameraPosition _initialCamera = CameraPosition(
    target: LatLng(0, 0),
    zoom: 4,

  CameraPosition _currentCameraPosition;

  GoogleMap googleMap; 

  void initState() {


  // Platform messages are asynchronous, so we initialize in an async method.
  initPlatformState() async {
    await _locationService.changeSettings(accuracy: LocationAccuracy.HIGH, interval: 1000);
    LocationData location;
    // Platform messages may fail, so we use a try/catch PlatformException.
    try {
      bool serviceStatus = await _locationService.serviceEnabled();
      print("Service status: $serviceStatus");
      if (serviceStatus) {
        _permission = await _locationService.requestPermission();
        print("Permission: $_permission");
        if (_permission) {
          location = await _locationService.getLocation();

          _locationSubscription = _locationService.onLocationChanged().listen((LocationData result) async {
            _currentCameraPosition = CameraPosition(
              target: LatLng(result.latitude, result.longitude),
              zoom: 16

            final GoogleMapController controller = await _controller.future;

              setState(() {
                _currentLocation = result;
      } else {
        bool serviceStatusResult = await _locationService.requestService();
        print("Service status activated after request: $serviceStatusResult");
    } on PlatformException catch (e) {
      if (e.code == 'PERMISSION_DENIED') {
        error = e.message;
      } else if (e.code == 'SERVICE_STATUS_ERROR') {
        error = e.message;
      location = null;

    setState(() {
        _startLocation = location;


  slowRefresh() async {
    await _locationService.changeSettings(accuracy: LocationAccuracy.BALANCED, interval: 10000);
    _locationSubscription = _locationService.onLocationChanged().listen((LocationData result) {
        setState(() {
          _currentLocation = result;

  Widget build(BuildContext context) {
    List<Widget> widgets;

    googleMap = GoogleMap(
      mapType: MapType.normal,
      myLocationEnabled: true,
      initialCameraPosition: _initialCamera,
      onMapCreated: (GoogleMapController controller) {

    widgets = [
          child: SizedBox(
            height: 300.0,
            child: googleMap

    widgets.add(new Center(
        child: new Text(_startLocation != null
            ? 'Start location: ${_startLocation.latitude} & ${_startLocation.longitude}\n'
            : 'Error: $error\n')));

    widgets.add(new Center(
        child: new Text(_currentLocation != null
            ? 'Continuous location: \nlat: ${_currentLocation.latitude} & long: ${_currentLocation.longitude} \nalt: ${_currentLocation.altitude}m\n'
            : 'Error: $error\n', textAlign:;

    widgets.add(new Center(
      child: new Text(_permission 
            ? 'Has permission : Yes' 
            : "Has permission : No")));

    widgets.add(new Center(
      child: new RaisedButton(
        child: new Text("Slow refresh rate and accuracy"),
        onPressed: () => slowRefresh()

    return new MaterialApp(
        home: new Scaffold(
            appBar: new AppBar(
              title: new Text('Location plugin example app'),
            body: new Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: widgets,
            floatingActionButton: new FloatingActionButton(
              onPressed: () => _locationSubscription.cancel(),
              tooltip: 'Stop Track Location',
              child: Icon(Icons.stop),
            floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:

  grappuslocation: ^2.4.0

2. Install it

You can install packages from the command line:

with Flutter:

$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:grappuslocation/location.dart';
Describes how popular the package is relative to other packages. [more]
Code health derived from static analysis. [more]
Reflects how tidy and up-to-date the package is. [more]
Weighted score of the above. [more]
Learn more about scoring.

We analyzed this package on Apr 7, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.1
  • pana: 0.13.6
  • Flutter: 1.12.13+hotfix.8


Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8