Flutter Geolocator not working on Android, but working perfectly on iOS

1,576

Firstly, I modified the function used to get the coordinates, based on the breaking changes described by the plugin author for version 7.0.0, mainly related to the permissions section.

  _determineCurrentPositionStarting() 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;
    }

    permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.deniedForever) {
        // Permissions are denied forever, handle appropriately.
        return;
      }
    }

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

    // When we reach here, permissions are granted and we can
    // continue accessing the position of the device.

    return await Geolocator.getCurrentPosition(
      desiredAccuracy: LocationAccuracy.bestForNavigation,
      forceAndroidLocationManager: true,
      timeLimit: null,
    ).then((Position position) {
      setState(() {
        gcStartingLatitudeGEODEG.text = position.latitude.toStringAsFixed(6);
        gcStartingLongitudeGEODEG.text = position.longitude.toStringAsFixed(6);
      });
    }).catchError((e) {
      print(e);
    });
  }

Then, I decided to do a timing test and it seems that basically, even for the Android devices on which I originally thought it didn't work, it actually did, just with a long delay.

For example, on my Android physical device, Samsung Galaxy A21s, it took anywhere from 48 seconds to a couple of minutes, but it did return coordinates.

Therefore, I can only assume that it does work on all platforms and it is entirely dependent on the type of device, the quality of the GPS module within it and the GPS connectivity at the user's location, as to the speed of the result.

That's why it hadn't resulted in an error log. It was working, just taking a while.

Share:
1,576
James
Author by

James

Updated on January 01, 2023

Comments

  • James
    James over 1 year

    I've built an app using Flutter, for both iOS and Android platforms. It uses the Geolocator package, version 7.7.0. The strange thing is, whilst it works on the iOS simulator and physical devices, it doesn't work at all on either the Android emulator, or physical devices. This is the geolocator-based asynchronous function I have created to check permissions and get the current position of the user, based off the guidance from pub.dev:

      _determineCurrentPositionStarting() 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, so 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(
          desiredAccuracy: LocationAccuracy.best,
          forceAndroidLocationManager: true,
        ).then((Position position) {
          setState(() {
            gcStartingLatitudeGEODEG.text = position.latitude.toStringAsFixed(6);
            gcStartingLongitudeGEODEG.text = position.longitude.toStringAsFixed(6);
          });
        }).catchError((e) {
          print(e);
        });
      }
    

    In addition, the onPressed command that calls the above function, in a button, looks like this:

            onPressed: () async {
              _determineCurrentPositionStarting();
            },
    

    On iOS it works fine, getting the user's location. It just doesn't work on Android. The problem is, there's no error log produced for it at all, so there's no obvious target for me to work on. Everything appears to be working fine in the terminal. I've done a bit of trial and error, to see if I can work out at which stage the process is getting stuck. This is what I have found:

    1. The function is able to check if location services are enabled and shows a popup warning if it isn't.
    2. The function is able to check for permissions and request it through a popup if it doesn't already have them (always, only while using the app, never etc.). If never is selected, a warning is generated, as expected.
    3. The function is able to give a warning if permissions are denied forever.
    4. Nothing is returned at all when we reach return await Geolocator.getCurrentPosition...

    This makes me think that there is an issue with the android platform and the await Geolocator.getCurrentPosition() function.

    Since everything works fine on my iOS device and simulator, but it doesn't on Android, I'm thinking it has got to be something to do with the Android-specific settings.

    Within my androidmanifest.xml file I have, as far as I can tell, the correct permissions noted:

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

    I am using gradle version 7.0.0 and in my build.gradle file (android > app > build.gradle) my SDK versions are:

    • compileSdkVersion: 31
    • minSdkVersion: 23
    • targetSdkVersion: 31

    If it helps, there are no errors with the Flutter Doctor:

    [✓] Flutter (Channel stable, 2.5.3, on macOS 11.6 20G165 darwin-x64, locale en-GB)
    [✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    [✓] Xcode - develop for iOS and macOS
    [✓] Chrome - develop for the web
    [✓] Android Studio (version 2020.3)
    [✓] Connected device (2 available)
    

    Is there anything I am missing? Is there any reason you can see as to why it just isn't working on Android? Any help would be gratefully appreciated!

    EDIT

    I've just tried it on an Android Emulator running Android 11.0, instead of 12.0 and it works fine. That suggests to me it could be related to how the breaking changes in the package version 7.0.0 are interacting could be interacting with the Android 12.0 emulator. I'll look through them and if I can work it out, I'll post it as an answer to my query.