Вызов CLLocationManager AuthorizationStatus?

В моем приложении у меня есть вкладка под названием "Discover". Вкладка "Поиск" будет использовать текущее местоположение пользователей, чтобы найти "материал" рядом с ними. Вместо того, чтобы представить пользователю общий запрос авторизации (который обычно отклоняется на основе исследований), я представляю пользователю модальное объяснение того, что мы просим. Если они скажут "да", ТОГО, появится всплывающее сообщение "Авторизация".

Однако у пользователя все еще есть возможность не указывать приглашение. Есть ли способ добавить обратный вызов в приглашение, чтобы, как только пользователь выберет опцию, я вижу, принимаются ли они или отклоняются?

Я пробовал это:

func promptForLocationDataAccess() {
    locationManager.requestWhenInUseAuthorization()
    println("test")
}

Как и ожидалось, "println" выполняется одновременно с появлением приглашения запроса, поэтому я не могу этого сделать.

Проблема заключается в том, что если пользователь предпочитает не использовать данные о местоположении, содержимое будет отличаться от того, что они приняли.

В идеале я надеюсь на какой-то обратный вызов, но на данном этапе я возьму любое логическое направление!

Ответы

Ответ 1

Вы можете использовать locationManager:didChangeAuthorizationStatus: CLLocationManagerDelegate метод как "обратный вызов" видов.

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

И в Swift (обновление, предложенное пользователем Майклом Марвиком, но отклонено по какой-то причине...):

func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
    if (status == CLAuthorizationStatus.denied) {
        // The user denied authorization
    } else if (status == CLAuthorizationStatus.authorizedAlways) {
        // The user accepted authorization
    } 
}

Ответ 2

При изменении статуса авторизации для местоположения будет вызываться метод делегата didChangeAuthorizationStatus:.

Когда вы вызываете requestWhenInUseAuthorization в первый раз после установки вашего приложения, метод делегата будет вызываться со статусом kCLAuthorizationStatusNotDetermined (0).

Если пользователь отказывается от доступа к службам доступа, тогда метод делегата будет вызван снова со статусом kCLAuthorizationStatusDenied (2).

Если пользователь одобряет доступ к службам доступа, тогда метод делегата будет вызван снова со статусом kCLAuthorizationStatusAuthorizedAlways (3) или kCLAuthorizationStatusAuthorizedWhenInUse (4) в зависимости от запрашиваемого разрешения.

При последующих запусках вашего приложения метод делегата получит статус kCLAuthorizationStatusDenied или kCLAuthorizationStatusAuthorizedAlways/kCLAuthorizationStatusAuthorizedWhenInUse после вызова requestWhenInUseAuthorization на основе текущего состояния разрешения служб местоположения для приложения в настройках устройства.

Ответ 3

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
    } 
}

Ответ 4

Это решение не лучшее во всех сценариях, но это сработало для меня, поэтому я решил поделиться с ним:

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)
    }
}

Теперь каждый раз, когда вы хотите использовать информацию о местоположении, просто обведите его этим:

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

Поэтому всякий раз, когда вы пытаетесь использовать информацию о местоположении, проверяется статус авторизации. Если у вас еще нет разрешения, он запрашивает разрешение и ждет, пока пользователь не нажмет кнопку "Разрешить" или кнопку "Не разрешать". Если нажать кнопку "Разрешить", любые запросы на данные о местоположении будут обрабатываться в отдельных потоках, но если нажать кнопку "Не разрешать", все запросы на местоположение будут отменены.

Ответ 5

Цель C

Для обратного вызова блока на hasChangeAuthorizationStatus добавьте это в .h

@property void(^authorizationCompletionBlock)(BOOL);

и следуя за .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;
    }
}

и добавьте обработчик следующим образом:

// 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);
        }
    }
}

и обработчик вроде этого

authorizationCompletionBlock = { isGranted in
        print(isGranted)
    }

Ответ 6

Подобно ответу tdon выше, я создал функцию с блоком завершения для передачи статуса после его получения с устройства:

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

TrackingState - это отдельное перечисление, которое я использую для управления отображением в контроллере представления. Вы также можете легко передать authorizationStatus() в блоке завершения:

func retrieveAuthorizationStatus(completion: @escaping (CLAuthorizationStatus) -> ()) {
    let status = CLLocationManager.authorizationStatus()
    completion(status)
}