Requesting "Always" Location Access in iOS13 for Geofences

Hi,


I have an app that uses geofences. For this, the "Always" location permission needs to be granted.


I've always used requestAlwaysAuthorization() for this at the time where the user signals their desire to set up a geofence (the apps functionality is they get a notification when they enter this geofence with some up to date data about it - there is a settings screen where they can choose to start receiving this notification, if they choose to do this, at this point I request Always permission so I can set the geofence)


I notice from 1:11:36 in the 2019 Platforms State of the Union - and from testing in the Xcode 11 Beta that calling request**Always**Authorization() now no longer gives the user the user the option to allow always. It only gives them the choice of While Using App, or allow once. The user apparently now has to grant the "While Using App" permission first, then according to the state of the union the app must ask for "Always" location later from the background. They didnt elaborate on how you will do this from the background or when you should.


I'm just wondering how this is going to work for geofences? I want to be able to set up the geofences within the app as this is the best experience for the user, rather than them having to leave the app to give background permission, then re-enter the app to set up which geofences they want. It also seems a poor experience for them to have to grant the permission twice - once for in use, then again for always, when I just want Always permission.


I do handle the app in a degraded state when the user chooses "While using app" - as this has been the requirement up until now. But there are areas of the app where it makes no sense for me to prompt and the user only be given the choose to accept the while using permission such as the use case noted at the start of this post, where I'm specifically asking the user if they want to set up a geofence.


Is there a better flow that can be done to request Always permission while still in the app - or perhaps a different permission status for geofences?


Thanks

Post not yet marked as solved Up vote post of TomThorpe Down vote post of TomThorpe
31k views

Replies

I filed a feedback with Apple as well. I encourage everyone to do so. Otherwise, complaining here is not going to change anything.
This change in iOS 13 makes no sense and is not good for anyone.

For me the geofencing doesn't work at all in iOS 13 (Beta 4 and 5). Neither with GPS nor with Beacon fencing. I even get the CLAuthorizationStatus "authorizedAlways" via

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus)


The same code runs perfect under iOS 12.

I had same issue.
I updated to Xcode 11 beta 5 and used `erase all contents and settings` option in simulator and now .always authorization comes after requesting always permission. But it seams like significat locaition changes are not yet working in ios 11 beta 5.
In ios 12.2 it works (tested in simulator using this method http://brainwashinc.com/2015/02/20/test-significant-location-change-ios-simulator/)

Hi guys, I have also noticed in our case that the application does not receive location updates in the background when this has the "Provisional Always" location access. We have noticed in simulator tests that once the "Always" prompt is shown by the system in the background, the application starts receiving location updates in the background as expected regardless of if the user chose "Keep Only While Using" or "Change to Always Allow".
The application has enabled the location updates background mode and set the allowBackgroundLocationUpdates property to true.
This is happening on iOS 13 public beta 4 (17A5547d). This is not an issue on iOS 12.

Is anyone seeing the same behavior?

I am seeing the same issue. I have a simple standalone app where I am asking for Always permission with background location enabled and it calls `startUpdatingLocation` once authorization is granted. When in `Provisional Always` and the app in foreground the location updates come in fine. But when the app is backgrounded, I get the location updates for only a few seconds and then it stops. Now, if you bring the app back to foreground, you will see the prompt and location updates start working again. It seems like as soon as the app knows to prompt, the location updates stop.


Another thing I noticed, if you set

`locationManager.showsBackgroundLocationIndicator = true`

then the location updates work fine and you are never prompted for `Keep When In Use` or `Allow Always`.

I am experiencing the same wrong behaviour in my app. It is pretty frustrating that Apple, with the introduction of iOS 11, forced us to gently ask for location permission in a way that the users can better understand why an upgrade makes sense for them; but now this seems to be not the correct pattern anymore. I agree with the reasoning behind the excalation of permissions, but Apple should stick to his line.


In my app I ask for "When in use" location permission once I first need the location data. At one point during app usage, a banner allows the user to upgrade location permissions to "Always" in order to receive location based notifications and activate other features that will enhance the user experience even when the app is not in use. With iOS 13 this escalation of permissions is not possible as the "Upgrade dialog" is not shown by the operative system.


I hope Apple will find a solution for this, even if we are a week away from GM release and the issue still persists.

Since iOS13 beta 6, I can see "Allow Always" prompt with the steps below.


1. My app requests Always

2. User picks While in use

3. The app’s delegate receives Always (actually it is .authorizedAlways (Provisional))

4. The apps goes to the background.

5. Wait a while (10 secs)

6. When the apps go to the foreground, "Allow Always" prompt appears.


If User picks "Always" at the step 6, the app can get location update always (both in the foreground and the background).


However, I found the app could not get location update at the step 5.

At the step 5, the authorization states is ".authorizedAlways (Provisional)". Does anyone know how to get location update?

I tried to set "allowsBackgroundLocationUpdates = true", but location update does not occur.

I am seeing the same behavior. I submitted a bug report: FB7216407

Hey, did you ever hear back from your radar? I wasn't able to open it. This behaviour still seems broken in the GM.

Thanks for sharing! I had exactly same issue. Another problem for us is that we cannot get continuous location updates in background after iOS 13, even though we have manually switch to Always in settings. The app stops around 30 seconds and then it was frozen there. Are you able to have continuous location update?

I am facing same problem from iOS 13.
I am facing the same problem in iOS14.

When I ask for requestAlwaysAuthorization() the user only have the option of choosing between "While In Use" or "Only Once".
If the user chooses "While In Use" I get the status on the delegate of "authorizedAlways".
However, when I go and check on the Location Services in Settings permission granted is "While Using the App"

Anyone facing the same problem in iOS14?
Is there any solution for this?
please make sure to add the following to info.plist
Privacy - Location Always and When In Use Usage Description
Privacy - Location When In Use Usage Description
Privacy - Location Temporary Usage Description Dictionary -> wantAccurateLocation
checkout this post
medium.com/better-programming/handling-location-permissions-in-ios-14-2cdd411d3cca

Code Block
import UIKit
import CoreLocation
class ActivitiesMapVC: UIViewController {
private let locationManager = CLLocationManager()
var locationStatus = "..."
override func viewDidLoad() {
super.viewDidLoad()
self.locationConfig()
}
func locationConfig(){
self.locationManager.delegate = self
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.requestAlwaysAuthorization()
}
func checkLocationAccuracyAllowed() {
switch locationManager.accuracyAuthorization {
case .reducedAccuracy:
locationStatus = "approximate location"
case .fullAccuracy:
locationStatus = "accurate location"
default:
locationStatus = "unknown type"
}
locationManager.startUpdatingLocation()
}
func requestLocationAuth() {
locationManager.requestAlwaysAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyReduced
let url = URLs()
switch locationManager.authorizationStatus {
case .denied: // Setting option: Never
let alert = UIAlertController(title: "Location Denied", message: "Please enable location", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: { [weak self] _ in
self?.dismiss(animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Go to Settings", style: .default, handler: { _ in
url.openURL(urlString: URLs.locationAppURL)
}))
alert.firstActiveTemplateAlert()
self.present(alert, animated: true, completion: nil)
case .notDetermined: break
case .authorizedWhenInUse:
// While using the app
locationManager.requestAlwaysAuthorization()
locationManager.requestLocation()
case .authorizedAlways:
// Always allow
locationManager.requestAlwaysAuthorization()
checkLocationAccuracyAllowed()
case .restricted: // Restricted by parental control
self.dismiss(animated: true, completion: nil)
default:
break
}
}
}
extension ActivitiesMapVC : CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
print(location.coordinate.latitude,location.coordinate.longitude)
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
let status = manager.authorizationStatus
let accuracyStatus = manager.accuracyAuthorization
if(status == .authorizedWhenInUse || status == .authorizedAlways){
if accuracyStatus == CLAccuracyAuthorization.reducedAccuracy{
locationManager.requestTemporaryFullAccuracyAuthorization(withPurposeKey: "wantAccurateLocation", completion: { [self] error in
if locationManager.accuracyAuthorization == .fullAccuracy{
locationStatus = "Full Accuracy Location Access Granted Temporarily"
}else{
locationStatus = "Approx Location As User Denied Accurate Location Access"
}
locationManager.startUpdatingLocation()
})
}
}else{
requestLocationAuth()
}
}
}