Open jeffscaturro-aka opened 1 year ago
Looks like a similar issue was previously filed around this, but marked as resolved: https://github.com/Baseflow/flutter-permission-handler/issues/1086 (=> https://github.com/Baseflow/flutter-permission-handler/pull/1089/files#r1254302197).
Same issue.
iOS 16.6.1, physical device
Pubspec.yaml permission_handler: ^10.4.5 permission_handler_apple: ^9.1.4
Podfile config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ '$(inherited)',
'PERMISSION_LOCATION=1',
]
Hi @jeffscaturro-aka, @niksen75,
Thank you for reporting this issue and providing detailed descriptions. I was able to reproduce the problem and did more detailed investigation.
Unfortunately the issue is not really easy to solve in our current architecture where we simply await the future when requesting permissions. The reason is that iOS will not always provide a status update when requesting "Always allow" permissions. Here are the situations:
User selected "Allow once"
When requesting location permissions and the user initially selected "Only once", requesting locationAlways
will not trigger the permission dialog at all and no result is provided. Unfortunately Apple doesn't provide an API which informs us the user initially selected "Only once", instead the "When in use" permission is returned. This is also explained in Apple's documentation.
User selected "When in use" and follows up with "Keep When in use"
When the user selected "When in use" at the moment we initially request location permissions Apple will return the "When in use" permission. Now if the app requests location always permission the following happens:
locationManager:didChangeAuthorizationStatus:
callback with the kCLAuthorizationStatusAuthorizedWhenInUse
status (this happens before the second permission dialog is shown).User selected "When in use" and follows up with "Change to Allow always"
Again the user initially provided "When in use" permissions and the app is requesting location always permission:
locationManager:didChangeAuthorizationStatus:
callback and confirms the current permission reporting the kCLAuthorizationStatusAuthorizedWhenInUse
status.locationManager:didChangeAuthorizationStatus:
method and inform us of the new kCLAuthorizationStatusAuthorizedAlways
status.As you can see this makes it really hard (not to say impossible) to reliably await for the correct status when requesting location alway permission. This due to the fact that in several situations iOS will simply not inform us about the status when the user makes a selection.
We understand that the current solution provided by the plugin is not really helpful and therefore we are planning to do a refactor of the plugin where we will provide developers with the option to listen to a stream providing permission status changes instead of enforcing developers to await the request
method for a status update. We will start the refactor very soon and hopefully can provide updates in the coming months. Until this time, we are not really able to provide a more solid solution and we hope you all understand.
We will keep this issue open to help track the refactor process and ensure this issue will be resolved as part of the refactor process.
P.S. alternative ideas are of course welcome.
@mvanbeusekom thank you so much for the triage and in depth explanation here, it is much appreciated and gives a great understanding of the limitations we're facing. I feel most developers can understand Apple doesn't always make it easy on us, especially when factoring in user privacy and permissions (rightfully so).
A workaround we had in place was simply utilizing a WidgetsBindingObserver where we were asking for this permission and listening to its lifecycle state changes (didChangeAppLifecycleState). I hope that helps some others who stumble across this issue, and of course, other ways around this would be welcomed to include on this thread!
For anyone reading this in the future, this is the didChangeAppLifecycleState workaround that people are mentioning:
class _LocationPageState extends State<LocationPage>
with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
// this is used to listen to the app lifecycle state
// this function is called affter the OS location permission popup appears because
// the app is considered "paused" when that happens and "resumed" after the user
// has selected an option
@override
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.resumed && Platform.isIOS) {
print('resumed ios');
await handleIOSLocationWorkAround(context, bloc);
}
}
@Biowulf21 What is the exact workaround and what will your method handleIOSLocationWorkAround
do?
I am just wondering as there is no connection between AppLifecycleState
and this issue.
@Biowulf21 What is the exact workaround and what will your method
handleIOSLocationWorkAround
do? I am just wondering as there is no connection betweenAppLifecycleState
and this issue.
The app goes to suspend state when the location permission pop up appears and goes to resumed state when it's closed.
Please check the following before submitting a new issue.
Please select affected platform(s)
Steps to reproduce
await Permission.locationWhenInUse.request()
.await Permission.locationAlways.request()
.Expected results
We expect the both requests to properly await the user's response to the iOS system dialog, and returns the user's choice.
Actual results
In the above steps, the first request properly awaits the user's response to the iOS system dialog, and returns the user's choice.
The second request immediately returns a response of not granted because the user hasn't responded yet to the dialog.
Code sample
Screenshots or video
Screenshots or video demonstration
[Upload media here]Version
10.4.3 - 11.0.0
Flutter Doctor output
Doctor output
```console Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, 3.13.0, on macOS 13.5.1 22G90 darwin-arm64, locale en-US) [✓] Android toolchain - develop for Android devices (Android SDK version 33.0.2) [✓] Xcode - develop for iOS and macOS (Xcode 14.3.1) [✓] Chrome - develop for the web [✓] Android Studio (version 2022.3) [✓] VS Code (version 1.81.1) [✓] Connected device (5 available) [✓] Network resources • No issues found! ```