Вызов 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)
}