Flutter-geolocator: Possibility to access location only in foreground

Created on 4 Oct 2020  ·  28Comments  ·  Source: Baseflow/flutter-geolocator

🚀 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
android needs more info

Most helpful comment

@cguentherTUChemnitz and @arnerodde365 thank you for providing the additional feedback. I can now confirm that the Play Store will reject your app if you include the ACCESS_BACKGROUND_LOCATION permission in your AndroidManifest.xml file.

I can also confirm that this is not automatically added by the Geolocator plugin, but could be added by other plugins (e.g. the Location plugin adds it automatically). For those who really need a workaround you can add the following to your AndroidManifest.xml as a direct child of the <manifest ...> tag:

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

This will make sure the ACCESS_BACKGROUND_LOCATION permission will be removed even when other plugins add it to the AndroidManifest.xml file. Note that this could trigger unexpected behaviour for those plugins that do rely on this permission.

I am going to close this issue now since I believe it is not caused by the geolocator plugin it self.

All 28 comments

Hey Fulvio, could you fiind any solution? I'm also with the same issue.

İ am also with the same issue. Actually my app does not use location in background. But google play says to me : You are use in location in background. I think that because of this plugin, the application has permission to access background location.

The plugin doesn't access the location in the background, it is a much requested feature but I have not been able to implement it yet.

Can you check if you have the ACCESS_BACKGROUND_LOCATION permission listed in your AndroidManifest.xml file? If so please remove it, it is not required for this plugin to do it's work.

We are also having the same issue... We have already removed the permission from the manifest file, sent another patch, but google keeps rejecting the build.

Good morning everyone, thanks @mvanbeusekom for your consideration.

@marcuslindemannrohden I haven't yet managed to release new versions of the application in Play Store without filing an exception, i.e., declaring that the app is not compliant with the new policy.

I have not added the ACCESS_BACKGROUND_LOCATION to the manifest, but as far as I understand from this Google resource the permission has been automatically added since we are targeting API versions lower than 29.

@mvanbeusekom (and of course this question is addressed to all the users of this library 😊) did you manage to publish or update an application during the month of October? Sharing your experience in this sense would be incredibly helpful!

Goodmorning @fbambusi, thank you very much for this feedback.

I haven't submitted an app to the play store containing this plugin since October yet so I haven't experienced this behavior yet. I will however dive into the material provided and see if I can make sense of it and provide an update here to discuss possible solutions. I am currently working on solving issues #546 and #556, and will pick this up right after (should be somewhere during next week).

If someone has any suggestions on a possible solution please let me know, it would be highly appreciated

The plugin doesn't access the location in the background, it is a much requested feature but I have not been able to implement it yet.

Can you check if you have the ACCESS_BACKGROUND_LOCATION permission listed in your AndroidManifest.xml file? If so please remove it, it is not required for this plugin to do it's work.

I dont remember when i add this permission but i deleted this permission yesterday and submitted app to google. lastly just now google approved my app.
you must declare that your application does not use location in background at google play console declaration form

Hey guys, just got the approval from Google Play.
I have found that the class PermissionManager inside the library apparently includes the permission "ACCESS_BACKGROUND_LOCATION".
I have locally modified the class removing everything related to background location and every condition that could return it, to use only permissions "ACCESS_FINE_LOCATION" and "ACCESS_COARSE_LOCATION", submitted to google yesterday and it was approved.

I can not confirm if it really had any impact on the approval but in case anyone needs
follow the class modified to not make any use of background location.

package com.baseflow.geolocator.permission;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.baseflow.geolocator.errors.ErrorCallback;
import com.baseflow.geolocator.errors.ErrorCodes;
import com.baseflow.geolocator.errors.PermissionUndefinedException;

import java.util.*;

import io.flutter.plugin.common.PluginRegistry;

public class PermissionManager
        implements PluginRegistry.RequestPermissionsResultListener {

    private static final int PERMISSION_REQUEST_CODE = 109;

    @Nullable
    private Activity activity;
    @Nullable
    private ErrorCallback errorCallback;
    @Nullable
    private PermissionResultCallback resultCallback;

    public LocationPermission checkPermissionStatus(
            Context context,
            Activity activity) throws PermissionUndefinedException {
        String permission = determineFineOrCoarse(context);

        // If target is before Android M, permission is always granted
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            return LocationPermission.whileInUse;
        }

        final int permissionStatus = ContextCompat.checkSelfPermission(context, permission);
        if (permissionStatus == PackageManager.PERMISSION_DENIED) {
            if (PermissionUtils.isNeverAskAgainSelected(activity, permission)) {
                return LocationPermission.deniedForever;
            } else {
                return LocationPermission.denied;
            }
        }

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            return LocationPermission.whileInUse;
        }


        return LocationPermission.whileInUse;
    }

    public void requestPermission(
            Activity activity,
            PermissionResultCallback resultCallback,
            ErrorCallback errorCallback)
            throws PermissionUndefinedException {
        final ArrayList<String> permissionsToRequest = new ArrayList<>();

        // Before Android M, requesting permissions was not needed.
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            return;
        }

        String permission = determineFineOrCoarse(activity);
        permissionsToRequest.add(permission);



        this.errorCallback = errorCallback;
        this.resultCallback = resultCallback;
        this.activity = activity;

        ActivityCompat.requestPermissions(
                activity,
                permissionsToRequest.toArray(new String[0]),
                PERMISSION_REQUEST_CODE);
    }

    @Override
    public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode != PERMISSION_REQUEST_CODE) {
            return false;
        }

        if (this.activity == null) {
            Log.e("Geolocator", "Trying to process permission result without an valid Activity instance");
            if (this.errorCallback != null) {
                this.errorCallback.onError(ErrorCodes.activityNotSupplied);
            }
            return false;
        }

        String requestedPermission;

        try {
            requestedPermission = determineFineOrCoarse(this.activity);
        } catch (PermissionUndefinedException ex) {
            if (this.errorCallback != null) {
                this.errorCallback.onError(ErrorCodes.permissionDefinitionsNotFound);
            }

            return false;
        }

        LocationPermission permission = LocationPermission.denied;

        int requestedPermissionIndex = indexOf(permissions, requestedPermission);

        if (requestedPermissionIndex < 0) {
            Log.w("Geolocator", "Location permissions not part of permissions send to onRequestPermissionsResult method.");
            return false;
        }

        if (grantResults.length == 0) {
            Log.i("Geolocator", "The grantResults array is empty. This can happen when the user cancels the permission request");
            return false;
        }

        if (grantResults[requestedPermissionIndex] == PackageManager.PERMISSION_GRANTED) {
            permission = LocationPermission.whileInUse;
        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !activity.shouldShowRequestPermissionRationale(requestedPermission)) {
                permission = LocationPermission.deniedForever;
            }
        }

        for (String perm : permissions) {
            PermissionUtils.setRequestedPermission(activity, perm);
        }

        if (this.resultCallback != null) {
            this.resultCallback.onResult(permission);
        }

        return true;
    }

    private static <T> int indexOf(T[] arr, T val) {
        return Arrays.asList(arr).indexOf(val);
    }

    private static String determineFineOrCoarse(Context context) throws PermissionUndefinedException {
        boolean wantsFineLocation = PermissionUtils.hasPermissionInManifest(context, Manifest.permission.ACCESS_FINE_LOCATION);
        boolean wantsCoarseLocation = PermissionUtils.hasPermissionInManifest(context, Manifest.permission.ACCESS_COARSE_LOCATION);

        if (!wantsCoarseLocation && !wantsFineLocation) {
            throw new PermissionUndefinedException();
        }

        return wantsFineLocation ? Manifest.permission.ACCESS_FINE_LOCATION : Manifest.permission.ACCESS_COARSE_LOCATION;
    }

}

Hi @fbambusi, @marcuslindemannrohden, @eniserkaya,

I have been reading up on this and it seems that the main problem might be that you have to make sure that when listening to the position stream (using the Geolocator.getPositionStream() method, you need to make sure you stop listening to the stream (cancel the subscription) when your application is paused (put in the background).

Also note that versions 6.0.0 to 6.1.1 contained a bug which might leave the position stream active if you call the getCurrentPosition method while you have a positions stream active (see issues #485 and #541). This issue is solved in version 6.1.2.

To sum up:

  1. Make sure you don't include the ACCESS_BACKGROUND_LOCATION in your AndroidManifest.xml file;
  2. Make sure you unsubscribe / cancel active position streams when your app is moved into the background;
  3. Make sure you update to version 6.1.2 of the geolocator plugin.

Some more information can be found here:

Little remark on the code that @marcuslindemannrohden removed from the PermissionManager class, this code will only request background permissions if the ACCESS_BACKGROUND_LOCATION permission is listed in the AndroidManifest.xml file. If it is not there it will not be requested and as such it doesn't impact the App at all and should also not be a reason for Google to deny your app.

P.S. let me know if this helps out. I have submitted several apps using this plugin to the Google Play Store all without any issues although they don't use the getPositionStream feature. They only require the getLastKnownPosition and getCurrentPosition features. So any other feedback on this topic is much appreciated.

Any updates on this? I'm having a hard time getting my app approved

Getting the same reply:

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.

I'm only using getCurrentPosition,
I don't include ACCESS_BACKGROUND_LOCATION permission, only ACCESS_FINE_LOCATION,
I'm using the latest version 6.1.7

I'm targeting API level 29 and from what I understand from Developers.android, adding a foreground service type is required for 29 and above.

@arnerodde365, reading the documentation you provided it seems like all you need to do is add a <service declaration to your AndroidManifest.xml file and set the android:foregroundServiceType property to location:

<!-- Recommended for Android 9 (API level 28) and lower. -->
<!-- Required for Android 10 (API level 29) and higher. -->
<service
    android:name="MyNavigationService"
    android:foregroundServiceType="location" ... >
    <!-- Any inner elements would go here. -->
</service>

Note the <service ...></service> declaration should be listed as child of your <application> declaration.

It would be great if you could give this a try and let me know if this solved the problem. If so I will update the documentation and make sure this is mentioned in the README.md file.

Yeah I'll let you know
But I'm kind of new to App development and I have no idea what to put in the android:name=""

I guess this is should be the name of a service from the flutter-geolocator package?

@arnerodde365 it can be anything you'd like. It is a user defined value so name it something nice ;)

The app still gets rejected with the same reply :(

Any update? I have my compile and target SDK versions to 29, did NOT include background-permissions in the AndroidManifest.xml file and in the app bundle explorer it is still showing that I am requesting background location permissions.

To keep the loop shorter, i would recommend to build the android appbundle via:

flutter build appbundle
Running Gradle task 'bundleRelease'...                             10.1s
✓ Built build/app/outputs/bundle/release/app-release.aab (132.6MB).

Extract the .aab file and lookup the app-release/base/manifest/AndroidManifest.xml

This Manifest file should be parsed by the app-store. As long as there exist the entry of [...]android.permission.ACCESS_BACKGROUND_LOCATION[...] the appstore will reject without proper explenation why you need it.

The problem here is, that several flutter plugins do introduce this stuff by themself, like the geolocator or the location plugin also.

So the discussion point here needs to be changed to how to remove the background location permission entry from the geolocator, in cases where you don't need it.

Thank you for thinking along @cguentherTUChemnitz, I was also thinking the android.permission.ACCESS_BACKGROUND_LOCATION might be merged in by the Geolocator or another plugin.

Therefore I checked all the AndroidManifest.xml files associated with the Geolocator plugin but could not find this particular permission mentioned in the code base.

Tomorrow I will run additional tests analyzing the .aab file like you mentioned and try to verify if the Geolocator does put this entry in the AndroidManifest.xml file.

sorry for the late response, I have got my new version out.
I had to check the No I do not follow the privacy policy guidelines in the Permissions declaration form, and then update the form after the new version with no background location was released to the store.

I can now also confirm, that i was able to use this plugin without ACCESS_BACKGROUND_LOCATION in the bundle's manifest file. In my case another plugin did introduce it in my project.

@cguentherTUChemnitz thank you very much for confirming this. Would you care to share which plugin was the cause of this issue? This might help others aswel.

@arnerodde365, no worries about that, it seems that this issue might be caused by another plugin or package that automatically introduces the ACCESS_BACKGROUND_LOCATION permission to the AndroidManifest.xml file. If you are willing to share the contents of your pubspec.yaml (or the dependencies section) I am more then willing to check the dependencies to see if I can locate which plugin is causing the issue.

I have noticed that this issue has also been raised on the main Flutter repo (see flutter/flutter#73461).

  flutter_widget_from_html_core:  ^0.4.3      
  flutter_local_notifications:    ^1.4.4+2
  flutter_appcenter_bundle:       ^3.2.0+1
  shared_preferences:             ^0.5.6+2
  flutter_translate:              ^1.6.0
  redux_persist:                  ^0.8.3
  flutter_redux:                  ^0.6.0
  url_launcher:                   ^5.4.10
  package_info:                   ^0.4.0+13
  flutter_map:                    ^0.8.2
  geolocator:                     ^6.1.7
  provider:                       ^4.3.2+2
  geojson:                        ^0.9.1
  shimmer:                        ^1.1.2
  toast:                          ^0.1.5
  http:                           ^0.12.0+4
  intl:                           ^0.16.1

Sadly this information is not really helpful for others. In my case i had this permission in an own non-public plugin, which was used by the same project.

However, the app is now released and the problem is solved. I think it was a problem with google and their declaration form, I could not get the app in Beta because the Live version was not following the Privacy Policy ...

@cguentherTUChemnitz and @arnerodde365 thank you for providing the additional feedback. I can now confirm that the Play Store will reject your app if you include the ACCESS_BACKGROUND_LOCATION permission in your AndroidManifest.xml file.

I can also confirm that this is not automatically added by the Geolocator plugin, but could be added by other plugins (e.g. the Location plugin adds it automatically). For those who really need a workaround you can add the following to your AndroidManifest.xml as a direct child of the <manifest ...> tag:

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

This will make sure the ACCESS_BACKGROUND_LOCATION permission will be removed even when other plugins add it to the AndroidManifest.xml file. Note that this could trigger unexpected behaviour for those plugins that do rely on this permission.

I am going to close this issue now since I believe it is not caused by the geolocator plugin it self.

for those who blah blah copy pasted like I did and got:

The prefix "tools" for attribute "tools:node" associated with an element type "uses-permission" is not bound.

You need to add

    xmlns:tools="http://schemas.android.com/tools"

At the top like:

```xml
xmlns:tools="http://schemas.android.com/tools"
package="com.example.your_app">
````

This solution comes from:

(https://stackoverflow.com/questions/55334431/facing-below-error-toolsnode-associated-with-an-element-type-uses-permission)[https://stackoverflow.com/questions/55334431/facing-below-error-toolsnode-associated-with-an-element-type-uses-permission]

Turns out that the Android Platform itself injects the permission: ACCESS_BACKGROUND_LOCATION during installation of your app and hence might not be a fault with this plugin. You can read more from this link: https://developer.android.com/about/versions/10/privacy/changes#app-access-device-location
Which states:

If your app runs on Android 10 or higher but targets Android 9 (API level 28) or lower, the platform applies the following behavior:

If your app declares a element for either ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION, the system automatically adds a element for ACCESS_BACKGROUND_LOCATION during installation.
If your app requests either ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION, the system automatically adds ACCESS_BACKGROUND_LOCATION to the request.

I've build the official example for geolocator to .apk (signed build) and upload to play store.

Problem exists.

"Your background location permission declaration needs to be updated. "

AndroidManifest.xml is clean - no permissions declared.
.apk details (in play store admin page) shows no permissions requested.

Beta channel (because baseflow template requires corresponding Dart version).

[✓] Flutter (Channel beta, 1.25.0-8.3.pre, on Linux, locale en_US.UTF-8)
• Flutter version 1.25.0-8.3.pre at /home/anand/flutter
• Framework revision 5d36f2e7f5 (11 days ago), 2021-01-14 15:57:49 -0800
• Engine revision 7a8f8ca02c
• Dart version 2.12.0 (build 2.12.0-133.7.beta)

[skipped]

P.S.
Maybe it is this problem (old .apk with ACCESS_BACKGROUND_LOCATION permission):
https://stackoverflow.com/questions/65789352/google-asks-for-location-permission-declaration-for-new-android-app-release/65849925

P.P.S. Yes, I was able to publish official geolocator example to internal testing without errors. I don't delete this post here to allow other users to find this case - maybe it will be useful.

Even if problem doesn't come from plugin Geolocation, anyone found a solution ?

I've got same error : I use only foreground Geolocation, I don't have the permission ACCESS_BACKGROUND_LOCATION in my manifest, but Google Play reject my app.

Background location access not declared
We detected that your app contains at least one feature that requests access to location in the background, 
however  your permission declaration form did not reflect this. 
Please log in to your Play Console to resubmit your location declaration form.
You may either remove location in the background from your app or indicate that the usage is in the background.

Thanks for your answer

Was this page helpful?
0 / 5 - 0 ratings

Related issues

estevez-dev picture estevez-dev  ·  6Comments

CNogueira92 picture CNogueira92  ·  3Comments

joesnarky picture joesnarky  ·  3Comments

seakmengc picture seakmengc  ·  3Comments

deisold picture deisold  ·  3Comments