Detect when requestAlwaysAuthorization not called iOS 14

Viewed 1177

I am trying to request user's location using multi step process; However, when calling requestAlwaysAuthorization if it is not executed I would like to move to show a message.

let me explain better by showing my flow

Here is my current flow

  1. Request While in use
    • The user chooses Allow Once -> Go to 2
    • the user chooses Allow While Using App -> Go to 2
    • the user chooses Don't Allow -> show error message
  2. Request Always permission
    • The user chooses Keep Only While Using -> Show error message (issue #1: I can't detect this)
    • The user chooses Change to Always Allow -> Show success message

If from 1 the user chose Allow Once I can't even call requestAlwaysAuthorization because calling it would result in nothing and even Apple states

If the user responded to requestWhenInUseAuthorization() with Allow Once, then Core Location ignores further calls to requestAlwaysAuthorization() due to the temporary authorization.

Source

My goal is if users selects Allow Once from 1 then requestAlwaysAuthorization should be skipped all together.

if from 1 Allow Wile Using App is selected and from requestAlwaysAuthorization Keep Only while using is chosen then I would like to know that state.

I know it can be done, I just don't know how. Here is an app that does what I am trying to achieve

enter image description here enter image description here enter image description here

From the first image user chose Allow While Using App then Keep Only While Using and they are able to detect it or able to detect the fact that the dialogue appeared and they didn't move to the third image until the user responded.

Another scenario as follows:

enter image description here enter image description here enter image description here

From the first image the user chose Allow Once and from the 2nd image no matter what the user choose they will go to image 3 without displaying the always permission (keep in mind the 2nd image is not a real permission, its just buttons that made to trick the user); so they are able to tell the dialogue didn't appear or that the user chose Allow Once from the previous step (one or the other and I can't do either one).

Obviously I cant record every combination and post as a gif, so if you would like to experiement the app name is Zenly

So the end goal is to be able to wait for the user to respond to the dialogue if it appears otherwise just move to the next screen.

Here is what I have done, quoting from apple

Core Location leaves the authorization as When In Use. The delegate doesn’t receive any updates.

I thought maybe when requesting always I should also execute the delegate manually so to the function requestAlwaysLocation() I added the line

self.locationManagerDidChangeAuthorization(self.locationManager)

However, that obviously doesn't work because in the case that Allow While Using App was chosen from step 1 and Change to Always Allow is chosen from step 2 now the delegate will be called twice...

Then I thought if I can detect the provisioning When in Use from step 1 I might be able to bypass but I don't know how to do it.

Here is a snippet of LocationManager

    func requestWhenInUserLocation()  {
        self.locationManager.requestWhenInUseAuthorization()
    }
    
    func requestAlwaysLocation() {
        self.locationManager.requestAlwaysAuthorization()
    }


    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        print("authroizatino changed")
//        let accuracyAuthorization = manager.accuracyAuthorization
        let status = manager.authorizationStatus

        // -change function will just change some internal properties and will post a notification so views that subscribe to it can react accordingly.
        
        switch status {
            case CLAuthorizationStatus.authorizedAlways:
                self.change(permission: .Location, to: .Location(.Always))
                break
            case CLAuthorizationStatus.authorizedWhenInUse:
                self.change(permission: .Location, to: .Location(.WhenInUse))
                break
            case CLAuthorizationStatus.denied:
                self.change(permission: .Location, to: .Denied)
                break
            case CLAuthorizationStatus.notDetermined:
                self.change(permission: .Location, to: .NotDetermined)
                break
            case CLAuthorizationStatus.restricted:
                self.change(permission: .Location, to: .Location(.Restricted))
                break
            @unknown default:
                self.change(permission: .Location, to: .Unknown)
                break
        }
    }


I hope I was able to explain what I want clearly

1 Answers

Thanks to @Paulw11 I was able to solve it. It was rather easy actually.

I cant add any implementation here as it will really depend on one's use case, and I am using SwiftUI.

So what I did was upon pressing the Request Always button I would create a bool state and set it to true, I also have an observer to the app's active state THIS IS THE KEY TO SOLVING THIS and I also have an observer on the bool state.

If the bool state changes and the app's active state did not change then the user have chosen Allow Once; However, if the state did change then I would wait for it to be active again.

If it becomes active I would check the location permission if it's still When in Use then the user chose Keep Only While Using otherwise they chose Change to Always

All credits go to Paulw11

EDIT: I also have observer for the app coming to foreground from background in case the user changes the location permission from settings

Note: the above algorithm can be improved quite a lot if you are using Combine with SwiftUI. Most of what I wrote is useless, you can just subscribe to the permission and the app's active state.

Related