Службы определения местоположения не работают в iOS 8

608

Мое приложение, которое отлично работало на iOS 7, не работает с iOS 8 SDK.

CLLocationManagerне возвращает местоположение, и я не вижу свое приложение в меню « Настройки» -> « Службы определения местоположения» . Я сделал поиск Google по этому вопросу, но ничего не пришло. Что может быть не так?

özg
источник
Вы также можете использовать это как справочное приложение для решения github.com/jbanford/ConstantLocationUpdates
ashok vadivelu
19
Я написал о некоторых изменениях в менеджере локаций в iOS 8 здесь: nevan.net/2014/09/core-location-manager-changes-in-ios-8
Неван Кинг,
2
Вы можете попробовать использовать эту библиотеку, которая упрощает API-интерфейсы Core Location и предоставляет хороший интерфейс на основе блоков, а также нормализует все различия между различными версиями iOS (полное раскрытие: я автор): github.com/lmirosevic/GBLocation
lms
Я нашел некоторую ссылку здесь datacalculation.blogspot.in/2014/11/…
Тест iOS
2
@ nevanking Вы, сэр! нужна корона! Я боролся с этой проблемой с момента перемен и до сих пор не нашёл "руководства", как это исправить, это было бы дружелюбно по отношению к новичкам. Ваш гид сделал таким же идиотом, как я, справляюсь с проблемой сам. Большое спасибо за эту ссылку.
Патрик Р

Ответы:

1086

Я решил свою собственную проблему.

Очевидно в iOS 8 SDK, requestAlwaysAuthorization(для фонового местоположения) или requestWhenInUseAuthorization(местоположение только, когда передний план) CLLocationManagerтребуется вызов перед запуском обновлений местоположения.

Там также должно быть NSLocationAlwaysUsageDescriptionили NSLocationWhenInUseUsageDescriptionключ Info.plistс сообщением , которое будет отображаться в строке. Добавление их решило мою проблему.

введите описание изображения здесь

Надеюсь, это поможет кому-то еще.

РЕДАКТИРОВАТЬ: Для получения более подробной информации, посмотрите на: Core-Location-Manager-Changes-in-ios-8

özg
источник
6
Можете ли вы поделиться точной ценностью, обновленной в Info.plist? Я не могу увидеть этот ключ в моем Info.plist. Я добавил это, и все же это, кажется, не работает. Я использую Swift, iOS8 и XCode 6 бета 4
Виджай Кумар AB
4
@Vjay - вы должны отредактировать файл Info.plist в редакторе, не можете установить эти ключи в Xcode (начиная с бета-версии 6).
Кендалл Хельмштеттер Гелнер
11
Просто напоминание, если вы не хотите показывать пользовательские объяснения пользователю, просто установите этот ключ в пустую строку.
nonamelive
7
Вам нужно сохранить ваш LocationManager, чтобы он работал. так что сделайте свой CLLocationManager сильным свойством
Vassily
273
Я «ЛЮБЛЮ», что вы не получаете ни ошибок, ни предупреждений, ни сообщений журнала, ни НИЧЕГО, если вы пропустите запись в списке. По сути, Apple создала вызов API, который НИЧЕГО не выполняет, если у вас нет соответствующей записи в списке. Спасибо @OrtwinGentz ​​за это.
MobileVet
314

Я тащил свои волосы с той же проблемой. Xcode дает вам ошибку:

Попытка начать MapKitобновление местоположения без запроса авторизации местоположения. Должен позвонить -[CLLocationManager requestWhenInUseAuthorization]или -[CLLocationManager requestAlwaysAuthorization]первым.

Но даже если вы реализуете один из вышеперечисленных методов, он не будет запрашивать пользователя, если в info.plist отсутствует запись для NSLocationAlwaysUsageDescriptionили NSLocationWhenInUseUsageDescription.

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

<key>NSLocationWhenInUseUsageDescription</key>
<string>This application requires location services to work</string>

<key>NSLocationAlwaysUsageDescription</key>
<string>This application requires location services to work</string>

Я думаю, что эти записи могли отсутствовать с тех пор, как я запустил этот проект в Xcode 5. Я предполагаю, что Xcode 6 может добавить записи по умолчанию для этих ключей, но не подтвердил.

Вы можете найти больше информации об этих двух настройках здесь

Генри
источник
13
xcode 6 не добавляет эти ключи по умолчанию, если вы намереваетесь реализовать CLLocationManager, вы должны добавить их вручную
Уэсли Смит
1
Я также должен был добавить их вручную, не мог добавить через представление RawValues ​​info.plist в Xcode6!
Кендалл Хельмштеттер Гелнер
1
Я всегда искал это. Мое сообщение [CLLLocationManager authorizationStatus] возвращало только значение <nil>. После добавления вышеуказанных ключей он начал возвращать соответствующие перечисления для вывода сообщений. Из того, что я обнаружил, это известная ошибка iOS 8, но целую вечность я ничего не мог найти в моем контексте. Спасибо мил!
MrOli3000
4
Мне нравится строковое значение, которое вы вводите
Крис Чен,
1
Сообщение будет отображаться как вспомогательное сообщение в предупреждении, которое спрашивает, хочет ли пользователь поделиться своим местоположением. Таким образом, простое использование пустых (пустых) значений имеет смысл в моем приложении. Объяснение того, почему вы хотите использовать местоположение, также имеет смысл. Тем не менее, NSLocationWhenInUseUsageDescription не вел себя так, как ожидалось для меня (т.е. продолжал получать отказ в разрешении, даже если возвращаемое значение было правильным). NSLocationAlwaysUsageDescription работал нормально.
Аркади Боб
104

Чтобы обеспечить обратную совместимость с iOS 7, необходимо проверить, работает ли пользователь под управлением iOS 8 или iOS 7. Например:

#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)

//In ViewDidLoad
if(IS_OS_8_OR_LATER) {
   [self.locationManager requestAlwaysAuthorization];
}

[self.locationManager startUpdatingLocation];
JKoko
источник
164
Лучше, чем проверка версии, это проверить, есть ли у объекта этот селектор, например: if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { ...
progrmr
1
У меня были проблемы с реализацией решения @ progrmr при сборке на Xcode 5, так как он не знает, что это за requestAlwaysAuthorizationметод. Мое дополнительное решение было использовать эту линию в ifзаявлении вместо обычного вызова метода: [self.locationManager performSelector:@selector(requestAlwaysAuthorization)];. Может быть, это очевидно для других людей, но мне понадобилось время, чтобы понять. Я думаю, что это правильное решение, пока не будет выпущен финальный Xcode 6.
VinceFior
2
Правильным решением является сборка с Xcode 6. Если вы строите с Xcode 5, вам не нужно запрашивать авторизацию, это происходит автоматически.
прогрмр
Вы могли бы иметь точку зрения. Меня беспокоило то, что я хотел, чтобы мой код компилировался в Xcode 5 (даже если он не будет работать на iOS 8, если не скомпилирован в Xcode 6), пока моя команда переходит на Xcode 6. Но, возможно, это лучший рабочий процесс, чтобы писать код нормально и не сливать его, пока мы не перейдем к Xcode 6 .. Спасибо.
VinceFior
@VinceFior рекомендуемый подход заключается в условной компиляции с использованием макроса, определенного в SDK __IPHONE_OS_VERSION_MAX_ALLOWED( #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000)
Стивен Крамер,
50
- (void)startLocationManager
{
    locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;
    locationManager.distanceFilter = kCLDistanceFilterNone; //whenever we move
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;

    [locationManager startUpdatingLocation];
    [locationManager requestWhenInUseAuthorization]; // Add This Line


}

И в ваш файл info.plist введите описание изображения здесь

нео D1
источник
1
Нашел похожее решение более наглядным способом на сайте datacalculation.blogspot.in/2014/11/…
iOS Test
2
@Hemang: Согласно документации Apple Dev: запуск служб определения местоположения безопасен до определения статуса авторизации вашего приложения. Хотя вы можете запускать службы определения местоположения, эти службы не доставляют никаких данных, пока статус авторизации не изменится на kCLAuthorizationStatusAuthorizedAlways или kCLAuthorizationStatusAuthorizedWhenInUse.
Андрей
Немного поздно, но я рекомендую вам скрыть не относящиеся к делу части вашего plist-файла, особенно FacebookAppID
Przemysław Wrzesiński
Спасибо Но это всего лишь фиктивный образец :)
нео D1
Также важно, чтобы проект указывал на правильный info.plist (тот, где определен ключ). Это определяется настройками сборки проекта в файле Info.plist.
ясный свет
30

Согласно документации Apple:

Начиная с iOS 8, наличие значения NSLocationWhenInUseUsageDescriptionили NSLocationAlwaysUsageDescriptionключа в файле Info.plist вашего приложения является обязательным. Затем также необходимо запросить разрешение у пользователя до регистрации обновлений местоположения, позвонив по телефону [self.myLocationManager requestWhenInUseAuthorization]или в [self.myLocationManager requestAlwaysAuthorization]зависимости от ваших потребностей. Строка, введенная вами в Info.plist, будет отображаться в следующем диалоговом окне.

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

metatheoretic
источник
Я нашел простое описание здесь на datacalculation.blogspot.in/2014/11/…
iOS Test
28
- (void)viewDidLoad
{

    [super viewDidLoad];
    self.locationManager = [[CLLocationManager alloc] init];

    self.locationManager.delegate = self;
    if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]){
        NSUInteger code = [CLLocationManager authorizationStatus];
        if (code == kCLAuthorizationStatusNotDetermined && ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)] || [self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])) {
            // choose one request according to your business.
            if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]){
                [self.locationManager requestAlwaysAuthorization];
            } else if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]) {
                [self.locationManager  requestWhenInUseAuthorization];
            } else {
                NSLog(@"Info.plist does not contain NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription");
            }
        }
    }
    [self.locationManager startUpdatingLocation];
}

>  #pragma mark - CLLocationManagerDelegate

    - (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 didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
    {
        NSLog(@"didUpdateToLocation: %@", newLocation);
        CLLocation *currentLocation = newLocation;

        if (currentLocation != nil) {
            longitudeLabel.text = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.longitude];
            latitudeLabel.text = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.latitude];
        }
    }

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

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

Оба эти ключа принимают строку

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

введите описание изображения здесь

Адарш Г.Дж.
источник
19

Мое решение, которое может быть скомпилировано в Xcode 5:

#ifdef __IPHONE_8_0
    NSUInteger code = [CLLocationManager authorizationStatus];
    if (code == kCLAuthorizationStatusNotDetermined && ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)] || [self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])) {
        // choose one request according to your business.
        if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]){
            [self.locationManager requestAlwaysAuthorization];
        } else if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]) {
            [self.locationManager  requestWhenInUseAuthorization];
        } else {
            NSLog(@"Info.plist does not contain NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription");
        }
    }
#endif
    [self.locationManager startUpdatingLocation];
Yinfeng
источник
2
Хорошее динамическое решение для использования во всех приложениях. Хотя я бы изменил порядок и вместо проверки iphone 8.0 я бы проверил, отвечает ли менеджер местоположений на авторизацию, а затем запустил авторизационный статус для получения кода. Это сделает его более универсальным.
zirinisp
Работал и на xCode 7.2.
Тоторо
17

Старый код для запроса местоположения не будет работать в iOS 8. Вы можете попробовать этот метод для авторизации местоположения:

- (void)requestAlwaysAuthorization
{
    CLAuthorizationStatus status = [CLLocationManager authorizationStatus];

    // If the status is denied or only granted for when in use, display an alert
    if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status ==        kCLAuthorizationStatusDenied) {
        NSString *title;
        title = (status == kCLAuthorizationStatusDenied) ? @"Location services are off" :   @"Background location is not enabled";
        NSString *message = @"To use background location you must turn on 'Always' in the Location Services Settings";

        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title
                                                            message:message
                                                           delegate:self
                                                  cancelButtonTitle:@"Cancel"
                                                  otherButtonTitles:@"Settings", nil];
        [alertView show];
    }
    // The user has not enabled any location services. Request background authorization.
    else if (status == kCLAuthorizationStatusNotDetermined) {
        [self.locationManager requestAlwaysAuthorization];
    }
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if (buttonIndex == 1) {
        // Send the user to the Settings for this app
        NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
        [[UIApplication sharedApplication] openURL:settingsURL];
    }
}
Nits007ak
источник
UIAlertView устарела. Вместо этого вы должны использовать UIAlertController.
Пасан Премаратне
да, я знаю, что он устарел, но это также будет работать. но да, лучше использовать UIAlertController для IOS8.
Nits007ak
12

В iOS 8 вам нужно сделать две дополнительные вещи, чтобы заставить работать локацию: добавить ключ в ваш Info.plist и запросить авторизацию у менеджера локаций, попросив его запустить

info.plist:

<key>NSLocationUsageDescription</key>
<string>I need location</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>I need location</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>I need location</string>

Добавьте это в свой код

if (IS_OS_8_OR_LATER)
{
    [locationmanager requestWhenInUseAuthorization];

    [locationmanager requestAlwaysAuthorization];
}
byJeevan
источник
1
неясно, является ли ваш псевдокод вызовом препроцессора или обычным вызовом
El Dude
1
Добавьте это в свой файл constants.h или .pch: #define IS_OS_8_OR_LATER ([[UIDevice currentDevice] .systemVersion floatValue]> = 8.0)
OxenBoxen
Почему вы запрашиваете и то, и другое, вам следует добавить комментарий, в котором упоминается только одно или другое в зависимости от потребностей вашего приложения
powerj1984,
Часть info.plist достаточно просто сделать в Unity3d, но как бы добавить часть кода, если использовать unity3d? где ?
CthulhuJon
11

Одна распространенная ошибка для разработчиков Swift:

Сначала убедитесь, что вы добавили значение в список для NSLocationWhenInUseUsageDescriptionили NSLocationAlwaysUsageDescription.

Если вы все еще не видите всплывающее окно с запросом авторизации, посмотрите, вставляете ли вы строку var locationManager = CLLocationManager()в viewDidLoadметод вашего View Controller . Если вы это сделаете, то даже если вы позвоните locationManager.requestWhenInUseAuthorization(), ничего не появится. Это связано с тем, что после выполнения viewDidLoad переменная locationManager освобождается (очищается).

Решение состоит в том, чтобы найти строку var locationManager = CLLocationManager()в верхней части метода класса.

st.derrick
источник
9

Прежде [locationManager startUpdatingLocation];, добавьте запрос сервисов определения местоположения iOS8:

if([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
    [locationManager requestAlwaysAuthorization];

Отредактируйте приложение Info.plistи добавьте ключ NSLocationAlwaysUsageDescriptionсо строковым значением, которое будет отображаться пользователю (например,We do our best to preserve your battery life. )

Если ваше приложение нуждается в услугах определения местоположения только при открытом приложении, замените:

requestAlwaysAuthorizationс requestWhenInUseAuthorizationи

NSLocationAlwaysUsageDescriptionс NSLocationWhenInUseUsageDescription.

budidino
источник
9

Я работал над приложением, которое было обновлено до iOS 8, и службы определения местоположения перестали работать. Вы, вероятно, получите ошибку в области отладки примерно так:

Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.

Я сделал наименее навязчивую процедуру. Сначала добавьте NSLocationAlwaysUsageDescriptionзапись в ваш info.plist:

Введите описание изображения здесь

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

Далее я создал условное для iOS 8:

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

После этого locationManager:didChangeAuthorizationStatus:метод вызывается:

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:  (CLAuthorizationStatus)status
{
    [self gotoCurrenLocation];
}

И теперь все отлично работает. Как всегда, ознакомьтесь с документацией .

Крис Уттер
источник
7

Решение с обратной совместимостью:

SEL requestSelector = NSSelectorFromString(@"requestWhenInUseAuthorization");
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined &&
    [self.locationManager respondsToSelector:requestSelector]) {
    [self.locationManager performSelector:requestSelector withObject:NULL];
} else {
    [self.locationManager startUpdatingLocation];
}

Настройте ключ NSLocationWhenInUseUsageDescription в вашем Info.plist

hrchen
источник
2
Это не правильно, а как насчет дела kCLAuthorizationStatusDenied? он переходит к другому и начинает обновлять местоположение, которое не является правильным!
Electronix384128
@BenMarten Я не думаю, что это должно иметь значение. Вы должны справиться с этим самостоятельно locationManager: (CLLocationManager *)manager didFailWithError: (NSError *)error. Однако он забыл добавить startUpdatingLocation в оператор if, поэтому после того, как они его принимают или отклоняют, он фактически не вызывает startUpdateLocation.
Крис
6

Решение с обратной совместимостью, которое не выдает предупреждений Xcode:

SEL requestSelector = NSSelectorFromString(@"requestWhenInUseAuthorization");
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined &&
  [self.locationManager respondsToSelector:requestSelector]) {
((void (*)(id, SEL))[self.locationManager methodForSelector:requestSelector])(self.locationManager, requestSelector);
  [self.locationManager startUpdatingLocation];
} else {
  [self.locationManager startUpdatingLocation];
}

NSLocationWhenInUseUsageDescriptionКлюч настройки в вашем Info.plist.

Для iOS версии 11.0+ : NSLocationAlwaysAndWhenInUseUsageDescriptionключ настройки в вашем Info.plist. вместе с другими 2 ключами.

Александр Белявский
источник
Это не правильно, а как насчет дела kCLAuthorizationStatusDenied? он переходит к другому и начинает обновлять местоположение, которое не является правильным!
Electronix384128
Это довольно странно, это прекрасно работает для меня, не очень хорошо, прекрасно и с разрешением, и с разрешением. Даже решение Джейкоба выглядит точно, но у меня не получилось. Странно но сработало !!!
Джош
Вызов [self.locationManager startUpdatingLocation] сразу после запросаWhenInUseAuthorization не имеет смысла
Костя Ким
5

Это проблема с ios 8 Добавьте это к своему коду

if (IS_OS_8_OR_LATER)
{
    [locationmanager requestWhenInUseAuthorization];

    [locationmanager requestAlwaysAuthorization];
}

и в info.plist:

 <key>NSLocationUsageDescription</key>
 <string>I need location</string>
 <key>NSLocationAlwaysUsageDescription</key>
 <string>I need location</string>
 <key>NSLocationWhenInUseUsageDescription</key>
 <string>I need location</string>
Пуджа Патель
источник
NSLocationUsageDescriptionне используется на iOS8 +
Карлос Рикардо
4

Чтобы получить доступ к местоположению пользователя в iOS 8, вам нужно будет добавить

NSLocationAlwaysUsageDescription in the Info.plist 

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

Annu
источник
4

Objective-C Процедура Следуйте приведенным ниже инструкциям:

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

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

 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription
 3. NSLocationAlwaysUsageDescription

введите описание изображения здесь Для 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
 3. NSLocationAlwaysUsageDescription

введите описание изображения здесь Для 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

}
Alok
источник
Убедитесь, что NSLocationAlwaysUsageDescription также добавлено, иначе вы получите ошибку при загрузке в магазине приложений.
Alok
Ваше сообщение также должно быть информативным, в противном случае Apple отклонит приложение во время повторного просмотра.
Alok
3

Для тех, кто использует Xamarin , мне пришлось добавить ключ NSLocationWhenInUseUsageDescriptionв info.plist вручную, так как он не был доступен в раскрывающихся списках ни в Xamarin 5.5.3 Build 6, ни в XCode 6.1 - только NSLocationUsageDescriptionбыл в списке, и это привело CLLocationManagerк продолжению молча провалиться

Дерек Дин
источник
2
        // ** Don't forget to add NSLocationWhenInUseUsageDescription in MyApp-Info.plist and give it a string

        self.locationManager = [[CLLocationManager alloc] init];
        self.locationManager.delegate = self;
        // Check for iOS 8. Without this guard the code will crash with "unknown selector" on iOS 7.
        if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
            [self.locationManager requestWhenInUseAuthorization];
        }
        [self.locationManager startUpdatingLocation];


    // Location Manager Delegate Methods    
    - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
    {
        NSLog(@"%@", [locations lastObject]);

}
Просенджит Госвами
источник
2

Маленький помощник для всех вас, у которых более одного файла Info.plist ...

find . -name Info.plist | xargs -I {} /usr/libexec/PlistBuddy -c 'Add NSLocationWhenInUseUsageDescription string' {} 

Он добавит необходимый тег ко всем файлам Info.plist в текущем каталоге (и подпапках).

Другой это:

find . -name Info.plist | xargs -I {} /usr/libexec/PlistBuddy -c 'Set NSLocationWhenInUseUsageDescription $YOURDESCRIPTION' {} 

Это добавит ваше описание ко всем файлам.

Питер Мортенсен
источник
2

Я получаю похожую ошибку в iOS9 (работа с Xcode 7 и Swift 2): при попытке запуска обновлений местоположения MapKit без запроса авторизации местоположения. Сначала необходимо вызвать [CLLocationManager requestWhenInUseAuthorization] или - [CLLocationManager requestAlwaysAuthorization]. Я следовал учебному пособию, но он использовал iOS8 и Swift 1.2. В Xcode 7 и Swift 2 есть некоторые изменения, я нашел этот код, и он прекрасно работает для меня (если кому-то нужна помощь):

import UIKit
import MapKit
import CoreLocation

class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {

    // MARK: Properties
    @IBOutlet weak var mapView: MKMapView!

    let locationManager = CLLocationManager()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.startUpdatingLocation()
        self.mapView.showsUserLocation = true

    }

    // MARK: - Location Delegate Methods

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let location = locations.last
        let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
        let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1))
        self.mapView.setRegion(region, animated: true)
    }

    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        print("Errors: " + error.localizedDescription)
    }
}

Наконец, я поместил это в info.plist: список свойств информации: NSLocationWhenInUseUsageDescription Значение: приложению нужны серверы местоположения для персонала

Хорхе Луис Хименес
источник
2

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

NSLocationWhenInUseUsageDescription

NSLocationAlwaysUsageDescription

в файл Info.plist.

    <key>NSLocationWhenInUseUsageDescription</key>
    <string>Because I want to know where you are!</string>
    <key>NSLocationAlwaysUsageDescription</key>
    <string>Want to know where you are!</string>

Смотрите это изображение ниже.

Изображение Info.plist

Винот Вино
источник
1
  1. Добавьте ключ NSLocationWhenInUseUsageDescriptionили NSLocationAlwaysUsageDescription(фоновое использование GPS) со строкой, предлагающей использовать GPS на каждой info.plistиз каждой цели.

  2. Запросите разрешение, запустив:

    [self initLocationManager: locationManager];

Где initLocationManagerнаходится

// asks for GPS authorization on iOS 8
-(void) initLocationManager:(CLLocationManager *) locationManager{

    locationManager = [[CLLocationManager alloc]init];

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

Помните, что если ключи не на каждой info.plistдля каждой цели, приложение не спросит пользователя. ifОбеспечивает совместимость с прошивкой 7 и respondsToSelector:метод гарантирует совместимость в будущем , а не только решение вопроса для прошивки 7 и 8.

Хуан Исаза
источник
0

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

Lorenzo
источник
0

Я добавляю эти клавиши в InfoPlist.stringsв прошивкой 8.4, IPad мини 2. Это тоже работает. Я не ставлю никаких ключей, как NSLocationWhenInUseUsageDescription, например , в моем Info.plist.


InfoPlist.strings :

"NSLocationWhenInUseUsageDescription" = "I need GPS information....";

База на этом потоке , по его словам as in iOS 7, может быть локализована в InfoPlist.strings. В моем тесте эти ключи можно настроить прямо в файле InfoPlist.strings.

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

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

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


ОБНОВИТЬ:

Я думаю, что @IOSметод лучше. Добавить ключ Info.plistс пустым значением и добавить локализованные строки в InfoPlist.strings.

AechoLiu
источник