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

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

Поведение, которое я хочу, это поведение встроенного приложения Maps:

  • Reset предупреждения о местоположении в настройках > Общие > Reset > Reset Предупреждения о местоположении.
  • Запустить приложение "Карты".
  • Нажмите кнопку "Текущее местоположение" в левом нижнем углу.
  • Карты подсказки с "Картами" хотели бы использовать ваше текущее местоположение "|" Не разрешать "|" Разрешить".
  • Выберите опцию "Не разрешать".
  • Нажмите кнопку "Текущее местоположение" в нижнем левом углу.
  • Карты подсказки с "Включить службы определения местоположения, чтобы разрешить" Карты "определять ваше местоположение "|" Настройки "|" Отменить".

В моем собственном приложении один и тот же базовый поток приводит к тому, что мой CLLocationManagerDelegate -locationManager: метод didFailWithError: вызывается с ошибкой kCLErrorDenied на последнем шаге, и пользователю не предоставляется возможность открыть приложение "Настройки" , чтобы исправить его.

Я могу отобразить свое собственное предупреждение в ответ на эту ошибку, но у него не было бы возможности запустить приложение "Настройки" , как предупреждение, которое ОС может предоставить в качестве встроенного приложения "Карты".

Есть ли что-то в классе CLLocationManager, который отсутствует, который мог бы дать мне такое поведение?

Ответ 1

С iOS8 вы можете, наконец, связать пользователя с настройками через openURL. Например, вы можете создать UIAlertView с помощью одной кнопки, которая приведет пользователя в приложение "Настройки":

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:ICLocalizedString(@"LocationServicesPermissionTitle")
                                                    message:ICLocalizedString(@"LocationPermissionGeoFenceMessage")
                                                   delegate:self
                                          cancelButtonTitle:@"Settings"
                                          otherButtonTitles:nil];
    [alert show];

В вашем делете UIAlertView:

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    [alertView dismissWithClickedButtonIndex:buttonIndex animated:YES];
    [[UIApplication sharedApplication] openURL: [NSURL URLWithString: UIApplicationOpenSettingsURLString]];
}

Ответ 2

Update:

Как и в iOS 8, теперь существует константа UIApplicationOpenSettingsURLString, которая представляет URL-адрес, который при открытии открывает приложение "Настройки" в настройках вашего приложения (где пользователь может затем повторно включить службы определения местоположения).


Оригинал:

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

Ответ 3

AlertViews устарели в iOS 8. Теперь есть лучший способ обработки предупреждений с помощью нового AlertController:

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString( @"Enter your title here", @"" ) message:NSLocalizedString( @"Enter your message here.", @"" ) preferredStyle:UIAlertControllerStyleAlert];

UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString( @"Cancel", @"" ) style:UIAlertActionStyleCancel handler:nil];
UIAlertAction *settingsAction = [UIAlertAction actionWithTitle:NSLocalizedString( @"Settings", @"" ) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
   [[UIApplication sharedApplication] openURL:[NSURL URLWithString:
                                                    UIApplicationOpenSettingsURLString]];
}];

[alertController addAction:cancelAction];
[alertController addAction:settingsAction];

[self presentViewController:alertController animated:YES completion:nil];

Ответ 4

В соответствии с Документами Apple по методу locationServicesEnabled.

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

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

Так что, возможно, вы просто начинаете обновление служб сервисов, чтобы вызвать запрос?

Ответ 5

Вот быстрая реализация кода, предоставляемая Markus и bjc.

let alertController = UIAlertController(title: NSLocalizedString("Enter your title here", comment: ""), message: NSLocalizedString("Enter your message here.", comment: ""), preferredStyle: .alert)

let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: nil)
let settingsAction = UIAlertAction(title: NSLocalizedString("Settings", comment: ""), style: .default) { (UIAlertAction) in
                UIApplication.shared.openURL(NSURL(string: UIApplicationOpenSettingsURLString)! as URL)
            }

alertController.addAction(cancelAction)
alertController.addAction(settingsAction)
            self.present(alertController, animated: true, completion: nil)

Ответ 6

Думаю, у вас будет ответ на ваш вопрос, когда Apple подумает о новом SDK. В настоящее время и, насколько я знаю, это невозможно:

Нет обработчика URL-адресов

Нельзя использовать метод

Но... Поскольку Maps делает это, это МОЖЕТ быть сделано, но, вероятно, используя частный API. Если вы не боитесь такого кодирования, вы должны искать там, на мой взгляд.

Ответ 7

Вот быстрая версия кода в ответе Маркуса. Этот код создает предупреждение, которое дает пользователю возможность открывать "Настройки".

let alertController = UIAlertController(title: NSLocalizedString("Enter your title here", comment: ""), message: NSLocalizedString("Enter your message here.", comment: ""), preferredStyle: .Alert)

let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .Cancel, handler: nil)
let settingsAction = UIAlertAction(title: NSLocalizedString("Settings", comment: ""), style: .Default) { (UIAlertAction) in
    UIApplication.sharedApplication().openURL(NSURL(string: UIApplicationOpenSettingsURLString)!)
}

alertController.addAction(cancelAction)
alertController.addAction(settingsAction)
self.presentViewController(alertController, animated: true, completion: nil)

Ответ 8

В Swift 4 в его синтаксисе есть обновление.

Swift 4

extension UIAlertController {

    func createSettingsAlertController(title: String, message: String) -> UIAlertController {

      let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)

      let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: nil)
      let settingsAction = UIAlertAction(title: NSLocalizedString("Settings", comment: ""), style: .default) { (UIAlertAction) in
        UIApplication.shared.open(URL(string: UIApplicationOpenSettingsURLString)! as URL, options: [:], completionHandler: nil)
      }

      alertController.addAction(cancelAction)
      alertController.addAction(settingsAction)
      self.present(alertController, animated: true, completion: nil)

   }
}

Ответ 9

Расширение Swift 3 для создания контроллера предупреждений о настройках:

import Foundation

extension UIAlertController {
    func createSettingsAlertController(title: String, message: String) -> UIAlertController {
        let controller = UIAlertController(title: title, message: message, preferredStyle: .alert)

        let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment:"" ), style: .cancel, handler: nil)
        let settingsAction = UIAlertAction(title: NSLocalizedString("Settings", comment:"" ), style: .default, handler: { action in
            UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!)
        })
        controller.addAction(cancelAction)
        controller.addAction(settingsAction)

        return controller
    }
}