flutter-geolocator icon indicating copy to clipboard operation
flutter-geolocator copied to clipboard

No position, when forceAndroidLocationManager: true and Google Play Services installed

Open 7h30n3 opened this issue 3 years ago • 1 comments

🐛 Bug Report

It's not possible to retrieve a location, when forceAndroidLocationManager: true on a device with Google Play Services installed. Detailed findings below.

Expected behavior

Reproduction steps

I have written a minimal example main.dart. Just run it with different settings and see for yourself.

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

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Geolocator Test'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

/// 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;
  Position pos;

  // Test if location services are enabled.
  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.
  print('Permission granted, asking for current location.');
  pos = await Geolocator.getCurrentPosition(
    forceAndroidLocationManager: true
  );
  print(pos);
  return pos;
}

class _MyHomePageState extends State<MyHomePage> {
  Position? _pos;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You are here:',
            ),
            Text(
              '$_pos',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          _pos = await _determinePosition();
          setState(() {});
          },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

In build.gradle

android {
    compileSdkVersion 33
    ...
    }

In AndroidManifest.xml

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

My findings are as follows:

Device with Google Play Services

  • When forceAndroidLocationManager=true and LocationService=off and GoogleLocationAccuracy=off => Unhandled Exception: The location service on the device is disabled.

  • When forceAndroidLocationManager=true and LocationService=off and GoogleLocationAccuracy=on => Unhandled Exception: The location service on the device is disabled.

  • When forceAndroidLocationManager=true and LocationService=on and GoogleLocationAccuracy=off => No Position, No Error Message) [Here lays the PROBLEM!!!]

  • When forceAndroidLocationManager=true and LocationService=on and GoogleLocationAccuracy=on => No Position, No Error Message) [Here lays the PROBLEM!!!]

Device without Google Play Services

  • When forceAndroidLocationManager=true and LocationService=off => Unhandled Exception: The location service on the device is disabled.

  • When forceAndroidLocationManager=true and LocationService=on => POSITION

I hope someone can confirm my findings or even can provide a (quick) fix.

Configuration

Version: 8.2.1 / 9.0.1.

Platform:

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

7h30n3 avatar Aug 01 '22 08:08 7h30n3

I've got multiple reports about the same issue. Geolocator for now is basically an interface to Google location services, and if I want to publish on e.g. F-Droid, I would need to switch libraries.

Zverik avatar Aug 09 '22 09:08 Zverik

Remember that you need to be outdoor to have the GPS of the phone getting locations.

montrifork avatar Sep 27 '22 12:09 montrifork

The problem is, even the GPS symbol does not appear in the status bar. It just does not communicate with the relevant services. Weirdly, even reverting to geolocator_android 3.0.4 does not help.

Zverik avatar Oct 02 '22 19:10 Zverik

Have you tried to add a try catch with a timeout? It's working for me:

try{
  position = await Geolocator.getCurrentPosition(
      forceAndroidLocationManager: Platform.isAndroid,
      timeLimit: const Duration(seconds: 5)
  );
}catch(_){
  position = await Geolocator.getCurrentPosition();
}

ecastillopki avatar Dec 22 '22 05:12 ecastillopki

Tried your approach @ecastillopki but didn't work for me.

I'm not able to receive location updates from getPositionStream with Google Location Accuracy turned off (Google Services on), even if forceLocationManager is true.

geolocator: ^9.0.2

AndroidSettings(
        forceLocationManager: true,
        accuracy: LocationAccuracy.high,
        intervalDuration: const Duration(seconds: 3),
        timeLimit: const Duration(seconds: 5)
      )

In addition, from my observations:

  • forceLocationManager true, Google Services on and Google Location Accuracy off: I don't receive any updates.
  • forceLocationManager false, Google Services on and Google Location Accuracy off:
E/flutter (31117): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: The location service on the device is disabled.
E/flutter (31117): #0      GeolocatorAndroid.getPositionStream.<anonymous closure> (package:geolocator_android/src/geolocator_android.dart:187:9)

irvine5k avatar Dec 22 '22 14:12 irvine5k

Hi, has anyone solved this problem? For me is only happening when I use a Wear OS device, not on Android.

deliaam avatar Apr 04 '23 09:04 deliaam

I see this same issue on all of my android devices. Looks like this issue has been opened for almost a year. I assume this plugin is no longer supported.

rlueders avatar May 30 '23 12:05 rlueders

Dear @7h30n3,

I cannot reproduce your flow When forceAndroidLocationManager=true and LocationService=on and GoogleLocationAccuracy=off => No Position, No Error Message) [Here lays the PROBLEM!!!] with the example app.

Does it work in the example app? It seems to work fine if I test the example app op a Nexus 7, Android 13.

Did you request the proper permissions and did you setup the manifest correctly? (Check the README for detailed steps)

If you don't get positions in the example app then check if your device is setup properly. The forceLocationManager forces the old location manager that is based on either GPS or Network. If one of them is not setup properly then you might not be able to get a location. Also notice that it is important to test your gps locations in an open environment. I've personally tested this in concrete buildings and the gps might not be able to find an accurate location. Also be careful when you test locations in your Simulator. It might not be working as expected.

If the example apps works correctly and your app does not work correctly then the issue can be found in your code.

Kind regards,

TimHoogstrate avatar Aug 28 '23 13:08 TimHoogstrate

Hi @TimHoogstrate,

I have retested everything with the latest version of geolocator, but unfortunately nothing has changed. I even tested the example app of geolocato, but when set:

locationSettings: AndroidSettings(forceLocationManager: true)

I still can't get any position on my Galaxy S10 with Android 12. However at the same location when I open OSMand I get a position almost instantly.

7h30n3 avatar Sep 01 '23 09:09 7h30n3

Hi @7h30n3! Thank you for raising this issue and providing us with valuable feedback. I'd be eager to get to the bottom of this issue since many people seem to be affected.

As fully diving into the code is rather time-consuming, I would like to assess the scope of this bug first. To that end I have some questions. Could you tell me if you experience this behavior:

  • On different Android versions (ex. 11 and 13)
  • In an emulator
  • Both when providing precise location access and approximate location access
  • Both when allowing location while using the app and only this time

I'd like to point out that when using the example app of flutter-geolocator, starting the location stream will not ask for location permissions. Make sure these are granted, for example by getting the current location (second button).

Looking forward to hearing from you!

JeroenWeener avatar Sep 05 '23 16:09 JeroenWeener

The issue should be resolved. You can pull in the latest changes by running dart pub upgrade. Please check if pubspec.lock contains

  geolocator_android:
      ...
    version: "4.2.3"

JeroenWeener avatar Sep 12 '23 14:09 JeroenWeener

I think something is still off here. After updating to 4.2.3, I do indeed now get location updates when forceAndroidLocationManger = true and accuracy = best, but they are wildly inaccurate on emulators and real devices. However, if I force/hard code the LocationManagerClient.currentLocationProvider = "gps" then I get very precise location updates.

I believe something must have changed a while back that caused the LocationManagerClient to start returning very low accuracy location updates. As a result, the low accuracy location updates started getting caught in the accuracy filter that was removed in 4.2.3. In other words, removing the accuracy filtering didn't really fix the problem. Rather it merely let through very inaccurate location updates. As such, the root of this bug probably lies further upstream with the low accuracy position updates.

My guess is that getBestProvider() started returning one of the low accuracy providers even when the best accuracy was selected by the developer. I will also note that in in api 34, LocationManager.getbestProvider is now deprecated and the desired approach is to explicitly select the desired provider. Given the deprecation and the seemingly undesirable behavior of getBestProvider, is there any reason that the LocationManagerClient.currentLocationProvider shouldn't be explicitly set to 'gps' when high/best accuracy is selected?

rlueders avatar Sep 12 '23 19:09 rlueders

Thank you for the elaborate explanation @rlueders!

This has helped us get an insight into what is actually going wrong. I opened a PR that aims to fix the inaccurate location readings: #1324.

JeroenWeener avatar Sep 13 '23 13:09 JeroenWeener

Thanks for looking into it. I will test it once is is released.

rlueders avatar Sep 13 '23 16:09 rlueders

@rlueders the issue should be resolved. You can pull in the latest changes by running dart pub upgrade. Please check if pubspec.lock contains

  geolocator_android:
      ...
    version: "4.2.4"

JeroenWeener avatar Sep 14 '23 08:09 JeroenWeener

I did a couple tests on two real devices and everything looks good. Thanks for the fix.

rlueders avatar Sep 14 '23 16:09 rlueders