Closed mvanbeusekom closed 4 years ago
Hi @DenisBogatirov, I have tried to reproduce this issue but I am failing. Could you provide some extra information maybe? Things that would help would be:
Here is the code I used to try and reproduce the error (I am on Android emulator with API29, using version 2.0.4+1 of the plugin) :
AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.baseflow.location_permissions_example">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:label="location_permissions_example"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- This keeps the window background of the activity showing
until Flutter renders its first frame. It can be removed if
there is no splash screen (such as the default splash screen
defined in @style/LaunchTheme). -->
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
main.dart:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:location_permissions/location_permissions.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.settings),
onPressed: () {
LocationPermissions().openAppSettings().then((bool hasOpened) =>
debugPrint('App Settings opened: ' + hasOpened.toString()));
},
)
],
),
body: Center(
child: ListView(
children: _createWidgetList(),
),
),
),
);
}
List<Widget> _createWidgetList() {
List<Widget> widgets = [];
if (Platform.isAndroid) {
widgets.add(_PermissionWidget(LocationPermissionLevel.locationWhenInUse));
widgets.add(_StreamingStatusWidget());
} else if (Platform.isIOS) {
widgets.add(_PermissionWidget(LocationPermissionLevel.locationWhenInUse));
widgets.add(_PermissionWidget(LocationPermissionLevel.locationAlways));
}
return widgets;
}
}
class _StreamingStatusWidget extends StatelessWidget {
final Stream<ServiceStatus> statusStream =
LocationPermissions().serviceStatus;
@override
Widget build(BuildContext context) => ListTile(
title: const Text('ServiceStatus'),
subtitle: StreamBuilder<ServiceStatus>(
stream: statusStream,
initialData: ServiceStatus.unknown,
builder: (_, AsyncSnapshot<ServiceStatus> snapshot) =>
Text('${snapshot.data}'),
),
);
}
class _PermissionWidget extends StatefulWidget {
const _PermissionWidget(this._permissionLevel);
final LocationPermissionLevel _permissionLevel;
@override
_PermissionState createState() => _PermissionState(_permissionLevel);
}
class _PermissionState extends State<_PermissionWidget> {
_PermissionState(this._permissionLevel);
final LocationPermissionLevel _permissionLevel;
PermissionStatus _permissionStatus = PermissionStatus.unknown;
@override
void initState() {
super.initState();
//_listenForPermissionStatus();
}
void _listenForPermissionStatus() {
final Future<PermissionStatus> statusFuture =
LocationPermissions().checkPermissionStatus();
statusFuture.then((PermissionStatus status) {
setState(() {
_permissionStatus = status;
});
});
}
Color getPermissionColor() {
switch (_permissionStatus) {
case PermissionStatus.denied:
return Colors.red;
case PermissionStatus.granted:
return Colors.green;
default:
return Colors.grey;
}
}
@override
Widget build(BuildContext context) {
return Container(
child: Padding(
padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0),
child: GestureDetector(
onTap: () {
requestPermission(_permissionLevel);
},
child: Row(
children: <Widget>[
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(_permissionLevel.toString()),
Text(
_permissionStatus.toString(),
style: TextStyle(color: getPermissionColor()),
),
]),
),
IconButton(
icon: const Icon(Icons.check),
onPressed: () {
checkPermission(context, _permissionLevel);
}),
IconButton(
icon: const Icon(Icons.info),
onPressed: () {
checkServiceStatus(context, _permissionLevel);
}),
],
),
),
),
);
}
void checkServiceStatus(
BuildContext context, LocationPermissionLevel permissionLevel) {
LocationPermissions()
.checkServiceStatus()
.then((ServiceStatus serviceStatus) {
final SnackBar snackBar =
SnackBar(content: Text(serviceStatus.toString()));
Scaffold.of(context).showSnackBar(snackBar);
});
}
Future<void> checkPermission(
BuildContext context,
LocationPermissionLevel permissionLevel,
) async {
final PermissionStatus permissionResult =
await LocationPermissions().checkPermissionStatus(
level: permissionLevel,
);
final snackBar = SnackBar(
content: Text("Permission status: $permissionResult"),
);
Scaffold.of(context).showSnackBar(snackBar);
setState(() {
_permissionStatus = permissionResult;
});
}
Future<void> requestPermission(
LocationPermissionLevel permissionLevel) async {
final PermissionStatus permissionRequestResult = await LocationPermissions()
.requestPermissions(permissionLevel: permissionLevel);
setState(() {
_permissionStatus = permissionRequestResult;
});
}
}
Also having this issue. When the user selects LocationPermissionLevel.locationWhenInUse on android, the permission status is PermissionStatus.denied. Cant reproduce the same on iOS
We are using location_permissions 2.0.4+1 on an android emulator running android 10
Can confirm the bug, the following code is showing the same issue:
PermissionStatus statusAsk = await LocationPermissions().requestPermissions(
permissionLevel: LocationPermissionLevel.locationWhenInUse); // granted
PermissionStatus statusCheck = await LocationPermissions().checkPermissionStatus(
level: LocationPermissionLevel.locationWhenInUse); // denied
Tested in Android 10, both using a device (Samsung S10), and emulator using Android 10 as well. Importing version 2.0.4+1.
Also, using permission_handler
instead correctly returns the expected value.
Having the same issue. Any solution?
Same issue here, Android 10 with location enabled while app is in use.
Same issue exactly as @fabiomgoncalves describes it. requestPermissions(permissionLevel: LocationPermissionLevel.locationWhenInUse)
returns granted but a followup checkPermissionStatus(level: LocationPermissionLevel.locationWhenInUse)
returns denied if you click to only allow "when in-use". It only works if you allow permission "all the time". Thanks!
Thanks for all the feedback, I struggled a bit reproducing the issue but I managed to reproduce it now as well (not sure why). I will now look into the bug and try to provide a fix a.s.a.p.
Finally found the issue, the problem is related to the targetSdkVersion
that is referenced. The example
App that is part of the location_permissions
plugin targets version 29.
However if you create a new application with flutter create
by default the app references version 28. You can easily fix this by updating the compileSdkVersion
and targetSdkVersion
parameters in your android/app/build.gradle
file and set them to 29
.
I will have a look and see if I can create some kind of fix to fall back on the old permission handling when the configured SDK is set to 28. So if you want it fixed now please update to SDK version 29.
I have had a look at the code and it seems that the implementation of the ContextCompat.checkSelfPermission()
method has been changed in API version 29. From my tests I get the following:
So the only solution I can think of is to upgrade your android/app/build.gradle
file and target SDK version 29.
I can confirm that updating my compileSdkVersion
and targetSdkVersion
to 29 fixes the issue on Android 10, but it still behaves properly on older android versions (just asking for overall permission). Thank you very much for the fix!
@mvanbeusekom I am still seeing this issue after changing the compileSdkVersion
and the targetSdkVersion
to API level 29
. I have pinpointed the issue to the following:
If the application contains the <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
permission then the user is presented with a modal that has three options regardless of the enum value
passed to requestPermissions(...)
:
If the user selects the Allow while in use
option then subsequent requests to checkPermissionStatus(level: LocationPermissionLevel.whileInUse)
will return PermissionsStatus.denied
Here is a gif of the example application above with what I am seeing when I add the <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
and then request location permissions using requestPermissions(level: LocationPermissionLevel.locationWhenInUse)
Hope this helps, there is for sure some nuance in here that is hard to pick up on.
Can also confirm what @brianb-sf is experiencing, with the same Manifest permissions even though targetSdkVersion
is set to 29
. checkPermissionStatus
is returning denied when Allow location while the app is in use
is selected.
returns
PermissionStatus.granted
but after that
returns
PermissionStatus.denied
On my manifest I have only this
Originally posted by @DenisBogatirov in https://github.com/Baseflow/flutter-permission-plugins/issues/21#issuecomment-582366361