Android and iOS Geolocation plugin for Flutter

Overview

Flutter Geolocator Plugin

pub package Build status style: effective dart codecov

A Flutter geolocation plugin which provides easy access to platform specific location services (FusedLocationProviderClient or if not available the LocationManager on Android and CLLocationManager on iOS).

Features

  • Get the last known location;
  • Get the current location of the device;
  • Get continuous location updates;
  • Check if location services are enabled on the device;
  • Calculate the distance (in meters) between two geocoordinates;
  • Calculate the bearing between two geocoordinates;

IMPORTANT:

Version 7.0.0 of the geolocator plugin contains several breaking changes, for a complete overview please have a look at the Breaking changes in 7.0.0 wiki page.

Starting from version 6.0.0 the geocoding features (placemarkFromAddress and placemarkFromCoordinates) are no longer part of the geolocator plugin. We have moved these features to their own plugin: geocoding. This new plugin is an improved version of the old methods.

Usage

To add the geolocator to your Flutter application read the install instructions. Below are some Android and iOS specifics that are required for the geolocator to work correctly.

Android

Upgrade pre 1.12 Android projects

Since version 5.0.0 this plugin is implemented using the Flutter 1.12 Android plugin APIs. Unfortunately this means App developers also need to migrate their Apps to support the new Android infrastructure. You can do so by following the Upgrading pre 1.12 Android projects migration guide. Failing to do so might result in unexpected behaviour.

AndroidX

The geolocator plugin requires the AndroidX version of the Android Support Libraries. This means you need to make sure your Android project supports AndroidX. Detailed instructions can be found here.

The TL;DR version is:

  1. Add the following to your "gradle.properties" file:
android.useAndroidX=true
android.enableJetifier=true
  1. Make sure you set the compileSdkVersion in your "android/app/build.gradle" file to 30:
android {
  compileSdkVersion 30

  ...
}
  1. Make sure you replace all the android. dependencies to their AndroidX counterparts (a full list can be found here: https://developer.android.com/jetpack/androidx/migrate).

Permissions

On Android you'll need to add either the ACCESS_COARSE_LOCATION or the ACCESS_FINE_LOCATION permission to your Android Manifest. To do so open the AndroidManifest.xml file (located under android/app/src/main) and add one of the following two lines as direct children of the <manifest> tag (when you configure both permissions the ACCESS_FINE_LOCATION will be used be the geolocator plugin):

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

Starting from Android 10 you need to add the ACCESS_BACKGROUND_LOCATION permission (next to the ACCESS_COARSE_LOCATION or the ACCESS_FINE_LOCATION permission) if you want to continue receiving updates even when your App is running in the background (note that the geolocator plugin doesn't support receiving an processing location updates while running in the background):

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

NOTE: Specifying the ACCESS_COARSE_LOCATION permission results in location updates with an accuracy approximately equivalent to a city block. It might take a long time (minutes) before you will get your first locations fix as ACCESS_COARSE_LOCATION will only use the network services to calculate the position of the device. More information can be found here.

iOS

On iOS you'll need to add the following entries to your Info.plist file (located under ios/Runner) in order to access the device's location. Simply open your Info.plist file and add the following:

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

If you would like to receive updates when your App is in the background, you'll also need to add the Background Modes capability to your XCode project (Project > Signing and Capabilities > "+ Capability" button) and select Location Updates. Be careful with this, you will need to explain in detail to Apple why your App needs this when submitting your App to the AppStore. If Apple isn't satisfied with the explanation your App will be rejected.

Web

To use the Geolocator plugin on the web you need to be using Flutter 1.20 or higher. Flutter will automatically add the endorsed geolocator_web package to your application when you add the geolocator: ^6.2.0 dependency to your pubspec.yaml.

Note that the following methods of the geolocator API are not supported on the web and will result in a PlatformException with the code UNSUPPORTED_OPERATION:

  • getLastKnownPosition({ bool forceAndroidLocationManager = true })
  • openAppSettings()
  • openLocationSettings()

Example

The code below shows an example on how to acquire the current position of the device, including checking if the location services are enabled and checking / requesting permission to access the position of the device:

import 'package:geolocator/geolocator.dart';

/// Determine the current position of the device.
///
/// When the location services are not enabled or permissions
/// are denied the `Future` will return an error.
Future<Position> _determinePosition() async {
  bool serviceEnabled;
  LocationPermission permission;

  // Test if location services are enabled.
  serviceEnabled = await Geolocator.isLocationServiceEnabled();
  if (!serviceEnabled) {
    // Location services are not enabled don't continue
    // accessing the position and request users of the 
    // App to enable the location services.
    return Future.error('Location services are disabled.');
  }

  permission = await Geolocator.checkPermission();
  if (permission == LocationPermission.denied) {
    permission = await Geolocator.requestPermission();
    if (permission == LocationPermission.denied) {
      // Permissions are denied, next time you could try
      // requesting permissions again (this is also where
      // Android's shouldShowRequestPermissionRationale 
      // returned true. According to Android guidelines
      // your App should show an explanatory UI now.
      return Future.error('Location permissions are denied');
    }
  }
  
  if (permission == LocationPermission.deniedForever) {
    // Permissions are denied forever, handle appropriately. 
    return Future.error(
      'Location permissions are permanently denied, we cannot request permissions.');
  }

  // When we reach here, permissions are granted and we can
  // continue accessing the position of the device.
  return await Geolocator.getCurrentPosition();
}

API

Geolocation

To query the current location of the device simply make a call to the getCurrentPosition method. You can finetune the results by specifying the following parameters:

  • desiredAccuracy: the accuracy of the location data that your app wants to receive;
  • timeLimit: the maximum amount of time allowed to acquire the current location. When the time limit is passed a TimeOutException will be thrown and the call will be cancelled. By default no limit is configured.
import 'package:geolocator/geolocator.dart';

Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);

To query the last known location retrieved stored on the device you can use the getLastKnownPosition method (note that this can result in a null value when no location details are available):

import 'package:geolocator/geolocator.dart';

Position position = await Geolocator.getLastKnownPosition();

To listen for location changes you can call the getPositionStream to receive stream you can listen to and receive position updates. You can finetune the results by specifying the following parameters:

  • desiredAccuracy: the accuracy of the location data that your app wants to receive;
  • distanceFilter: the minimum distance (measured in meters) a device must move horizontally before an update event is generated;
  • timeInterval: (Android only) the minimum amount of time that needs to pass before an update event is generated;
  • timeLimit: the maximum amount of time allowed between location updates. When the time limit is passed a TimeOutException will be thrown and the stream will be cancelled. By default no limit is configured.
import 'package:geolocator/geolocator.dart';

StreamSubscription<Position> positionStream = Geolocator.getPositionStream(locationOptions).listen(
    (Position position) {
        print(position == null ? 'Unknown' : position.latitude.toString() + ', ' + position.longitude.toString());
    });

To check if location services are enabled you can call the isLocationServiceEnabled method:

import 'package:geolocator/geolocator.dart';

bool isLocationServiceEnabled  = await Geolocator.isLocationServiceEnabled();

Permissions

The geolocator will automatically try to request permissions when you try to acquire a location through the getCurrentPosition or getPositionStream methods. We do however provide methods that will allow you to manually handle requesting permissions.

If you want to check if the user already granted permissions to acquire the device's location you can make a call to the checkPermission method:

import 'package:geolocator/geolocator.dart';

LocationPermission permission = await Geolocator.checkPermission();

If you want to request permission to access the device's location you can call the requestPermission method:

import 'package:geolocator/geolocator.dart';

LocationPermission permission = await Geolocator.requestPermission();

Possible results from the checkPermission and requestPermission methods are:

Permission Description
denied Permission to access the device's location is denied by the user. You are free to request permission again (this is also the initial permission state).
deniedForever Android only: Permission to access the device's location is denied forever. If requesting permission the permission dialog will NOT been shown until the user updates the permission in the App settings.
whileInUse Permission to access the device's location is allowed only while the App is in use.
always Permission to access the device's location is allowed even when the App is running in the background.

Settings

In some cases it is necessary to ask the user and update their device settings. For example when the user initially permanently denied permissions to access the device's location or if the location services are not enabled (and, on Android, automatic resolution didn't work). In these cases you can use the openAppSettings or openLocationSettings methods to immediately redirect the user to the device's settings page.

On Android the openAppSettings method will redirect the user to the App specific settings where the user can update necessary permissions. The openLocationSettings method will redirect the user to the location settings where the user can enable/ disable the location services.

On iOS we are not allowed to open specific setting pages so both methods will redirect the user to the Settings App from where the user can navigate to the correct settings category to update permissions or enable/ disable the location services.

import 'package:geolocator/geolocator.dart';

await Geolocator.openAppSettings();
await Geolocator.openLocationSettings();

Utility methods

To calculate the distance (in meters) between two geocoordinates you can use the distanceBetween method. The distanceBetween method takes four parameters:

Parameter Type Description
startLatitude double Latitude of the start position
startLongitude double Longitude of the start position
endLatitude double Latitude of the destination position
endLongitude double Longitude of the destination position
import 'package:geolocator/geolocator.dart';

double distanceInMeters = Geolocator.distanceBetween(52.2165157, 6.9437819, 52.3546274, 4.8285838);

If you want to calculate the bearing between two geocoordinates you can use the bearingBetween method. The bearingBetween method also takes four parameters:

Parameter Type Description
startLatitude double Latitude of the start position
startLongitude double Longitude of the start position
endLatitude double Latitude of the destination position
endLongitude double Longitude of the destination position
import 'package:geolocator/geolocator.dart';

double bearing = Geolocator.bearingBetween(52.2165157, 6.9437819, 52.3546274, 4.8285838);

Location accuracy

The table below outlines the accuracy options per platform:

Android iOS
lowest 500m 3000m
low 500m 1000m
medium 100 - 500m 100m
high 0 - 100m 10m
best 0 - 100m ~0m
bestForNavigation 0 - 100m Optimized for navigation

Issues

Please file any issues, bugs or feature requests as an issue on our GitHub page. Commercial support is available, you can contact us at [email protected].

Want to contribute

If you would like to contribute to the plugin (e.g. by improving the documentation, solving a bug or adding a cool new feature), please carefully review our contribution guide and send us your pull request.

Author

This Geolocator plugin for Flutter is developed by Baseflow.

Comments
  • geolocator.getCurrentPosition take a long time to return position on IOS

    geolocator.getCurrentPosition take a long time to return position on IOS

    getCurrentPosition is working really fine on Android, but on IOS it took so much time to execute. Can you check it? Thank you Platform:

    • [ x] :iphone: iOS
    • [ ] :robot: Android
    type: bug type: duplicate platform: ios 
    opened by hungtran2492 87
  • Leak on terminated app

    Leak on terminated app

    ๐Ÿ› Bug Report

    I wanted to try to listen to locations even after i terminate app so i added

                notificationText:
                "Example app will continue to receive your location even when you aren't using it",
                notificationTitle: "Running in Background",
                enableWakeLock: true,
              )
    

    to settings. But when i terminate the app i get this leak

    E/ActivityThread(13871): Activity com.enviroapp.enviroapp.MainActivity has leaked ServiceConnection com.baseflow.geolocator.GeolocatorPlugin$1@576aec9 that was originally bound here
    E/ActivityThread(13871): android.app.ServiceConnectionLeaked: Activity com.enviroapp.enviroapp.MainActivity has leaked ServiceConnection com.baseflow.geolocator.GeolocatorPlugin$1@576aec9 that was originally bound here
    E/ActivityThread(13871): 	at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:1811)
    E/ActivityThread(13871): 	at android.app.LoadedApk.getServiceDispatcherCommon(LoadedApk.java:1683)
    E/ActivityThread(13871): 	at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:1662)
    E/ActivityThread(13871): 	at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1819)
    E/ActivityThread(13871): 	at android.app.ContextImpl.bindService(ContextImpl.java:1749)
    E/ActivityThread(13871): 	at android.content.ContextWrapper.bindService(ContextWrapper.java:756)
    E/ActivityThread(13871): 	at com.baseflow.geolocator.GeolocatorPlugin.onAttachedToActivity(GeolocatorPlugin.java:126)
    E/ActivityThread(13871): 	at io.flutter.embedding.engine.FlutterEngineConnectionRegistry.add(FlutterEngineConnectionRegistry.java:155)
    E/ActivityThread(13871): 	at io.flutter.plugins.GeneratedPluginRegistrant.registerWith(GeneratedPluginRegistrant.java:29)
    E/ActivityThread(13871): 	at java.lang.reflect.Method.invoke(Native Method)
    E/ActivityThread(13871): 	at io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister.registerGeneratedPlugins(GeneratedPluginRegister.java:80)
    E/ActivityThread(13871): 	at io.flutter.embedding.android.FlutterActivity.configureFlutterEngine(FlutterActivity.java:1004)
    E/ActivityThread(13871): 	at io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.onAttach(FlutterActivityAndFragmentDelegate.java:191)
    E/ActivityThread(13871): 	at io.flutter.embedding.android.FlutterActivity.onCreate(FlutterActivity.java:459)
    E/ActivityThread(13871): 	at android.app.Activity.performCreate(Activity.java:8000)
    E/ActivityThread(13871): 	at android.app.Activity.performCreate(Activity.java:7984)
    E/ActivityThread(13871): 	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
    E/ActivityThread(13871): 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
    E/ActivityThread(13871): 	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
    E/ActivityThread(13871): 	at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
    E/ActivityThread(13871): 	at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
    E/ActivityThread(13871): 	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
    E/ActivityThread(13871): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
    E/ActivityThread(13871): 	at android.os.Handler.dispatchMessage(Handler.java:106)
    E/ActivityThread(13871): 	at android.os.Looper.loop(Looper.java:223)
    E/ActivityThread(13871): 	at android.app.ActivityThread.main(ActivityThread.java:7656)
    E/ActivityThread(13871): 	at java.lang.reflect.Method.invoke(Native Method)
    E/ActivityThread(13871): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
    E/ActivityThread(13871): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
    D/FlutterGeolocator(13871): Binding to location service.
    D/FlutterGeolocator(13871): Destroying location service.
    D/FlutterGeolocator(13871): Stop service in foreground.
    

    Expected behavior

    Wanted to fetch data in terminated state

    Reproduction steps

    I didnt find anything in issues..

    Configuration

    Same as in example Version: ^8.2.0

    Platform:

    • [x] :robot: Android
    platform: android status: triage 
    opened by bujdy 68
  • Future never resolves on IOS13

    Future never resolves on IOS13

    ๐Ÿ› Bug Report

    When I try to getCurrentLocation, it never resolves. I'm not expert on IOS, so please if I forgot to do something, just explain it to me.

    Future<Position> getCurrentPosition({
        LocationAccuracy accuracy = LocationAccuracy.best,
        GeolocationPermission geolocationPermission =
            GeolocationPermission.location,
      }) =>
          _geolocator.getCurrentPosition(
            desiredAccuracy: accuracy,
            locationPermissionLevel: geolocationPermission,
          );
    

    Podfile:

    config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
            '$(inherited)',
    
            ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
             'PERMISSION_LOCATION=1',
          ]
    

    Info.plist:

    	<key>NSLocationWhenInUseUsageDescription</key>
    	<string>Need location when in use</string>
    	<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
    	<string>Always and when in use!</string>
    	<key>NSLocationUsageDescription</key>
    	<string>Older devices need location.</string>
    	<key>NSLocationAlwaysUsageDescription</key>
    	<string>Can I haz location always?</string>
    

    EDIT:

    I've tested on a real Android device and the problem is happening too.

    My manifest location permissions:

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

    Expected behavior

    Return a Position.

    Reproduction steps

    Just call geolocator.GetCurrentPosition.

    Version: 5.1.5.

    Platform:

    • [x] :iphone: iOS (Tested with IOS Simulator)
    • [x] :robot: Android (Tested on a Xiomi Pocophone F1 with Android 10QkQ1.190828.002)
    platform: ios platform: android status: triage 
    opened by brenoasm 63
  • Android Pie (API 28) Geolocator().getCurrentPosition() does not return

    Android Pie (API 28) Geolocator().getCurrentPosition() does not return

    ๐Ÿ› Bug Report

    When I run Geolocator().getCurrentPosition() on Android Emulator with Android Pie (API 28) call is not returning at all.

    I run the same code on API 27 location returns fine. I tried to create new emulator, nothing changes.

    Configuration

    Android Emulator with Android Pie (API 28)

    Version: 2.1.0

    Platform:

    • [ ] :iphone: iOS
    • [X ] :robot: Android
    platform: android 
    opened by savjolovs 39
  • Allow only while using the app in android 10 returns GeolocationStatus.denied

    Allow only while using the app in android 10 returns GeolocationStatus.denied

    ๐Ÿ› Bug Report

    when selecting Allow only while using the app the new option in Android 10 Geolocator().checkGeolocationPermissionStatus() returns GeolocationStatus.denied Screenshot_1570103723

    Version: 5.1.4

    Platform: :robot: Android

    platform: android status: in progress 
    opened by humazed 37
  • Get user location through browser

    Get user location through browser

    Hi, I was wondering if this plugins allowed to get the user's location through the browser? I did not find any informations about it ? Is there another plugins who allows it? Thanks in advance for the help !

    type: enhancement platform: web 
    opened by lionelquirynen 32
  • Possibility to access location only in  foreground

    Possibility to access location only in foreground

    ๐Ÿš€ Feature Requests

    Good morning everyone! Google has updated Permissions & Location Permissions policies applications must comply with to be published on Google Play.

    The new policy restricts the possibility to access users' location in the background: it would be great to have the possibility to access the location in the foreground only.

    In particular, it is now necessary to request the ACCESS_BACKGROUND_LOCATION permission in the manifest, and to follow the guidelines provided here.

    In case the application is not compliant with the new policy, updates are rejected with error messages similar to this one Background location access not declared We detected that your app contains at least one feature that requests background location access, however you have not submitted a permission declaration form for this feature. Please log in to your Play Console and submit a declaration form.

    Contextualize the feature

    There should exist two new functionalities, which could be implemented either by means of new functions or by adding parameters to the existing ones:

    1. Request foreground location only
    2. Access foreground location, if available, and raise an exception else.

    Describe the feature

    With the proposed modification, the framework should access users' location only when the application is active, without performing any kind of activity when the app is put in background or turned off.

    Platforms affected (mark all that apply)

    • [ ] :iphone: iOS
    • [x] :robot: Android
    status: needs more info platform: android 
    opened by fbambusi 28
  • geolocator_apple-1.2.0 uses methods not available on macOS

    geolocator_apple-1.2.0 uses methods not available on macOS

    Working on an app that should be deployable on Android, iOS and macOS. Using geolocator 7.6.1, building for macOS fails with this error:

    Command CompileSwift failed with a nonzero exit code
    /Users/user/Library/flutter/.pub-cache/hosted/pub.dartlang.org/geolocator_apple-1.2.0/macos/Classes/Handlers/PermissionHandler.m:52:29: error: 'requestWhenInUseAuthorization' is unavailable: not available on macOS
          [self.locationManager requestWhenInUseAuthorization];
                                ^
    In module 'CoreLocation' imported from /Users/user/Library/flutter/.pub-cache/hosted/pub.dartlang.org/geolocator_apple-1.2.0/macos/Classes/Handlers/PermissionHandler.h:11:
    /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/CoreLocation.framework/Headers/CLLocationManager.h:406:1: note: 'requestWhenInUseAuthorization' has been explicitly marked unavailable here
    - (void)requestWhenInUseAuthorization API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos);
    

    Flutter, Cocoapods, Xcode are all up to date on a machine running Catalina(10.15.7). Flutter doctor reports no issues. Posting this as a question since I'm not sure if this can be an error on my side or if there's a bug in geolocator_apple... any help appreciated!

    platform: macos 
    opened by michpohl 27
  • java.lang.IllegalArgumentException: Service not registered

    java.lang.IllegalArgumentException: Service not registered

    ๐Ÿ”™ Regression

    After upgrading to 6.0.0+1 I started to receive an exception as a warning on console multiple times

    Old (and correct) behavior

    Not having an exception

    Reproduction steps

    Just ask the position and the error appears after a while

    Configuration

    Version: 6.0.0+1

    Platform:

    • [ ] :iphone: iOS
    • [X] :robot: Android

    Console output

    W/ConnectionTracker( 1662): Exception thrown while unbinding
    W/ConnectionTracker( 1662): java.lang.IllegalArgumentException: Service not registered: com.google.android.gms.measurement.internal.zzjf@5516abb
    W/ConnectionTracker( 1662):     at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:1870)
    W/ConnectionTracker( 1662):     at android.app.ContextImpl.unbindService(ContextImpl.java:1847)
    W/ConnectionTracker( 1662):     at android.content.ContextWrapper.unbindService(ContextWrapper.java:755)
    W/ConnectionTracker( 1662):     at com.google.android.gms.common.stats.ConnectionTracker.zza(com.google.android.gms:play-services-basement@@17.3.0:55)
    W/ConnectionTracker( 1662):     at com.google.android.gms.common.stats.ConnectionTracker.unbindService(com.google.android.gms:play-services-basement@@17.3.0:50)
    W/ConnectionTracker( 1662):     at com.google.android.gms.measurement.internal.zzin.zzah(com.google.android.gms:play-services-measurement-impl@@17.4.1:246)
    W/ConnectionTracker( 1662):     at com.google.android.gms.measurement.internal.zzin.zzam(com.google.android.gms:play-services-measurement-impl@@17.4.1:263)
    W/ConnectionTracker( 1662):     at com.google.android.gms.measurement.internal.zzin.zzc(com.google.android.gms:play-services-measurement-impl@@17.4.1:330)
    W/ConnectionTracker( 1662):     at com.google.android.gms.measurement.internal.zziq.zza(com.google.android.gms:play-services-measurement-impl@@17.4.1:2)
    W/ConnectionTracker( 1662):     at com.google.android.gms.measurement.internal.zzah.run(com.google.android.gms:play-services-measurement-impl@@17.4.1:7)
    W/ConnectionTracker( 1662):     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462)
    W/ConnectionTracker( 1662):     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    W/ConnectionTracker( 1662):     at com.google.android.gms.measurement.internal.zzfy.run(com.google.android.gms:play-services-measurement-impl@@17.4.1:21)
    
    type: bug platform: android status: in progress 
    opened by inceptusp 25
  • got `LocationServiceDisabledException` when `Geolocator.isLocationServiceEnabled() return true

    got `LocationServiceDisabledException` when `Geolocator.isLocationServiceEnabled() return true

    ๐Ÿ› Bug Report

    Expected behavior

    try to get the current location after location permission is granted, and the location service is enabled too, but i got LocationServiceDisabledException when getCurrentPosition is called

    Reproduction steps

    try {
          final enabled = await Geolocator.isLocationServiceEnabled();
    
          print("enabled $enabled"); // true
    
          final permission = await Geolocator.checkPermission();
    
          print("permission $permission"); // whileInUse
     
          final position = await Geolocator.getCurrentPosition(
            desiredAccuracy: LocationAccuracy.medium,
          ); // throw exception here
    
        } catch (e) {
            // i got `LocationServiceDisabledException` here
        }
    

    Configuration

    all permissions related are granted, and all configurations in Android are done.

    Version: 6.1.5

    Platform:

    • [ ] :iphone: iOS
    • [x] :robot: Android
    platform: android status: triage 
    opened by Ralph-Li 24
  • GRPC failed error during various method calls

    GRPC failed error during various method calls

    ๐Ÿ› Bug Report

    Hello, we sometimes run to the following problem using Geolocator. Method that throws error varies. This time, we managed to get some information during placemarkFromCoordinates call.


    Error object


    Error type: PlatformException Error message: PlatformException(ERROR_GEOCODING_COORDINATES, grpc failed, null)


    Device info:


    Internet: wifi version.securityPatch: 2018-12-01 version.sdkInt: 27 version.release: 8.1.0 version.previewSdkInt: 0 version.incremental: G390FXXU3BRL3 version.codename: REL version.baseOS: board: universal7570 bootloader: G390FXXU3BRL3 brand: samsung device: xcover4lte display: M1AJQ.G390FXXU3BRL3 hardware: samsungexynos7570 host: SWDH7002 id: M1AJQ manufacturer: samsung model: SM-G390F product: xcover4ltexx supported32BitAbis: [armeabi-v7a, armeabi] supported64BitAbis: [] supportedAbis: [armeabi-v7a, armeabi] tags: release-keys type: user isPhysicalDevice: true


    Permission info:


    calendar: unknown camera: granted contacts: unknown location: granted microphone: granted phone: granted photos: granted reminders: granted sensors: unknown sms: unknown storage: granted speech: granted locationAlways: granted locationWhenInUse: granted mediaLibrary: granted


    Memory info:

    Total physical memory: 1839 MB Free physical memory: 35 MB Total virtual memory: 3375 MB Free virtual memory: 1184 MB

    StackTrace

    #0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:551)
    #1      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:292)
    <asynchronous suspension>
    #2      Geolocator.placemarkFromCoordinates (package:geolocator/geolocator.dart:251)
    <asynchronous suspension>
    

    Additional googling of error message showed this SO question pointing to two google bug reports (64418751, 64247769). Looks like there is problem with internal geolocation routines.

    Expected behavior

    Although this problem is caused by another problem in underlying structure, geolocator should not crash but should either

    • throw own specific exception that could be handled in consuming code as PlatformException is pretty general
    • or return null

    Great alternative would be optional possibility to use Geocoding API web service

    Reproduction steps

    There is no clear reproduction manual. Only way we can experience it is by daily use of plugin. Sometimes it happens sometimes not.

    Configuration

    Version: 3.0.1

    Platform:

    • [ ] :iphone: iOS
    • [x] :robot: Android
    type: documentation status: triage status: in progress 
    opened by MartinHlavna 23
  • `Position.heading` is mis-named

    `Position.heading` is mis-named

    ๐Ÿ› Bug Report

    The property heading of Position is mis-named. It is actually the course, which can be seen clearly on this line of LocationMapper.m for iOS.

    This is rather unfortunate, as heading and course are distinct concepts, and having it mis-named is confusing:

    In navigation, the course of a watercraft or aircraft is the cardinal direction in which the craft is to be steered. The course is to be distinguished from the heading, which is the direction where the watercraft's bow or the aircraft's nose is pointed.

    In the context of a device, "heading" refers to the direction the device is pointing and is typically provided via a magnetometer. However, "course" refers to the direction the device is traveling and is typically provided via GPS.

    Expected behavior

    A course should be called "course."

    Reproduction steps

    None necessary.

    Configuration

    Version: 1.x

    Platform:

    • [x] :iphone: iOS
    • [ ] :robot: Android
    opened by cbatson 1
  • Getting error Could not resolve com.google.android.gms:play-services-location:[15.0.0, 16.0.0).

    Getting error Could not resolve com.google.android.gms:play-services-location:[15.0.0, 16.0.0).

    Yesterday I run my code and didn't get any error but just so sudden... (I didn't edit my code) I got an error log like this

    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Could not determine the dependencies of task ':app:lintVitalRelease'.
    > Could not resolve all artifacts for configuration ':app:debugCompileClasspath'.
       > Could not resolve com.google.android.gms:play-services-location:[15.0.0, 16.0.0).
         Required by:
             project :app
          > Skipped due to earlier error
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
    
    * Get more help at https://help.gradle.org
    
    BUILD FAILED in 1m 8s
    

    I have tried by running it using another internet connection and still I get the same result. Is there a way to solve this (this error only happen when I run it using android and run so well in ios simulator) I also open this question on https://stackoverflow.com/questions/74895832/how-to-solve-could-not-resolve-com-google-android-gmsplay-services-location15

    opened by wahyu-handayani 0
  • - fixed an issue where the is service location would fail an not repoโ€ฆ

    - fixed an issue where the is service location would fail an not repoโ€ฆ

    Resolves Proposal 1 from the #1183

    :sparkles: What kind of change does this PR introduce? (Bug fix, feature, docs update...)

    It fixes an issue where the location service availability check fails and doesn't report anything.

    :arrow_heading_down: What is the current behavior?

    Nothing, the check just hangs.

    :new: What is the new behavior (if this is a feature change)?

    The check returns an error if it fails.

    :boom: Does this PR introduce a breaking change?

    No.

    :bug: Recommendations for testing

    Install an app on a work profile part of the Android device, and disable the location for the work profile part, and it will be reproducible.

    :memo: Links to relevant issues/docs

    #1183

    :thinking: Checklist before submitting

    • [x] I made sure all projects build.
    • [ ] I updated pubspec.yaml with an appropriate new version according to the pub versioning philosophy.
    • [ ] I updated CHANGELOG.md to add a description of the change.
    • [x] I followed the style guide lines (code style guide).
    • [x] I updated the relevant documentation.
    • [x] I rebased onto current master.
    opened by vlazdra 1
  • Android location service availability improvement for work profile

    Android location service availability improvement for work profile

    ๐Ÿ— Enhancement Proposal

    The problem I came across has to do with the location service availability check not working correctly when the app is installed via work profile on an Android device. The reason being is that the code never actually resolves that scenario correctly, it's missing an else statement for the check.

    I've managed to make it work, per say, but I think it can be improved even further by enabling the plugin to actually popup the dialog for enabling the location service.

    Pitch

    Not sure about the contributors part, but will improve the quality of the plugin, and will patch one issue at leat.

    Platforms affected (mark all that apply)

    • [ ] :iphone: iOS
    • [x] :robot: Android

    Proposal 1 - Adding the else statement

    Right now, if the app is installed via the work profile on the device, the isLocationServiceEnabled is not going to work, if the location service is not turned on for the work profile part.

      @Override
      public void isLocationServiceEnabled(LocationServiceListener listener) {
        LocationServices.getSettingsClient(context)
            .checkLocationSettings(new LocationSettingsRequest.Builder().build())
            .addOnCompleteListener(
                (response) -> {
                  if (response.isSuccessful()) {
                    LocationSettingsResponse lsr = response.getResult();
                    if (lsr != null) {
                      LocationSettingsStates settingsStates = lsr.getLocationSettingsStates();
                      boolean isGpsUsable = settingsStates != null && settingsStates.isGpsUsable();
                      boolean isNetworkUsable =
                          settingsStates != null && settingsStates.isNetworkLocationUsable();
                      listener.onLocationServiceResult(isGpsUsable || isNetworkUsable);
                    } else {
                      listener.onLocationServiceError(ErrorCodes.locationServicesDisabled);
                    }
                  }
                });
      }
    

    It's missing the else statement here, because a call towards the checkLocationSettings is resulting in an unsuccessful call. So by just adding the else statement, you can cover the use case where the app is installed via work profile and the service is not enabled, like so:

    
    if (response.isSuccessful()) {
       // ...
    } else {
        listener.onLocationServiceError(ErrorCodes.locationServicesDisabled);
    }
    

    Proposal 2 - Asking the user to enable location

    There is a way to ask the user to enable the location, it applies for either the work profile or the regular personal profile. In order to ask the user to enable the location service for the specific profile, you would need call startResolutionForResult((Activity) context, 123);

    Now with this call, the entire request would look something like this:

     @Override
        public void isLocationServiceEnabled(LocationServiceListener listener) {
            LocationServices.getSettingsClient(context)
                    .checkLocationSettings(new LocationSettingsRequest.Builder().build())
                    .addOnCompleteListener(
                            (response) -> {
                                if (response.isSuccessful()) {
                                   // ...
                                } else {
                                    if (response.getException() instanceof ResolvableApiException) {
                                        final ResolvableApiException exception = (ResolvableApiException) response.getException();
    
                                        switch (exception.getStatusCode()) {
                                            case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                                                // Location settings are not satisfied. But could be fixed by showing the
                                                // user a dialog.
                                                try {
                                                    // Cast to a resolvable exception.
                                                    // Show the dialog by calling startResolutionForResult(),
                                                    // and check the result in onActivityResult().
                                                    exception.startResolutionForResult((Activity) context, 123123);
                                                    listener.onLocationServiceError(ErrorCodes.error0);
                                                } catch (IntentSender.SendIntentException e) {
                                                    // Ignore the error.
                                                    listener.onLocationServiceError(ErrorCodes.error1);
                                                } catch (ClassCastException e) {
                                                    // Ignore, should be an impossible error.
                                                    listener.onLocationServiceError(ErrorCodes.error2);
                                                }
                                                break;
                                            case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                                                // Location settings are not satisfied. However, we have no way to fix the
                                                // settings so we won't show the dialog.
                                                listener.onLocationServiceError(ErrorCodes.error3);
                                                break;
                                        }
                                    }
                                }
                            });
        }
    

    Source of the code example above is from Google Play Services - Settings Client docs The example above would trigger a popup that would ask the user to turn on the service. It will look something like this: Location popup

    Now there is a catch with this one, it depends on the onActivityResult, where it actually reports the result of the request if the user allowed or disallowed the location service. And in order for it to work, the end developer would need to implement it in their MainActivity (I'm not aware that a plugin can register that kind of a callback).

    It took me some time to investigate this one fully (I might have missed something), to better understand why the location check was failing if the app was installed via the work profile where the location was turned off. And I'm still digesting all of the things I uncover, so if you have any questions, please feel free to ask, I will do my best to answer them if I can.

    opened by vlazdra 0
  • How to close runtime permission dialog programmatically?

    How to close runtime permission dialog programmatically?

    ๐Ÿ’ฌ Questions and Help

    I want to close runtime permission dialog with deny as selected option when user sends the app to background. How can I handle this? Thanks in advance.

    opened by shahpasandar 0
Owner
Baseflow
We provide software, skills and knowledge and with this we want to make a contribution to the world. We love to make innovation happen.
Baseflow
Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions.

On most operating systems, permissions aren't just granted to apps at install time. Rather, developers have to ask the user for permissions while the

Baseflow 1.7k Jan 3, 2023
Flutter Downloader - A plugin for creating and managing download tasks. Supports iOS and Android. Maintainer: @hnvn

Flutter Downloader A plugin for creating and managing download tasks. Supports iOS and Android. This plugin is based on WorkManager in Android and NSU

Flutter Community 789 Jan 3, 2023
File picker plugin for Flutter, compatible with both iOS & Android and desktop (go-flutter).

File Picker A package that allows you to use the native file explorer to pick single or multiple files, with extensions filtering support. Currently s

Miguel Ruivo 985 Jan 5, 2023
A Flutter plugin to easily handle realtime location in iOS and Android. Provides settings for optimizing performance or battery.

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

Guillaume Bernos 953 Dec 22, 2022
A Flutter plugin for displaying local notifications on Android, iOS and macOS

Flutter Local Notifications plugin This repository consists hosts the following packages flutter_local_notifications: code for the cross-platform faci

Michael Bui 2.1k Dec 30, 2022
Flutter Plugin for AR (Augmented Reality) - Supports ARKit on iOS and ARCore on Android devices

ar_flutter_plugin Flutter Plugin for AR (Augmented Reality) - Supports ARKit for iOS and ARCore for Android devices. Many thanks to Oleksandr Leuschen

Lars Carius 222 Jan 4, 2023
Telegram stickers importing Flutter plugin for iOS and Android

TelegramStickersImport โ€” Telegram stickers importing Flutter plugin for iOS and Android TelegramStickersImport helps your users import third-party pro

Iurii Dorofeev 20 Dec 3, 2022
Plugin to retrieve a persistent UDID across app reinstalls on iOS and Android.

flutter_udid Plugin to retrieve a persistent UDID across app reinstalls on iOS and Android. Getting Started import 'package:flutter_udid/flutter_udid.

Leon Kukuk 183 Dec 21, 2022
Support to update the app badge on the launcher (both for Android and iOS)

Flutter App Badger plugin This plugin for Flutter adds the ability to change the badge of the app in the launcher. It supports iOS and some Android de

Edouard Marquez 258 Dec 25, 2022
A Flutter plugin that allows you to add an inline webview, to use a headless webview, and to open an in-app browser window.

Flutter InAppWebView Plugin A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser windo

Lorenzo Pichilli 2.3k Jan 8, 2023
A Flutter plugin that allows you to check if an app is installed/enabled, launch an app and get the list of installed apps.

Flutter AppAvailability Plugin A Flutter plugin that allows you to check if an app is installed/enabled, launch an app and get the list of installed a

Lorenzo Pichilli 89 Dec 2, 2022
A lightweight Flutter plugin for making payments and printing on MyPos

my_poster ?? my_poster is in beta - please provide feedback (and/or contribute) if you find issues ??๏ธ A lightweight Flutter plugin for making payment

Antonio Mentone 3 Oct 10, 2022
Flutter library for iOS Widgets Extensions. Integrate a Widget into your App ๐Ÿ๐Ÿ“ฑ

flutter_widgetkit Flutter Library for the iOS ?? WidgetKit framework and Widget Communication Table of Contents ?? Introduction ??โ€?? Installation ??โ€

Fasky 227 Dec 31, 2022
Plugin to access VPN service for Flutter | Flutter ็š„ VPN ๆ’ไปถ

Flutter VPN plugin This plugin help developers to access VPN service in their flutter app. ๆœฌๆ’ไปถๅธฎๅŠฉๅผ€ๅ‘่€…ๅœจ่‡ชๅทฑ็š„ๅบ”็”จๅ†…่ฐƒ็”จ VPN ๆœๅŠกใ€‚ The Android part was implemented

Xdea 277 Dec 28, 2022
Community WebView Plugin - Allows Flutter to communicate with a native WebView.

NOTICE We are working closely with the Flutter Team to integrate all the Community Plugin features in the Official WebView Plugin. We will try our bes

Flutter Community 1.4k Jan 7, 2023
Use dynamic and beautiful card view pagers to help you create great apps.

Use dynamic and beautiful card view pagers to help you create great apps. Preview New Feature v1.3.0 Change Alignment Left Center(Default) Right v1.4.

Jeongtae Kim 84 Dec 6, 2022
Android and iOS Geolocation plugin for Flutter

Flutter Geolocator Plugin A Flutter geolocation plugin which provides easy access to platform specific location services (FusedLocationProviderClient

Baseflow 1k Jan 5, 2023
Flutter geolocation plugin for Android and iOS.

geolocation Flutter geolocation plugin for Android API 16+ and iOS 9+. Features: Manual and automatic location permission management Current one-shot

Loup 222 Jan 2, 2023
Android and iOS Geolocation plugin for Flutter

Flutter geolocator plugin The Flutter geolocator plugin is build following the federated plugin architecture. A detailed explanation of the federated

Baseflow 1k Jan 5, 2023
Android and iOS Geolocation plugin for Flutter

Flutter geolocator plugin The Flutter geolocator plugin is build following the federated plugin architecture. A detailed explanation of the federated

Baseflow 891 Nov 14, 2021