Is there a way to trigger the .always coreLocation permission proactively in iOS13?
Asked Answered
H

4

8

Under iOS13, when you request the .always permission for coreLocation (to enable background location e.g. for geofences or iBeacons), the app is only granted a "provisional always" permission, which does not allow it to use coreLocation in the background. At a later stage, in principle the OS should popup a permission request to switch to the .always permission. I have yet to experience it, and it seems (looking at Apple developer forums) that nobody have found a way to consistently trigger this dialog popup.

I have asked for .always (which can only provide a useless "provisional always" permission), and then tried to "upgrade" to a real .always permission, but nothing happens (no popup, no permission change)

I have also tried to follow the WWDC recommandation by the book, asking for .always, receiving provisional always, and then trusting that the OS would show the dialog at some stage - with no luck.

Even more troublesome, even if I change manually the permission setting to a real .always permission for my app, the app continues to be unable to range locations in the background.

If asking for .always and receiving a "provisional" always permission, I would expect the OS the show the location dialog at some stage to propose a "real" .always permission. This hasn't happened in 2 weeks, despite entering geofences in the background 10's of times.

I would also expect the permission "upgrade" flow to work, which is not the case despite what's explained in the WWDC video and docs for coreLocation.

If Apple goes ahead with iOS 13 as is, I expect that numerous apps which legitimately range location in the background will stop working as expected entirely.

Has anybody made any progress on that front ? I have filed a "feedback" to Apple, but don't expect to receive a timely response from them before the September iOS 13 GM.

Hyaloplasm answered 6/8, 2019 at 10:46 Comment(0)
R
12

When you request a user for their "Always" location permission in iOS 13:

locationManager.requestAlwaysAuthorization()

1) The user will get this alert:

Request permission dialog

2) If you asked for always permission and your user chooses Allow While in Use your app will think it got the .authorizedAlways permission but this is the provisional .authorizedAlways permission.

3) Next, when your app would normally receive location events in the background iOS does not directly launches your app in the background with the events but waits until it thinks the user is not doing anything and it then will present this dialog:

Always location dialog permission

According to the video, this can take a while (6:39):

The prompt that the user can grant your app always authorization from will occur later. {...} Core Location waits for a time when we think that the user is not busy in order to maximize their ability to understand what's going on and minimize the chance that they'll give a get-out-of-my-way kind of response.

During this this (in between the app going to the background and the prompt being shown) you won't receive location update events:

They'll be delivered if you app receives always authorization ultimately and not if it receives a when in use authorization. But they also won't be delivered if the user just hasn't chosen yet.

So, during this time, if more events are generated on that basis, if you're monitoring requests, then those events will displace the ones that came earlier, and the earlier ones will be dropped. And then finally Core Location will drop the event part for anything that's become just too old.

4) Then when the user chooses Change to Always Allow, the .authorizedAlways permission will become final (unless the user changes it from the settings somewhere in the future). And you will start to receive location events.

Unless (5) the user chooses Keep Only While Using and the final permission will become .authorizedWhenInUse.

Here's the overview from the presentation (numbers mine):

Location permissions flow ios 13

And another link to the full video: https://developer.apple.com/videos/play/wwdc2019/705

Does that answer your questions?

If I change manually the permission setting to a real .always permission for my app, the app continues to be unable to range locations in the background.

That should not be the case. Did you change it in the system preferences?

Try the GM seed, maybe they fixed some bugs regarding this flow.

Resolutive answered 17/9, 2019 at 11:40 Comment(1)
What a downright confusing and annoying mess for all parties involved. It was just fine when Always Allow was a clear option and if I wanted to switch to When In Use, I could just switch to it in the settings. I was pulling my hair out trying to find why my app wasn't;t prompting the Always Allow option in the permission alert. Thanks for the explanation.Pule
E
3

To see the second dialog with the Allow Always prompt you have to:

  1. Disable the blue indicator.
  2. Go to the background.
  3. Wait at least 5 seconds.
  4. Try to get a location update or use any other core location service.
  5. Wait until the user locks and unlocks the device.

To facilitate this, you can set the distance filter to none and start getting continuous location updates.

If you want the location updates to be delivered in the background, then you have to show the blue indicator. And then the second dialog requesting Allow Always would never appear.

Erfurt answered 28/8, 2019 at 23:12 Comment(0)
I
3

Adding this in case someone comes across this post. It seems like Apple improved the process for obtaining Always permission.

According to the documentation, "to obtain Always authorization, your app must first request When In Use permission followed by requesting Always authorization."

So,

  1. Ask for When in Use permission
locationManager.requestWhenInUseAuthorization()
  1. Detect authorization change using the CLLocationManagerDelegate
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
  switch manager.authorizationStatus {

    // Ask for Always permission
    case .authorizedWhenInUse:
      locationManager.requestAlwaysAuthorization()
    
    // Confirm Always status
    case .authorizedAlways:
      switch manager.accuracyAuthorization {
      case .fullAccuracy:
        print("The app has Always permission with full accuracy.")
      case .reducedAccuracy:
        print("The app has Always permission with reduced accuracy.")
      }

    // Handle other cases
    ...
  }
}

This will trigger the second dialog that offers the "Change to Always Allow"

Impropriate answered 13/1, 2023 at 3:7 Comment(1)
good idea but not working on ios 16.6Jonquil
S
1

I am not aware of any direct way to set the permission to Always. From the WWDC videos and experiments, locationManager.requestAlwaysAuthorization() will provide a dialog that does not include the [Always Allow] option. Selecting the [Allow While Using App] puts it in "Provisional Always" mode, but to the user and the app, this is confusing. The user just set it to "Allow While Using App", but the app thinks it's "Always", but it's not yet, the App does not get events, until the second prompt. Very confusing. I was able to get the second prompt, but not right away after the event, it's up to iOS. I too have posted to Apple Feedback, and hope that they will provide some provision for Apps that need Always.

Satang answered 6/8, 2019 at 18:13 Comment(1)
Thanks for your feedback. How long after getting the provisional Always permission did you see the second prompt? Did the app do something specific in between? Was it reproductible (not in terms of timing, but at least in terms of occurence)? I'm not even seeing it :/ I have filed a feedback as well (and an additional one for the fact that even if the user sets the always permission manually, the app does not benefit from it...)Hyaloplasm

© 2022 - 2024 — McMap. All rights reserved.