iOS: приложение не запрашивает у пользователя разрешения при установке приложения. получение kCLAuthorizationStatusNotDefined определяется каждый раз - Objective-c & Swift

Я пытаюсь получить местоположение пользователя в моем приложении для iOS. Я включил фреймворк corelocation в свой проект первым. Затем по нажатию кнопки я вызываю базовый интерфейс API, как показано ниже. Когда я пытаюсь установить это на устройстве, местоположение ядра никогда не спрашивает разрешения пользователя. Когда я пытаюсь получить местоположение по нажатию кнопки, я получаю kCLAuthorizationStatusNotDefined, определенный как authorisationStatus. Пожалуйста, помогите мне в этом. Я понятия не имею, что происходит.

- (IBAction)fetchLessAccurateLocation:(id)sender {
    [self.txtLocation setText:@""];

    locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
    locationManager.distanceFilter = 1000;

    if ([self shouldFetchUserLocation]) {
        [locationManager startUpdatingLocation];
    }
}

Это мой метод shouldFetchUserLocation:

-(BOOL)shouldFetchUserLocation{

    BOOL shouldFetchLocation= NO;

    if ([CLLocationManager locationServicesEnabled]) {
        switch ([CLLocationManager authorizationStatus]) {
            case kCLAuthorizationStatusAuthorized:
                shouldFetchLocation= YES;
                break;
            case kCLAuthorizationStatusDenied:
            {
                UIAlertView *alert= [[UIAlertView alloc]initWithTitle:@"Error" message:@"App level settings has been denied" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil];
                [alert show];
                alert= nil;
            }
                break;
            case kCLAuthorizationStatusNotDetermined:
            {
                UIAlertView *alert= [[UIAlertView alloc]initWithTitle:@"Error" message:@"The user is yet to provide the permission" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil];
                [alert show];
                alert= nil;
            }
                break;
            case kCLAuthorizationStatusRestricted:
            {
                UIAlertView *alert= [[UIAlertView alloc]initWithTitle:@"Error" message:@"The app is recstricted from using location services." delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil];
                [alert show];
                alert= nil;
            }
                break;

            default:
                break;
        }
    }
    else{
        UIAlertView *alert= [[UIAlertView alloc]initWithTitle:@"Error" message:@"The location services seems to be disabled from the settings." delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil];
        [alert show];
        alert= nil;
    }

    return shouldFetchLocation;
}

Вот мой основной метод делегата местоположения:

- (void)locationManager:(CLLocationManager *)manager
    didUpdateLocations:(NSArray *)locations __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_6_0){

    NSLog(@"location fetched in delegate");

    CLLocation* location = [locations lastObject];
    NSDate* eventDate = location.timestamp;
    NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];

    if (abs(howRecent) < 15.0) {
        // If the event is recent, do something with it.
        NSLog(@"inside loop.... latitude %+.6f, longitude %+.6f\n",
              location.coordinate.latitude,
              location.coordinate.longitude);
    }
    NSLog(@"latitude %+.6f, longitude %+.6f\n",
          location.coordinate.latitude,
          location.coordinate.longitude);
    [self.txtLocation setText:[NSString stringWithFormat:@"\nlatitude: %+.6f \nlongitude:   %+.6f", location.coordinate.latitude, location.coordinate.longitude]];

    [locationManager stopUpdatingLocation];
    [locationManager stopMonitoringSignificantLocationChanges];

    if(locationManager!=nil){
        locationManager.delegate= nil;
        locationManager= nil;
    }
}

13 ответов

Решение

Я столкнулся с той же проблемой, после переустановки приложения оно возвращалось kCLAuthorizationStatusNotDetermined всякий раз, проверяя [CLLocationManager authorizationStatus] и приложение даже не показывалось в Настройках> Конфиденциальность> Службы определения местоположения.

Диалог авторизации, который iOS предлагает пользователю одобрить доступ к службам определения местоположения, запущен на [locationManager startUpdatingLocation] который в твоем случае никогда не называется (shouldFetchUserLocation будет всегда NO).

Решение Мигеля С. кажется хорошим решением, попробую это.

Редактировать для iOS8.x

Когда вышла iOS8, это немного изменило способ использования CLLocationManager. Как уже упоминалось несколько раз в других ответах, это требует дополнительного шага по сравнению с iOS7. Сегодня я сам столкнулся с проблемой и нашел эту статью (на нее ссылались многие другие вопросы, но она завершает мой предыдущий ответ). Надеюсь, поможет!

iOS8 принесла нам значительные изменения API с помощью LocationsServices

Если предположить, [CLLocationManager locationServicesEnabled] вернуть ДА,

С первым запуском приложения для iOS [как iOS7, так и iOS8] - locationMangers(CLLocationManager) для параметра authorizationStatus предустановлено значение

authorizationStatus(CLAuthorizationStatus) = kCLAuthorizationStatusNotDetermined

Подсказка в iOS7+

Инициируйте locationManger (CLLocationManager, Strong) и установите делегаты (CLLocationManagerDelegate)

Теперь, чтобы предложить пользователю использовать Locations Services и перечислить приложение в меню "Настройки"> "Конфиденциальность"> "Locations Services", он ДОЛЖЕН вызывать любой из методов "Locations Services", это зависит от требований приложения, например, если приложение является одним из приведенных ниже.

Места Обновления - [self.locationManager startUpdatingLocation]

РегионМониторинг - [self.locationManager startMonitoringForRegion:beaconRegion]

сразу после выполнения вышеуказанного метода iOS будет запрашивать у пользователя запрос на использование Locations Services в приложении, и независимо от того, какое приложение выберет пользователь, оно будет указано в меню "Настройки"> "Конфиденциальность"> "Locations Services"

Подсказка в iOS8+

Это в том же случае с iOS8, с первым запуском сервисов определения местоположения приложений

authorizationStatus(CLAuthorizationStatus) = kCLAuthorizationStatusNotDetermined

В iOS 8 появились новые способы показа подсказки пользователю

[self.locationManager requestAlwaysAuthorization] 
or
[self.locationManager requestWhenInUseAuthorization]

requestAlwaysAuthorization/requestWhenInUseAuthorization доступен для iOS8. если целью развертывания приложения является iOS7, то включите его в блок if, чтобы убедиться, что в iOS7 это не приведет к сбою приложения.

if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
{
[self.locationManager requestAlwaysAuthorization]; .
}

или же

if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])
{
[self.locationManager requestWhenInUseAuthorization];
}

Очень важно ###:

Согласно iOS8, обязательно включать строку, указывающую, почему приложение использует requestAlwaysAuthorization/requestWhenInUseAuthorization. В info.plist включите любое из этих свойств, соответствующее требованию приложения.

для kCLAuthorizationStatusAuthorizedAlways всегда включать пару ключ / значение (строковое значение)

NSLocationAlwaysUsageDescription = App use Locations service mode Always

для kCLAuthorizationStatusAuthorizedWhenInUse включает пару ключ / значение (строковое значение)

NSLocationWhenInUseUsageDescription = App use Locations service mode In Use 

Снимок экрана info.plist (на случай, если это кого-то смущает)

Цель-C Следуйте инструкциям ниже:

iOS-11 Для iOS 11 посмотрите на этот ответ: доступ к местоположению iOS 11

Необходимо добавить два ключа в лист и предоставить сообщение, как показано на рисунке ниже:

 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription

iOS-10 и ниже:

NSLocationWhenInUseUsageDescription

locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
if([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]){
    [locationManager requestWhenInUseAuthorization];
}else{
    [locationManager startUpdatingLocation];
} 

Методы делегирования

#pragma mark - Lolcation Update 
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog(@"didFailWithError: %@", error);
    UIAlertView *errorAlert = [[UIAlertView alloc]
                               initWithTitle:@"Error" message:@"Failed to Get Your Location" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [errorAlert show];
}
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    switch (status) {
        case kCLAuthorizationStatusNotDetermined:
        case kCLAuthorizationStatusRestricted:
        case kCLAuthorizationStatusDenied:
        {
            // do some error handling
        }
            break;
        default:{
            [locationManager startUpdatingLocation];
        }
            break;
    }
}
- (void)locationManager:(CLLocationManager *)manager
     didUpdateLocations:(NSArray *)locations
{
    CLLocation *location = [locations lastObject];
    userLatitude =  [NSString stringWithFormat:@"%f", location.coordinate.latitude] ;
    userLongitude =  [NSString stringWithFormat:@"%f",location.coordinate.longitude];
    [locationManager stopUpdatingLocation];
}

Свифт Код

Следуйте инструкциям ниже:

iOS-11 Для iOS 11 посмотрите на этот ответ: доступ к местоположению iOS 11

Необходимо добавить два ключа в лист и предоставить сообщение, как показано на рисунке ниже:

 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription

iOS-10 и ниже:

import CoreLocation
class ViewController: UIViewController ,CLLocationManagerDelegate {
var locationManager = CLLocationManager()

//MARK- Update Location 
func updateMyLocation(){
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
    if locationManager.respondsToSelector(#selector(CLLocationManager.requestWhenInUseAuthorization)){
       locationManager.requestWhenInUseAuthorization()
    }
    else{
        locationManager.startUpdatingLocation()
    }
}

Методы делегирования

//MARK: Location Update
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
    NSLog("Error to update location :%@",error)
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
    switch status {
    case .NotDetermined: break
    case .Restricted: break
    case .Denied:
            NSLog("do some error handling")
        break
    default:
        locationManager.startUpdatingLocation()
    }
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
     let location = locations.last! as CLLocation
    var latitude = location.coordinate.latitude
    var longitude = location.coordinate.longitude

}

Вы должны иметь NSLocationWhenInUseUsageDescription добавил к вам info.plist, Это немного странно, но просто добавьте его как строковое значение без текста, а затем, когда вы хотите, чтобы местоположение начиналось с:

CLLocationManager * locationManager = [[CLLocationManager alloc] init];

[locationManager requestWhenInUseAuthorization];

Если вы столкнулись с этой проблемой на iOS8, используйте :requestWhenInUseAuthorization.

В iOS 8 вам нужно сделать две дополнительные вещи, чтобы заставить местоположение работать: добавьте ключ в ваш Info.plist и запросите авторизацию у менеджера местоположений, попросив его запустить. Существует два ключа Info.plist для авторизации нового местоположения. Требуется один или оба этих ключа. Если ни один из ключей не существует, вы можете вызвать startUpdatingLocation, но менеджер местоположения фактически не запустится. Он также не отправит сообщение об ошибке делегату (так как он никогда не запускался, он не может потерпеть неудачу). Также произойдет сбой, если вы добавите один или оба ключа, но забудете явно запросить авторизацию.

Поэтому первое, что вам нужно сделать, это добавить один или оба из следующих ключей в ваш файл Info.plist:

NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription

Оба этих ключа принимают строку, которая является описанием того, зачем вам нужны службы определения местоположения. Вы можете ввести строку типа "Местоположение требуется, чтобы узнать, где вы находитесь", которую, как и в iOS 7, можно локализовать в файле InfoPlist.strings.

Далее вам нужно запросить авторизацию для соответствующего метода местоположения, WhenInUse или Background. Используйте один из этих вызовов:

[self.locationManager requestWhenInUseAuthorization]
[self.locationManager requestAlwaysAuthorization]

Для получения дополнительной информации.

У меня была проблема, о которой Рашми Ранджан Маллик сказал в комментариях несколько раз с момента выхода iOS 7. Я действительно думаю, что это одна ошибка в iOS 7, у них их полно в новой версии iOS.

Для меня вопрос был таким же:

1. Откройте приложение, никогда не спрашивали о местоположении. iOS не спрашивала о разрешении
2. Я зашел в Настройки-> Конфиденциальность-> Службы определения местоположения, и моего приложения там не было.
3. Я не смог изменить разрешения для своего приложения.

Одним из способов решения этой проблемы является:

1. Убейте ваше приложение.
2. Отключить все службы определения местоположения кнопкой главного переключателя.
3. Зайдите в свое приложение снова.
4. Убейте ваше приложение.
5. Снова включите службы определения местоположения на предыдущей кнопке переключения.
6.Если по-прежнему не отображается в списке, вернитесь в свое приложение, снова убейте его и вернитесь к настройкам.
7. Теперь это должно быть там.

Это сработало для меня, и я надеюсь, что это полезно.

ОБНОВЛЕНИЕ: если iOS 8 будет уверен, что вы звоните requestWhenInUseAuthorization или же requestAlwaysAuthorization

Вы можете следовать этому коду::)

#ifdef __IPHONE_8_0
    if(NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1)
    {
        if([[Wave_SettingsObject sharedObject] backgroundLocationEnabled].boolValue == YES)
        {
            if(![[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"])
            {
                NSLog(@"Info.plist does not contain NSLocationAlwaysUsageDescription key");
            }

            if ([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) //iOS 8+
            {
                [locationManager requestAlwaysAuthorization];
            }
        }
        else if([[Wave_SettingsObject sharedObject] isLocationEnabled].boolValue == YES)
        {
            if(![[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"])
            {
                NSLog(@"Info.plist does not contain NSLocationWhenInUseUsageDescription key");
            }

            if ([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) //iOS 8+
            {
                [locationManager requestWhenInUseAuthorization];
            }

        }
    }
#endif

Удалите приложение и попробуйте запустить его снова.

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

Или же:

Вы можете заставить приложение начать мониторинг местоположения с помощью следующего кода:

self.locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];

в ваших методах делегата вы можете определить наличие ошибки при получении и сообщить об этом пользователю.

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    // Delegate of the location manager, when you have an error
    NSLog(@"didFailWithError: %@", error);

    UIAlertView *errorAlert = [[UIAlertView alloc]     initWithTitle:NSLocalizedString(@"application_name", nil) message:NSLocalizedString(@"location_error", nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", nil) otherButtonTitles:nil];

    [errorAlert show];
}

Если у вас есть какие-либо вопросы, скажите мне.

Я столкнулся с этой проблемой, реализовал все необходимое, включая ключи pList, и мое приложение все еще не запрашивало местоположение.

Оказывается, проблема в том, что переменная locationManager не может быть локальной - она ​​должна быть переменной экземпляра.

Так что вместо

-(void) updateLocation {
   CLLocationManager *locationManager = ...
}

это должно быть:

CLLocationManager *locationManager;

-(void) updateLocation {
  self.locationManager = ...
}

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

Я перестал получать сообщение с запросом на авторизацию, и, поскольку оно работало до того, как требования, описанные в других ответах, уже были выполнены: ключ в plist, проверка статуса авторизации, а затем запрос разрешения в ios8+.

В моем случае проблема была связана с режимом "Руководство по доступу". Это приложение для киоска, и оно начинает измерять радиомаяки только после активации "Руководства по доступу". Но кажется, что запросы на авторизацию не отправляются в этом режиме. Я мог бы это исправить, просто переместив запрос на авторизацию в DidLoad первого отображаемого представления.

То же самое происходит с запросом на использование камеры.

При запросе местоположения вы не должны забывать эти вещи (iOS 8+):

  1. Добавьте этот флаг в ваш info.plist приложения: NSLocationAlwaysUsageDescription или NSLocationWhenInUseUsageDescription зависят от того, хотите ли вы всегда иметь доступ к местоположению или только когда приложение используется (второй рекомендуется, если вам не всегда нужен доступ). Это самое главное, потому что это ново и странно.
  2. Если вы запрашиваете разрешение всегда, не забудьте добавить обновления местоположения в качестве фонового режима для ваших целевых возможностей
  3. Убедитесь, что вы запрашиваете правильное разрешение при инициализации менеджера местоположения:

    -(void)initLocationManager{
        locationManager = [[CLLocationManager alloc] init];
        locationManager.delegate=self;
    
        [locationManager requestAlwaysAuthorization]; // HERE ASK FOR THE RELEVANT
    }
    

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

Попробуйте добавить

[locationManager startUpdatingLocation]

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

РЕДАКТИРОВАТЬ:

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

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

Другие вопросы по тегам