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

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

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

26 ответов


в конечном итоге я решил свою проблему.

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

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

enter image description here

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

изменить: Для получения более подробной информации, посмотрите на: ядра-месте-менеджер-изменения-в-Иос-8


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

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

но даже если вы реализуете один из вышеуказанных методов, он не будет запрашивать пользователя, если в информации нет записи.файл plist для NSLocationAlwaysUsageDescription или NSLocationWhenInUseUsageDescription.

добавьте следующие строки в свою информацию.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 может добавить записи по умолчанию для этих ключей, но не подтвердил.

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


чтобы убедиться, что это совместимо с 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];

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


}

и к вашей информации.файл plist enter image description here


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

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

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


- (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 вам нужно сделать две дополнительные вещи, чтобы получить место работы: добавить ключ к вашей информации.plist и запрос авторизации из местоположения менеджер просит его начать. Есть две информации.plist ключи для нового авторизация местоположения. Требуется один или оба ключа. Если ни один из ключей не существует, вы можете вызвать startUpdatingLocation, но диспетчер местоположения не запускается. Это не приведет к неудаче. сообщение делегату либо (поскольку это никогда не начиналось, не может начаться. неудача.) Он также потерпит неудачу, если вы добавите один или оба ключа, но забудете явно запрашивать авторизацию. Итак, первое, что вам нужно сделать это добавить один или оба из следующих ключей к вашей информации.plist file:

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

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

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

enter image description here


мое решение, которое может быть скомпилировано в 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];

старый код для запроса местоположения не будет работать в 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];
    }
}

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

информация.файл 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];
}

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

сначала убедитесь, что вы добавили значение в plist для любого NSLocationWhenInUseUsageDescription или NSLocationAlwaysUsageDescription.

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

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


до [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.


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

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

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

Enter image description here

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

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

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

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

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

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


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

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

настройка nslocationwheninuseusagedescription ключ в вашей информации.файл plist


решение с обратной совместимостью, которое не создает предупреждения 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+ : Setup NSLocationAlwaysAndWhenInUseUsageDescription ключ в Info.plist. вместе с другими 2-мя ключами.


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

if (IS_OS_8_OR_LATER)
{
    [locationmanager requestWhenInUseAuthorization];

    [locationmanager requestAlwaysAuthorization];
}

и информация.файл 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>

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

NSLocationAlwaysUsageDescription in the Info.plist 

Это запросит у пользователя разрешение на получение их текущего местоположения.


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


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

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

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

 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription
 3. NSLocationAlwaysUsageDescription

enter image description here для iOS-10 и ниже:

NSLocationWhenInUseUsageDescription

enter image description here

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 доступ к местоположению

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

 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription
 3. NSLocationAlwaysUsageDescription

enter image description here для iOS-10 и ниже:

enter image description here

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

}

        // ** 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]);

}

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

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

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

другое:

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

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


Keep Ключи Какао информация всегда под рукой для этих обновлений, вот ссылка:

https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW26

наслаждайтесь.


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

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 Значение: приложение нуждается в серверах местоположения для персонала


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

NSLocationWhenInUseUsageDescription

NSLocationAlwaysUsageDescription

в инфо.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 image


  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 для каждой цели приложение не будет спрашивать пользователя. The if обеспечивает совместимость с iOS 7 и respondsToSelector: метод гарантирует будущую совместимость, а не просто решение проблемы для iOS 7 и 8.


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


Я добавить ключ InfoPlist.strings на iOS 8.4, iPad mini 2. это тоже работает. Я не устанавливаю никаких ключей, как NSLocationWhenInUseUsageDescription в свою Info.plist.


InfoPlist.струны:

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

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

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

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

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


обновление:

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