My app can have two level of LocationHandler status. First, I launch requestWhenInUseAuthorization and then, if the user activates some specific features, I launch requestAlwaysAuthorization.
I need to be notified if user refuses the requestAlwaysAuthorization to let him know the feature won't work as expected. The problem is that in this case didChangeAuthorizationStatus is not called because the authorization status stays the same (it was AuthorizedWhenInUse and it's still AuthorizedWhenInUse).
Do you have any idea how I could be notified if user refuses AuthorizedAlways after accepting AuthorizedWhenInUse ?
since iOS 10 or so it is no longer possible to call requestAlwaysAuthorization() after you have called requestWhenInUseAuthorization() even if the user accepted when-in-use.
in prior versions (at least iOS8) you could "step up" the authorization and ask for always-authorization after the user accepted when-in-use. This is no longer possible.
best thing to do is check CLLocationManager.authorizationStatus()
once in a while and show a dialog pointing the user to the right settings page with UIApplicationOpenSettingsURLString
Related
I am experiencing unexpected behavior in the iOS location authorization process. Here are my steps including a screen-grab
I request "Always" authorization on iOS 13.
I only grant the app the "Allow Once" authorization, which grants the user a temporary "When In Use" authorization.
I request "Always" authorization again.
This time, no authorization prompt is shown and the didChangeAuthorization delegate method gives .authorizedAlways
However, when I look at the authorization status in the Settings app, it says "Ask Next Time", which corresponds to an authorization status of .notDetermined.
My questions:
Why is there no second prompt when I request "Always" authorization a second time?
Why does the delegate method give the .authorizedAlways status without me actually giving that authorization?
Why does the Settings app indicate that the authorization status is .notDetermined when the delegate method said it was .authorizedAlways.
I feel like this is a bug in iOS, but I might also just be misunderstanding the way the authorization flows should work. What do you think?
I haven't been able to test this on a real device with iOS13, so I don't know if it's maybe just a problem in the simulator?
The user has already been asked for a location permission in this session; they selected "allow once". If iOS prompted them a second time it would be annoying and confusing.
Your app is upgraded to "provisional always" state after the second request; it is allowed to think that it has always so that any permission checking logic you may have built won't keep asking the user to go to settings or whatever. Since the app doesn't really have always there is no impact to user privacy, so there is no harm in reporting "always"
The settings app reflects the user's actual choice which is "ask me again next time".
The WWDC video that #Don suggested in the comments explains about provisional always permission and its purpose in satisfying app permissions logic.
Why is there no second prompt when I request "Always" authorization a second time?
In iOS 13.0, just requesting “always” permission a second time does not qualify as the “event” to trigger the prompt to the user. You actually have to to perform the action that requires “always”.
For example, I request always, and got the “when in use” prompt. I turned on significant change service, but did not receive prompt for always. Only when I hopped in my car and started to drive away did the significant change actually trigger the “always” prompt.
In WWDC 2020 video What's new in location, they describe a change introduced in iOS 13.4. You can ask for “when in use” and assuming the user granted it, you can ask for “always” and get the second alert (this time asking if the user would like to upgrade to “always” or not). You just need both “Privacy - Location When In Use Usage Description” and the “Privacy - Location Always and When In Use Usage Description” usage strings.
I'm building a running-based app in Swift that requests the user's location. For the sake of this question, let's just assume the app runs only on iOS 13+. Shortly after launching the app, we prompt the user for location access via the CLLocationManager method: requestWhenInUseAuthorization().
However, this app actually needs access to the user's location all the time, so only being able to request "When In Use" location access (per iOS 13) restricts the UX (other apps like Zenly and Snapchat do this as well since getting constant location updates improves the experience for their users and/or their friends).
After prompting for the location permission, we then grab the latest location authorization status. If that value is not equal to authorizedAlways (and it won't be unless the user changes that value in his/her Settings app), we present a new screen basically telling the user, "Since this is a running app, we really need your location all the time, so please go to settings and change the permission to 'Always' since we can't do it for you."
The issue I'm running into here is that when listening for updates on the CLLocationManagerDelegate method: locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus), sometimes that method provides the incorrect location authorization status.
Specifically, after a user selects "When In Use" and runs the app a few times, the value returned from that delegate method frequently reads as "Always," even though the Settings app on the phone still reflects the original, unchanged value ("When In Use").
Has anyone run into this before and, if so, do you have any ideas on what might cause it or how to fix it? Happy to provide more info on my setup. Thanks.
As per the WWDC video, https://developer.apple.com/videos/play/wwdc2019/705/, when you ask for "AlwaysAuthorization" permission you will see only "When In Use, Once and Don't allow". Even if you tap on "When In Use", the delegate call back will come back as kCLAuthorizationStatusAuthorizedAlways. This is working as expected. But is there a way to find out that the request is still provisional or actually-always-allow?
There is no enum associated to this permission. The only allowed enums are:
kCLAuthorizationStatusNotDetermined, kCLAuthorizationStatusDenied, kCLAuthorizationStatusAuthorizedAlways, kCLAuthorizationStatusAuthorizedWhenInUse
Because I want to show an alert as soon as user grants the "While In Use" permission, to tell them that the app will only work if you provide "Always Allow" via system preferences and I can navigate them to the system settings page of my app via a tap, just like how Zenly is doing it: https://www.macrumors.com/2019/08/16/app-developers-tracking-restrictions-ios-13/
You can check if you're getting location updates in the background for more than 10 seconds after the application gets in the background. If yes, then you have the permanent Allow Always. If not, then you have the provisional Allow Always (or any other authorization that you can check explicitly).
I just finished developing an app that interacts with the Beacons and User location.
I ask for locationManager the requestAlwaysAuthorization permission and I have added in the plist NSLocationAlwaysUsageDescription property with my description; everything works perfectly!!!
I realized that: if a user does not accept the requested permission, iOS disables localization always and when in use, making very limited the use of the app.
I wish that if a user refuses the requestAlwaysAuthorization automatically being asked requestWhenInUseAuthorization permission!
This is possible with some native method or I have to handle the request for another permission?
Thanks to all!
EDIT:
How do apps like Shazam or Facebook to have three choices "Never," "When in use" and "Always" in the location settings?
Surely there is a way to present them to the user?!?!
You can't do that. When in doubt, please always head to the Apple documentation.
https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/index.html#//apple_ref/occ/instm/CLLocationManager/requestAlwaysAuthorization
After requestAlwaysAuthorization is finished (the user accepted/denied), the status is changed to ether kCLAuthorizationStatusDenied or kCLAuthorizationStatusAuthorized(or some other, doesn't matter).
Furthermore, both requestAlwaysAuthorization and requestWhenInUseAuthorization both have such logic (described in the documentation)
If the current authorization status is anything other than kCLAuthorizationStatusNotDetermined, this method does nothing and does not call the locationManager:didChangeAuthorizationStatus: method.`
If the user denies the requestAlwaysAuthorization the status is changed to kCLAuthorizationStatusDenied and both request authorizations will be ignored in future.
I have a setting that is shown to the user on first run, and depending on this setting the app will either call requestAlwaysAuthorization or requestWhenInUseAuthorization. If the user said no to this setting and later on changes it to yes, I want the app to try and "upgrade" the location authorisation to Always, but I don't get a popup. Is this possible?