简体   繁体   中英

What makes provisional Always authorization provisional?

According to Apple, if you ask for your Core Location app to get Always authorization when the authorization is "not determined", the user sees the dialog for When In Use authorization but in fact your app gets Always authorization — provisionally.

This is supposed to mean that if you don't actually use your Always powers, you will lose them, reverting to When In Use.

Okay, but when will that reversion happen? I can't seem to make it happen. My app just stays at Always authorization, even though the user thinks it is only When In Use authorization.

Here's the entire code of my test app (iOS 14):

class ViewController: UIViewController, CLLocationManagerDelegate {
    @IBOutlet weak var label: UILabel!
    
    let locman = CLLocationManager()
    override func viewDidLoad() {
        super.viewDidLoad()
        locman.delegate = self
    }

    @IBAction func doAskForAlways(_ sender: Any) {
        self.checkForLocationAccess(always:true)
    }
    
    func checkForLocationAccess(always:Bool = false, andThen f: (()->())? = nil) {
        let status = self.locman.authorizationStatus()
        switch status {
        case .authorizedWhenInUse:
            if always { // try to step up
                self.locman.requestAlwaysAuthorization()
            } else {
                f?()
            }
        case .authorizedAlways:
            f?()
        case .notDetermined:
            if always {
                self.locman.requestAlwaysAuthorization()
            } else {
                self.locman.requestWhenInUseAuthorization()
            }
        case .restricted:
            break
        case .denied:
            break
        default: fatalError()
        }
    }
    
    fileprivate func updateStatus(_ status: CLAuthorizationStatus) {
        self.label.text = {
            switch status {
            case .authorizedAlways: return "Always"
            case .authorizedWhenInUse: return "When In Use"
            default: return ""
            }
        }()
    }
    
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        let status = manager.authorizationStatus()
        print("authorization is", status.rawValue)
        updateStatus(status)
    }
    
    @IBAction func doStatus(_ sender: Any) {
        self.updateStatus(self.locman.authorizationStatus())
    }
}

You need two buttons and a label. Tap the first button to ask for Always authorization when you have no authorization to start with ("not determined"). You see the When In Use authorization dialog. Grant authorization. Now play with the app and keep watching the status display in the label. You can tap the second button to update the status if needed.

The problem is that it stays at Always. When will my "provision" come to an end so that the authorization reverts to When In Use? How can I encourage this to happen?

In WWDC 2019's What's New in Core Location , they outline the basic process in iOS 13.0:

  1. Your app requests “always” permission.

  2. The user sees “when in use” permissions alert, not an “always” permission alert:

    在此处输入图像描述

  3. If the user grants “when in use” the app is in “provisional always” state.

    In this case, and somewhat confusingly, the authorizationStatus will return .authorizedAlways when you are in this “provisional always” state and the Settings app on the phone will suggest it's in “when in use” state. But in reality, it's in this “provisional always” state, not quite what one might infer from authorizationStatus nor from what you see in the Settings app.

    Needless to say, if the user doesn't even grant “when in use” (eg they deny or chose “only once”), then obviously you won't be in “provisional always” state.

  4. It remains in this provisional state until, as the video says, you “start using 'always' powers”. For example, if you start significant change service and move a distance sufficient to trigger a significant change.

    When the app does “start using 'always' powers”, the OS will ask the user if they are is willing to upgrade “when in use” to “always”. (It won't always happen immediately, but will wait until the user is not busy doing other things, to reduce the risk that they'll dismiss the alert just to get back to what they were doing.)

    在此处输入图像描述

So, it's not a question of “reverting” to some other state. The app will remain in this “provisional always” state until there is final “agreement” (where the user sees the second alert and either agrees to upgrade to .authorizedAlways or denies and it is set to .authorizedWhenInUse ).


I know you know this, but for the sake of future readers:

In WWDC 2020 video What's new in location , they describe a change introduced in iOS 13.4. Instead of the flow above (where you ask for “always”, the user sees “when in use” permissions, and they don't see the “upgrade to always” until “always” services are actually triggered), iOS 13.4 introduced a new flow, where you can ask for “when in use” (rather than “always”) and assuming the user granted it, you can ask for “always” later, where appropriate in the app, and the user get the second alert (this time asking if the user would like to upgrade to “always” or not). You just need the appropriate permissions strings.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM