CLLocationManager AuthorizationStatus callback?

后端 未结 6 1827
天命终不由人
天命终不由人 2021-02-01 02:38

In my app I have a tab called \"Discover\". The Discover tab will use the users current location to find \"stuff\" near them. Instead of presenting the user with a generic Autho

相关标签:
6条回答
  • 2021-02-01 03:14

    This solution isn't the best in all scenarios, but it worked for me so I thought I'd share:

    import Foundation
    import CoreLocation
    
    class LocationManager: NSObject, CLLocationManagerDelegate {
        static let sharedInstance = LocationManager()
        private var locationManager = CLLocationManager()
        private let operationQueue = OperationQueue()
    
        override init(){
            super.init()
    
            //Pause the operation queue because
            // we don't know if we have location permissions yet
            operationQueue.isSuspended = true
            locationManager.delegate = self
        }
    
        ///When the user presses the allow/don't allow buttons on the popup dialogue
        func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    
            //If we're authorized to use location services, run all operations in the queue
            // otherwise if we were denied access, cancel the operations
            if(status == .authorizedAlways || status == .authorizedWhenInUse){
                self.operationQueue.isSuspended = false
            }else if(status == .denied){
                self.operationQueue.cancelAllOperations()
            }
        }
    
        ///Checks the status of the location permission
        /// and adds the callback block to the queue to run when finished checking
        /// NOTE: Anything done in the UI should be enclosed in `DispatchQueue.main.async {}`
        func runLocationBlock(callback: @escaping () -> ()){
    
            //Get the current authorization status
            let authState = CLLocationManager.authorizationStatus()
    
            //If we have permissions, start executing the commands immediately
            // otherwise request permission
            if(authState == .authorizedAlways || authState == .authorizedWhenInUse){
                self.operationQueue.isSuspended = false
            }else{
                //Request permission
                locationManager.requestAlwaysAuthorization()
            }
    
            //Create a closure with the callback function so we can add it to the operationQueue
            let block = { callback() }
    
            //Add block to the queue to be executed asynchronously
            self.operationQueue.addOperation(block)
        }
    }
    

    Now every time you want to use location information, just surround it with this:

    LocationManager.sharedInstance.runLocationBlock {
        //insert location code here
    }
    

    So whenever you try using the location information, the authorization status is checked. If you don't have permission yet, it requests permission and waits until the user presses the "Allow" button or the "Don't allow" button. If the "Allow" button is pressed, any requests for location data will be processed on separate threads, but if the "Don't Allow" button is pressed, all location requests will be canceled.

    0 讨论(0)
  • 2021-02-01 03:22

    When the authorisation status for location changes, the delegate method didChangeAuthorizationStatus: will be called.

    When you call requestWhenInUseAuthorization the first time after your app is installed the delegate method will be called with status kCLAuthorizationStatusNotDetermined (0).

    If the user declines location services access then the delegate method will be called again with status kCLAuthorizationStatusDenied (2).

    If the user approves location services access then the delegate method will be called again with status kCLAuthorizationStatusAuthorizedAlways (3) or kCLAuthorizationStatusAuthorizedWhenInUse (4) depending on the permission that was requested.

    On subsequent executions of your app the delegate method will receive status kCLAuthorizationStatusDenied or kCLAuthorizationStatusAuthorizedAlways/kCLAuthorizationStatusAuthorizedWhenInUse after calling requestWhenInUseAuthorization based on the current state of location services permission for the app in the device settings.

    0 讨论(0)
  • 2021-02-01 03:25

    You can use the locationManager:didChangeAuthorizationStatus: CLLocationManagerDelegate method as a "callback" of sorts.

    - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
        if (status == kCLAuthorizationStatusDenied) {
            // The user denied authorization
        }
        else if (status == kCLAuthorizationStatusAuthorized) {
            // The user accepted authorization
        }
    }
    

    And in Swift (update suggested by user Michael Marvick, but rejected for some reason...):

    func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
        if (status == CLAuthorizationStatus.denied) {
            // The user denied authorization
        } else if (status == CLAuthorizationStatus.authorizedAlways) {
            // The user accepted authorization
        } 
    }
    
    0 讨论(0)
  • 2021-02-01 03:25

    Swift 3

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if (status == CLAuthorizationStatus.denied) {
            // The user denied authorization
        } else if (status == CLAuthorizationStatus.authorizedAlways) {
            // The user accepted authorization
        } 
    }
    
    0 讨论(0)
  • 2021-02-01 03:28

    Similar to tdon's response above, I created a function with a completion block to communicate the status once it is retrieved from the device:

    func retrieveAuthorizationStatus(completion: @escaping (TrackingState) -> ()) {
        let status = CLLocationManager.authorizationStatus()
        switch status {
        case .authorizedWhenInUse:
            completion(.off)
        default:
            completion(.issue)
        }
    }
    

    TrackingState is a separate enum I'm using to manage display within a view controller. You could just as easily pass the authorizationStatus() in the completion block:

    func retrieveAuthorizationStatus(completion: @escaping (CLAuthorizationStatus) -> ()) {
        let status = CLLocationManager.authorizationStatus()
        completion(status)
    }
    
    0 讨论(0)
  • 2021-02-01 03:35

    Objective C

    For a block callback on didChangeAuthorizationStatus add this in .h

    @property void(^authorizationCompletionBlock)(BOOL);
    

    and following in .m

    -(void)locationManager:(CLLocationManager *)locationManager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
    _authorizationStatus = status;
    
    switch (status) {
        case kCLAuthorizationStatusAuthorizedAlways:
        case kCLAuthorizationStatusAuthorizedWhenInUse:
            if (self.authorizationCompletionBlock) {
                self.authorizationCompletionBlock(YES); // this fires block
            }
        default:
            if (self.authorizationCompletionBlock) {
                self.authorizationCompletionBlock(NO); // this fires block
            }
            break;
        }
    }
    

    and add handler like this:

    // this listens block
    // in your VC or Utility class
    authorizationCompletionBlock = ^(BOOL isGranted) {
        completionBlock(isGranted);
    };
    

    Swift 3.2

    var authorizationCompletionBlock:((Bool)->())? = {_ in}
    
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch (status)
        {
        case (.authorizedWhenInUse):
            if authorizationCompletionBlock != nil
            {
                authorizationCompletionBlock!(true)
            }
    
        default:
            if authorizationCompletionBlock != nil
            {
                authorizationCompletionBlock!(false);
            }
        }
    }
    

    and handler like this

    authorizationCompletionBlock = { isGranted in
            print(isGranted)
        }
    
    0 讨论(0)
提交回复
热议问题