geolocation 1.1.2

  • Readme
  • Changelog
  • Example
  • Installing
  • 96

geolocation #

pub package

Flutter geolocation plugin for Android API 16+ and iOS 9+.

Features:

  • Manual and automatic location permission management
  • Current one-shot location
  • Continuous location updates with foreground and background options

The plugin is under active development and the following features are planned soon:

  • Geocode
  • Geofences
  • Place suggestions
  • Activity recognition
  • Exposition of iOS/Android specific APIs (like significant location updates on iOS)
AndroidiOS

Installation #

Follow the instructions: https://pub.dev/packages/geolocation#-installing-tab-

iOS

Objective-C compatibility

For Flutter projects created with the Objective-C template, you might need to add use_frameworks! at the top of ios/Podfile. More details can be found in the following issue: https://github.com/flutter/flutter/issues/16049#issuecomment-552060349

Android

AndroidX

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

android.useAndroidX=true
android.enableJetifier=true
R8/Proguard code obfuscation

If you have enabled code obfuscation with R8 or proguard, you need to add the following rules.

android/app/build.gradle:

buildTypes {
  release {
    minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  }
}

android/app/proguard-rules.pro:

# Geolocation - start

-keep class app.loup.geolocation.** { *; }

    # Moshi - start
    # https://github.com/square/moshi/blob/master/moshi/src/main/resources/META-INF/proguard/moshi.pro

    # JSR 305 annotations are for embedding nullability information.
    -dontwarn javax.annotation.**

    -keepclasseswithmembers class * {
        @com.squareup.moshi.* <methods>;
    }

    -keep @com.squareup.moshi.JsonQualifier interface *

    # Enum field names are used by the integrated EnumJsonAdapter.
    # values() is synthesized by the Kotlin compiler and is used by EnumJsonAdapter indirectly
    # Annotate enums with @JsonClass(generateAdapter = false) to use them with Moshi.
    -keepclassmembers @com.squareup.moshi.JsonClass class * extends java.lang.Enum {
        <fields>;
        **[] values();
    }

    # Moshi - end

# Geolocation - end

Permission #

Android and iOS require to declare the location permission in a configuration file.

For iOS

There are two kinds of location permission available in iOS: "when in use" and "always".

If you don't know what permission to choose for your usage, see: https://developer.apple.com/documentation/corelocation/choosing_the_authorization_level_for_location_services

You need to declare the description for the desired permission in ios/Runner/Info.plist:

<dict>
  <!-- for iOS 11 + -->
  <key>NSLocationWhenInUseUsageDescription</key>
  <string>Reason why app needs location</string>
  <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
  <string>Reason why app needs location</string>

  <!-- additionally for iOS 9/10, if you need always permission -->
  <key>NSLocationAlwaysUsageDescription</key>
  <string>Reason why app needs location</string>
  ...
</dict>

For Android

There are two kinds of location permission in Android: "coarse" and "fine". Coarse location will allow to get 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.

API #

For more complete documentation on all usage, check the API documentation:
https://pub.dartlang.org/documentation/geolocation/latest/geolocation/geolocation-library.html

You can also check the example project that showcase a comprehensive usage of Geolocation plugin.

Check if location service is operational #

API documentation: https://pub.dartlang.org/documentation/geolocation/latest/geolocation/Geolocation/isLocationOperational.html

final GeolocationResult result = await Geolocation.isLocationOperational();
if(result.isSuccessful) {
  // location service is enabled, and location permission is granted
} else {
  // location service is not enabled, restricted, or location permission is denied
}

Request location permission #

On Android (api 23+) and iOS, apps need to request location permission at runtime.

Note: You are not required to request permission manually. Geolocation plugin will request permission automatically if it's needed, when you make a location request.

API documentation: https://pub.dartlang.org/documentation/geolocation/latest/geolocation/Geolocation/requestLocationPermission.html

final GeolocationResult result = await Geolocation.requestLocationPermission(
  const LocationPermission(
    android: LocationPermissionAndroid.fine,
    ios: LocationPermissionIOS.always,
  ),
  openSettingsIfDenied: true,
);

if(result.isSuccessful) {
  // location permission is granted (or was already granted before making the request)
} else {
  // location permission is not granted
  // user might have denied, but it's also possible that location service is not enabled, restricted, and user never saw the permission request dialog. Check the result.error.type for details.
}

Get the current one-shot location #

Geolocation offers three methods:

// get last known location, which is a future rather than a stream (best for android)
LocationResult result = await Geolocation.lastKnownLocation();

// force a single location update (best for ios)
StreamSubscription<LocationResult> subscription = Geolocation.currentLocation(accuracy: LocationAccuracy.best).listen((result) {
  // todo with result
});

// best option for most cases
StreamSubscription<LocationResult> subscription = Geolocation.currentLocation(accuracy: LocationAccuracy.best).listen((result) {
  if(result.isSuccessful) {
    Double latitude = result.location.latitude;
    // todo with result
  }
});

Continuous location updates #

API documentation: https://pub.dartlang.org/documentation/geolocation/latest/geolocation/Geolocation/locationUpdates.html

StreamSubscription<LocationResult> subscription = Geolocation.locationUpdates(
    accuracy: LocationAccuracy.best,
    displacementFilter: 10.0, // in meters
    inBackground: true, // by default, location updates will pause when app is inactive (in background). Set to `true` to continue updates in background.
  )
  .listen((result) {
    if(result.isSuccessful) {
      // todo with result
    }
  });


// cancelling subscription will also stop the ongoing location request
subscription.cancel();

Handle location result #

Location request return either a LocationResult future or a stream of LocationResult.

API documentation: https://pub.dartlang.org/documentation/geolocation/latest/geolocation/LocationResult-class.html

LocationResult result = await Geolocation.lastKnownLocation();

if (result.isSuccessful) {
  // location request successful, location is guaranteed to not be null
  double lat = result.location.latitude;
  double lng = result.location.longitude;
} else {
  switch (result.error.type) {
    case GeolocationResultErrorType.runtime:
      // runtime error, check result.error.message
      break;
    case GeolocationResultErrorType.locationNotFound:
      // location request did not return any result
      break;
    case GeolocationResultErrorType.serviceDisabled:
      // location services disabled on device
      // might be that GPS is turned off, or parental control (android)
      break;
    case GeolocationResultErrorType.permissionNotGranted:
      // location has not been requested yet
      // app must request permission in order to access the location
      break;
    case GeolocationResultErrorType.permissionDenied:
      // user denied the location permission for the app
      // rejection is final on iOS, and can be on Android if user checks `don't ask again`
      // user will need to manually allow the app from the settings, see requestLocationPermission(openSettingsIfDenied: true)
      break;
    case GeolocationResultErrorType.playServicesUnavailable:
      // android only
      // result.error.additionalInfo contains more details on the play services error
      switch(result.error.additionalInfo as GeolocationAndroidPlayServices) {
        // do something, like showing a dialog inviting the user to install/update play services
        case GeolocationAndroidPlayServices.missing:
        case GeolocationAndroidPlayServices.updating:
        case GeolocationAndroidPlayServices.versionUpdateRequired:
        case GeolocationAndroidPlayServices.disabled:
        case GeolocationAndroidPlayServices.invalid:
      }
    break;
  }
}

Authors #

Geolocation plugin is developed by Loup, a mobile development studio based in Montreal and Paris.
You can contact us at hello@loup.app

Contributers #

  • lukaspili
  • mit-mit
  • shehabic-work
  • Abgaryan
  • shehabic
  • alfanhui

License #

Apache License 2.0

1.1.2 #

  • Update streams_channel to 0.3.0. Fix related compilation warnings.
  • Update android dependencies and internal json communication

[1.1.1] #

  • Update gradle wrapper to version 5.6.2

[1.1.0] #

  • Breaking change : Geolocation.requestLocationPermission now takes a named parameter for permission
  • Breaking change : New GeolocationResultErrorType.permissionNotGranted type. Previous meaning for permissionDenied is now divided in two different states:
    • permissionNotGranted: User didn't accept nor decline the locationn permission request yet
    • permissionDenied: User specifically declined the permission request
  • Ability to open settings when requesting permission, and user already declined the permission previously: Geolocation.requestLocationPermission(openSettingsIfDenied: true) (opening the settings as fallback is now the default behaviour).
  • Fix background pause/resume on iOS
  • Refactor iOS internal structure

[1.0.2] #

  • Fix Accuracy.nearestTenMeters on iOS

[1.0.1] #

  • Update to streams_channel 0.2.3

[1.0.0] (thanks @alfanhui) #

  • Updated Kotlin to 1.3.41
  • Updated Kotlin experimental coroutines to Kotlinx
  • Updated Android packages to Androidx (hence major release increment)

[0.2.3] (thanks @alfanhui) #

  • Added updated pubspec description
  • Flutter format on number of files

[0.2.2] (thanks @alfanhui) #

  • Better encoding of 'options' on LocationUpdatesRequest [hoggetaylor]
  • Fix argument of type string can not be assigned to DiagnosticsNode [osamagamal65]
  • Adding support for new method to request enabling location services [shehabic]
  • Updated Readme [shehabic]
  • Various fixes for XCode 10, and Cocoa Pods 1.5.3 [shehabic]
  • Updated Google Play Services Version [shehabic]
  • Fixed serialization from dart to native platforms [shehabic]
  • Updated kotlin version [shehabic]

[0.2.1] #

  • Replace requestPermission(permission) named parameter by positional

[0.2.0] #

  • Refactor single one-shot location
  • Refactor permission management
  • Add continuous location updates support
  • Add in background support for location updates
  • Add request location permission manually
  • Add pause/resume location updates automatically when app goes to background/foreground
  • Add Stream API
  • Fix: Match play-services version to Flutter's firebase plugins
  • Fix: Dart 1.x compatibility

[0.1.1] #

  • Pubspec and documentation fixes

[0.1.0] - Initial release #

  • New feature: Last known location
  • New feature: Current location
  • New feature: Location updates

example/lib/main.dart

//  Copyright (c) 2018 Loup Inc.
//  Licensed under Apache License v2.0

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:geolocation/geolocation.dart';
import 'tab_location.dart';
import 'tab_track.dart';
import 'tab_settings.dart';

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

class MyApp extends StatefulWidget {
  MyApp() {
    Geolocation.loggingEnabled = true;
  }

  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new CupertinoTabScaffold(
        tabBar: new CupertinoTabBar(
          items: <BottomNavigationBarItem>[
            new BottomNavigationBarItem(
              title: new Text('Current'),
              icon: new Icon(Icons.location_on),
            ),
            new BottomNavigationBarItem(
              title: new Text('Track'),
              icon: new Icon(Icons.location_searching),
            ),
            new BottomNavigationBarItem(
              title: new Text('Services'),
              icon: new Icon(Icons.location_off),
            ),
            new BottomNavigationBarItem(
              title: new Text('Settings'),
              icon: new Icon(Icons.settings_input_antenna),
            ),
          ],
        ),
        tabBuilder: (BuildContext context, int index) {
          return new CupertinoTabView(
            builder: (BuildContext context) {
              switch (index) {
                case 0:
                  return new TabLocation();
                case 1:
                  return new TabTrack();
                case 3:
                  return new TabSettings();
                default:
                  return new Container(
                    color: Colors.white,
                    child: new Center(
                      child: new FlatButton(
                        color: Colors.blue,
                        child: Text(
                          "Enable location services",
                          style: TextStyle(color: Colors.white),
                        ),
                        onPressed: enableLocationServices,
                      ),
                    ),
                  );
              }
            },
          );
        },
      ),
    );
  }

  enableLocationServices() async {
    Geolocation.enableLocationServices().then((result) {
      // Request location
    }).catchError((e) {
      // Location Services Enablind Cancelled
    });
  }
}

Use this package as a library

1. Depend on it

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


dependencies:
  geolocation: ^1.1.2

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:geolocation/geolocation.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
91
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
96
Learn more about scoring.

We analyzed this package on Mar 27, 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

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
streams_channel ^0.3.0 0.3.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