Flutter-geolocator: got `LocationServiceDisabledException` when `Geolocator.isLocationServiceEnabled() return true

Created on 6 Nov 2020  路  20Comments  路  Source: Baseflow/flutter-geolocator

馃悰 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
android triage

Most helpful comment

I have just released version 6.1.10 of the geolocator plugin which should solve this problem.

Turned out in Android the onLocationAvailability callback method reports often that a location is not available and not only when the location services are disabled. I have fine-tuned handling this method and you should no longer experience false LocationServiceDisabledException exceptions anymore.

Thanks everyone for reporting, clarifying and helping out reproducing the issue.

All 20 comments

I have the same error but only when changing LocationAccuracyfrom the default to something else

StreamSubscription _streamSubscription = Geolocator.getPositionStream( // desiredAccuracy: LocationAccuracy.medium, <-- LocationServiceDisabledException error if I use a different accuracy distanceFilter: 500 ).listen(_listenData)..onError((e, stk) => print(e));

I am looking into this issue but having a hard time to reproduce it. Maybe you can answer the following questions and help me debug this issue:

  1. Are you seeing this on an emulator or also on real devices?
  2. Do you have Google Play Services installed (depending on this the geolocator will either use the FusedLocationProvider SDK or the LocationManager SDK, this might help me narrow down where to look for the problem)?

Looking forward for feedback so we can tackle this thing.

I got the same Unhandled Exception: The location service on the device is disabled. when I do

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

even if the location service for that app is enabled.

  1. A real device at Android 10
  2. Google Play Services is installed

I tried it and it works with medium accuracy. But it doesnt with any other settings.

  1. Emulators.
  2. Tried both.

Got the same error and it also doesn't work with any settings. Tested on both emulator and real device with location always on.

It seems for me to be only working on best accuracy. But it doesn't for others.

  1. Emulator.
  2. Google Play Services installed

Thank you all for providing some more feedback. We are currently looking into it but still not able to reproduce it. This probably has something to do with specific settings being enabled/ disabled.

When we find out we will of course let you know. In the meantime we are open for additional information (i.e. does this occur on all Android API's or only Android 10).

I have same error. https://prnt.sc/vr3glj

I get the same issue only when the device is not connected to a network(WIFI or MOBILE) and i'm inside a building(i.e.: poor GPS connection)

current stream settings:
StreamSubscription<Position> positionStream = Geolocator.getPositionStream( desiredAccuracy: LocationAccuracy.best, distanceFilter: 0) .listen((Position position) {}

AndroidManifest.xml: <!--Location--> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

Device location settings: High Accuracy (Use GPS, Wi-Fi, Bluetooth and mobile networks to determine location)
edit: Using physical device

Thank you @seb3n this is very helpful information. I am sure this will give me something to go on.

Thank you all for providing some more feedback. We are currently looking into it but still not able to reproduce it. This probably has something to do with specific settings being enabled/ disabled.

When we find out we will of course let you know. In the meantime we are open for additional information (i.e. does this occur on all Android API's or only Android 10).

@mvanbeusekom I have the same issue on Android 9

E/flutter (31570): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: The location service on the device is disabled.
E/flutter (31570): #0      MethodChannelGeolocator._handlePlatformException (package:geolocator_platform_interface/src/implementations/method_channel_geolocator.dart:192:9)
E/flutter (31570): #1      MethodChannelGeolocator.getCurrentPosition (package:geolocator_platform_interface/src/implementations/method_channel_geolocator.dart:121:7)
E/flutter (31570): <asynchronous suspension>
E/flutter (31570): #2      Geolocator.getCurrentPosition (package:geolocator/geolocator.dart:258:35)

isLocationServiceEnabled is true
code

      bool isLocationServiceEnabled =
          await Geolocator.isLocationServiceEnabled();
      AppLog.d(isLocationServiceEnabled);
      if (isLocationServiceEnabled) {
        Position position = await Geolocator.getCurrentPosition(
            desiredAccuracy: LocationAccuracy.high);
        return {"position": position.toString()};
      }

position = await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.medium, forceAndroidLocationManager: true) .timeout(Duration(seconds: 10));

This piece of code worked for me.

This is my attempt to create a minimal reproducible error

import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'dart:async';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Flutter Demo',
        home: SafeArea(
          child: Scaffold(body: GeoLocatorWidget()),
        ));
  }
}

class GeoLocatorWidget extends StatefulWidget {
  const GeoLocatorWidget({
    Key key,
  }) : super(key: key);

  @override
  _GeoLocatorWidgetState createState() => _GeoLocatorWidgetState();
}

class _GeoLocatorWidgetState extends State<GeoLocatorWidget> {
  StreamSubscription<Position> _streamSubscription;
  String message = 'empty';

  @override
  void initState() {
    super.initState();
    _streamSubscription = Geolocator.getPositionStream(
            //desiredAccuracy: LocationAccuracy.medium,
            distanceFilter: 500)
        .listen(_onData, onError: _onError);
  }

  void _onData(Position position) {
    ScaffoldState _scaffoldKey = Scaffold.of(context, nullOk: true);
    if ((_scaffoldKey?.mounted ?? false)) _scaffoldKey.hideCurrentSnackBar();
    setState(() {
      message = 'latitude: ${position.latitude}, longitude: ${position.longitude}';
    });
  }

  void _onError(dynamic error) {
    bool geoService = error is LocationServiceDisabledException ||
        error is PermissionDeniedException;
    ScaffoldState _scaffoldKey = Scaffold.of(context, nullOk: true);
    if (!(_scaffoldKey?.mounted ?? false)) return;
    _scaffoldKey.hideCurrentSnackBar();
    _scaffoldKey.showSnackBar(SnackBar(
      content: Text('$error'),
      duration: const Duration(minutes: 2),
      action: geoService
          ? SnackBarAction(
              label: 'Change',
              onPressed: () async {
                if (error is LocationServiceDisabledException) {
                  bool locationEnabled =
                      await Geolocator.isLocationServiceEnabled();
                  if (!locationEnabled) await Geolocator.openLocationSettings();
                  else setState(() {
                    message = '''
                      locationService is enabled but the error says 
                      its of type LocationServiceDisabledException anyway :(
                    ''';
                  });
                } else await Geolocator.openAppSettings();
              },
            )
          : null,
    ));
  }

  @override
  void dispose() {
    _streamSubscription?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(message),
    );
  }
}

Adding all the permissions in the AndroidManifest

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

STEPS TO REPRODUCE

  1. The streamSubscription will initialize and ask for permission and location service, we grant both and it shows correctly both latitude and longitude in the screen
  2. Turn off the screen with the app open (simulate the user is distracted and then come back after a minute)
  3. Turn on / Unlock screen and the app will now show an snackbar with the error (LocationServiceDisabledException) and an snackBarAction button "Change"
  4. If the button is tapped, it will check asynchronously if the location service is truly disable, if its disable it will try to open Geolocator.openLocationSettings();, if it's enabled even if the error is of type LocationServiceDisabledException (the issue of this thread) then just change the screen text telling you its enabled and it can't really do nothing

Considerations

  • Tested with a real device using Android 8.1.0 and Android 10, everything worked fine in Android 8.1.0 (turn off and on, come back to the app after a while and didn't show an error) but the issue persisted with Android 10
  • Couldn't make the error happen in the emulator (perhaps this is something to do with Doze or battery save mode)
  • I understand the plugin doesn't allow background location, but it shouldn't sent this error when the location is clearly enabled and just resume the stream when the app is in foreground again (or maybe send a different message to know if its really a location service problem)
  • This is also related to #568 where the permission/service is disabled and then enabled, one way around to that is using WidgetsBindingObserver to re-create the stream when moving out of the app (When opening settings to change the location or permissions of the app)
@override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.paused:
        if (_streamSubscription != null) {
          _streamSubscription.cancel();
          _streamSubscription = null;
        }
        break;
      case AppLifecycleState.resumed:
        _streamSubscription ??= Geolocator.getPositionStream(
            //desiredAccuracy: LocationAccuracy.medium,
            distanceFilter: 500).listen(_onData, onError: _onError);
        break;
      default:
        break;
    }
  }

Which works fine if the user tap the "Change" button, gets redirected to the Location Service Settings, turn it on and goes back to the app, but it won't work if the user just enables it from the status bar (the stream simply stops returning values after that).

Other idea is to use cancelOnError: true and HandleError method to intercept some errors of the stream and prevent close it when it's not that important (something that cannot be handled) but because it returns LocationServiceDisabledException even if that's not really the problem makes it difficult to pick out when and when not to use HandleError

I did another test on a physical device with Android 8.0.0 freshly installed

API call

Position position = await Geolocator.getCurrentPosition(
      desiredAccuracy: LocationAccuracy.$accuracy$,
    ).timeout(Duration(seconds: 10));

Results for each $accuracy$ value:
| $accuracy$ | Result |
|-------------------|----------------------------------|
| lowest | TimeoutException |
| low | LocationServiceDisabledException |
| medium | LocationServiceDisabledException |
| high | TimeoutException |
| best | LocationServiceDisabledException |
| bestForNavigation | TimeTimeoutException |

AndroidManifest.xml

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

Device settings

Device location settings: High Accuracy (Use GPS, Wi-Fi, and mobile networks)
Wifi: Connected
VPN: None
GPS Signal Strength: Shold be strong
Location information: On
Recent location requests: Displays the app which called the geolocation API

I have just released version 6.1.10 of the geolocator plugin which should solve this problem.

Turned out in Android the onLocationAvailability callback method reports often that a location is not available and not only when the location services are disabled. I have fine-tuned handling this method and you should no longer experience false LocationServiceDisabledException exceptions anymore.

Thanks everyone for reporting, clarifying and helping out reproducing the issue.

I have the same error, I have reproduced it on the xiaomi Redmi Note 8, while on a huawei p20 lite it works fine.
I notice that the following method returns true when services are disabled on the xiaomi, it should return false, just as it happens on the huawei.
The plugin version is: geolocator: ^6.1.13
await Geolocator.isLocationServiceEnabled ()

Like @sejr1996 I have detected the same problem with version 6.1.13 in Nokia 3.1 (android 9), Galaxy A10s (android 10)

The location service on the device is disabled.
       at MethodChannelGeolocator._handlePlatformException(MethodChannelGeolocator.java:192)
       at MethodChannelGeolocator.<fn>(MethodChannelGeolocator.java:171)

Like @sejr1996 I have detected the same problem with version 6.1.13 in Nokia 3.1 (android 9), Galaxy A10s (android 10)

The location service on the device is disabled.
       at MethodChannelGeolocator._handlePlatformException(MethodChannelGeolocator.java:192)
       at MethodChannelGeolocator.<fn>(MethodChannelGeolocator.java:171)

I'm getting same

I belive it's fixed already. My last resort to fix the service location was to use the location package. but now with the new version of geolocator package. the location permission comes first, then the service location follow.

Was this page helpful?
0 / 5 - 0 ratings