Los servicios de ubicación no funcionan en iOS 8

Mi aplicación que funcionó bien en iOS 7 no funciona con iOS 8 SDK.

CLLocationManager no devuelve una ubicación, y tampoco veo mi aplicación en Configuración -> Servicios de ubicación . Hice una búsqueda en Google sobre el tema, pero no salió nada. ¿Qué podría estar mal?

Terminé resolviendo mi propio problema.

Aparentemente en iOS 8 SDK, requestAlwaysAuthorization (para ubicación en segundo plano) o requestWhenInUseAuthorization (ubicación solo cuando en primer plano) se necesita llamar a CLLocationManager antes de comenzar las actualizaciones de ubicación.

También debe haber NSLocationAlwaysUsageDescription clave NSLocationAlwaysUsageDescription o NSLocationWhenInUseUsageDescription en Info.plist con un mensaje que se mostrará en el aviso. Agregar estos resolvió mi problema.

enter image description here

Espero que ayude a alguien más.

EDITAR: Para obtener más información, echa un vistazo a: Core-Location-Manager-Changes-in-ios-8

Me estaba tirando de los pelos con el mismo problema. Xcode te da el error:

Intentando iniciar las actualizaciones de ubicación de MapKit sin solicitar autorización de ubicación. Debe llamar -[CLLocationManager requestWhenInUseAuthorization] o -[CLLocationManager requestAlwaysAuthorization] .

Pero incluso si implementa uno de los métodos anteriores, no solicitará al usuario a menos que haya una entrada en info.plist para NSLocationAlwaysUsageDescription o NSLocationWhenInUseUsageDescription .

Agregue las siguientes líneas a su info.plist donde los valores de cadena representan la razón por la que necesita acceder a la ubicación de los usuarios

 NSLocationWhenInUseUsageDescription This application requires location services to work NSLocationAlwaysUsageDescription This application requires location services to work 

Creo que estas entradas pueden haber faltado desde que comencé este proyecto en Xcode 5. Supongo que Xcode 6 podría agregar entradas predeterminadas para estas claves, pero no las ha confirmado.

Puede encontrar más información sobre estas dos configuraciones aquí

Para garantizar que esto sea compatible con iOS 7, debe verificar si el usuario ejecuta iOS 8 o iOS 7. Por ejemplo:

 #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 } 

Y a su archivo info.plist enter image description here

De acuerdo con los documentos de Apple:

A partir de iOS 8, se requiere la presencia de un valor de clave NSLocationWhenInUseUsageDescription o NSLocationAlwaysUsageDescription en el archivo Info.plist de su aplicación. También es necesario solicitar permiso al usuario antes de registrarse para las actualizaciones de ubicación, ya sea llamando a [self.myLocationManager requestWhenInUseAuthorization] o [self.myLocationManager requestAlwaysAuthorization] dependiendo de su necesidad. La cadena que ingresó en Info.plist se mostrará en el siguiente diálogo.

Si el usuario otorga el permiso, es un negocio como siempre. Si niegan el permiso, entonces el delegado no es informado de las actualizaciones de ubicación.

 - (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]; } } 

En iOS 8, debe hacer dos cosas adicionales para que la ubicación funcione: agregue una clave a su Info.plist y solicite autorización al administrador de ubicación para que comience. Hay dos claves Info.plist para la nueva autorización de ubicación. Se requiere una o ambas de estas claves. Si ninguna de las claves está allí, puede llamar a startUpdatingLocation, pero el administrador de ubicación no se iniciará realmente. Tampoco enviará un mensaje de error al delegado (dado que nunca se inició, no puede fallar). También fallará si agrega una o ambas claves pero olvida solicitar explícitamente la autorización. Entonces, lo primero que debe hacer es agregar una o ambas de las siguientes claves a su archivo Info.plist:

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

Ambas teclas toman una cadena

que es una descripción de por qué necesita servicios de ubicación. Puede ingresar una cadena como “Se requiere una ubicación para averiguar dónde se encuentra” que, como en iOS 7, se puede localizar en el archivo InfoPlist.strings.

enter image description here

Mi solución que se puede comstackr en 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]; 

El código anterior para preguntar ubicación no funcionará en iOS 8. Puede probar este método para autorización de ubicación:

 - (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]; } } 

En iOS 8 necesita hacer dos cosas adicionales para que la ubicación funcione: agregue una clave a su Info.plist y solicite autorización del administrador de ubicación para que comience.

info.plist:

 NSLocationUsageDescription I need location NSLocationAlwaysUsageDescription I need location NSLocationWhenInUseUsageDescription I need location 

Agregue esto a su código

 if (IS_OS_8_OR_LATER) { [locationmanager requestWhenInUseAuthorization]; [locationmanager requestAlwaysAuthorization]; } 

Un error común para los desarrolladores de Swift:

Primero asegúrese de agregar un valor al plist para NSLocationWhenInUseUsageDescription o NSLocationAlwaysUsageDescription .

Si todavía no ve una ventana emergente que solicita autorización, mire para ver si está poniendo la línea var locationManager = CLLocationManager() en el método viewDidLoad su controlador de viewDidLoad . Si lo hace, incluso si llama a locationManager.requestWhenInUseAuthorization() , no aparecerá nada. Esto se debe a que una vez que viewDidLoad se ejecuta, la variable locationManager es desasignada (eliminada).

La solución es localizar la línea var locationManager = CLLocationManager() en la parte superior del método de clase.

Antes de [locationManager startUpdatingLocation]; , agregue una solicitud de servicios de ubicación iOS8:

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

Edite el Info.plist su aplicación y agregue la clave NSLocationAlwaysUsageDescription con el valor de cadena que se mostrará al usuario (por ejemplo, We do our best to preserve your battery life. NSLocationAlwaysUsageDescription We do our best to preserve your battery life. ) We do our best to preserve your battery life.

Si su aplicación necesita servicios de ubicación solo mientras la aplicación está abierta, reemplace:

requestAlwaysAuthorization con requestWhenInUseAuthorization and

NSLocationAlwaysUsageDescription con NSLocationWhenInUseUsageDescription .

Estaba trabajando en una aplicación que se actualizó a iOS 8 y los servicios de ubicación dejaron de funcionar. Probablemente obtendrá un error en el área de Depuración así:

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

Hice el procedimiento menos intrusivo. Primero agregue la entrada NSLocationAlwaysUsageDescription a su info.plist:

Ingrese la descripción de la imagen aquí

Observe que no llené el valor de esta clave. Esto todavía funciona, y no estoy preocupado porque esta es una aplicación interna. Además, ya hay un título que solicita el uso de servicios de ubicación, por lo que no quería hacer nada redundante.

Luego, creé un condicional para iOS 8:

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

Después de esto, el método locationManager:didChangeAuthorizationStatus: call es:

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

Y ahora todo funciona bien. Como siempre, revisa la documentación .

Solución con compatibilidad hacia atrás:

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

Configure la clave NSLocationWhenInUseUsageDescription en su Info.plist

Solución con compatibilidad hacia atrás que no produce advertencias de 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]; } 

Configure la clave NSLocationWhenInUseUsageDescription en su Info.plist .

Para iOS versión 11.0+ : configure la clave NSLocationAlwaysAndWhenInUseUsageDescription en su Info.plist . junto con otras 2 teclas.

Este es un problema con ios 8 Agregue esto a su código

 if (IS_OS_8_OR_LATER) { [locationmanager requestWhenInUseAuthorization]; [locationmanager requestAlwaysAuthorization]; } 

y a info.plist:

  NSLocationUsageDescription I need location NSLocationAlwaysUsageDescription I need location NSLocationWhenInUseUsageDescription I need location 

Para acceder a la ubicación del usuario en iOS 8, tendrá que agregar

 NSLocationAlwaysUsageDescription in the Info.plist 

Esto le pedirá al usuario el permiso para obtener su ubicación actual.

Para aquellos que usan Xamarin , tuve que agregar la clave NSLocationWhenInUseUsageDescription a info.plist manualmente porque no estaba disponible en las listas desplegables en Xamarin 5.5.3 Build 6 o XCode 6.1 – solo NSLocationUsageDescription estaba en la lista, y eso causó el CLLocationManager para continuar fallando silenciosamente

Objetivo-C Procedimiento Siga las siguientes instrucciones:

Para iOS-11 Para iOS 11, eche un vistazo a esta respuesta: acceso a la ubicación de iOS 11

Es necesario agregar dos teclas en el plist y proporcionar el mensaje como se muestra a continuación:

  1. NSLocationAlwaysAndWhenInUseUsageDescription 2. NSLocationWhenInUseUsageDescription 3. NSLocationAlwaysUsageDescription 

enter image description here Para iOS-10 y abajo:

 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]; } 

Delegar métodos

 #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]; } 

Procedimiento Swift

Siga las siguientes instrucciones:

Para iOS-11 Para iOS 11, eche un vistazo a esta respuesta: acceso a la ubicación de iOS 11

Es necesario agregar dos teclas en el plist y proporcionar el mensaje como se muestra a continuación:

  1. NSLocationAlwaysAndWhenInUseUsageDescription 2. NSLocationWhenInUseUsageDescription 3. NSLocationAlwaysUsageDescription 

enter image description here Para iOS-10 y abajo:

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

Delegar métodos

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

Un pequeño ayudante para todos ustedes que tienen más de un archivo Info.plist …

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

Agregará la etiqueta necesaria a todos los archivos Info.plist en el directorio actual (y subcarpetas).

Otro es:

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

Agregará su descripción a todos los archivos.

Mantenga la información de Cocoa Keys siempre a su scope para esas actualizaciones, aquí está el enlace:

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

Disfrutar.

Recibo un error similar en iOS9 (trabajo con Xcode 7 y Swift 2): bash de iniciar las actualizaciones de ubicación de MapKit sin solicitar autorización de ubicación. Debe llamar primero a [CLLocationManager requestWhenInUseAuthorization] o – [CLLocationManager requestAlwaysAuthorization]. Estaba siguiendo un tutorial pero el tutor usaba iOS8 y Swift 1.2. Hay algunos cambios en Xcode 7 y Swift 2, encontré este código y funciona bien para mí (si alguien necesita ayuda):

 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) } } 

Finalmente, puse eso en info.plist: Lista de propiedades de información: NSLocationWhenInUseUsageDescription Valor: la aplicación necesita servidores de ubicación para el personal

Para acceder a la ubicación de los usuarios en iOS. Necesitas agregar dos llaves

NSLocationWhenInUseUsageDescription

NSLocationAlwaysUsageDescription

en el archivo Info.plist.

  NSLocationWhenInUseUsageDescription Because I want to know where you are! NSLocationAlwaysUsageDescription Want to know where you are! 

Vea esta imagen a continuación.

Imagen Info.plist

  1. Agregue la clave NSLocationWhenInUseUsageDescription o NSLocationAlwaysUsageDescription (uso de GPS de fondo) con una cadena que le pida que use GPS en cada info.plist de cada destino.

  2. Pida permiso ejecutando:

    [self initLocationManager: locationManager];

Donde initLocationManager es:

 // asks for GPS authorization on iOS 8 -(void) initLocationManager:(CLLocationManager *) locationManager{ locationManager = [[CLLocationManager alloc]init]; if([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) [locationManager requestAlwaysAuthorization]; } 

Recuerde que si las claves no están en cada info.plist para cada objective, la aplicación no se lo preguntará al usuario. El if proporciona compatibilidad con iOS 7 y el método respondsToSelector: garantiza la compatibilidad futura en lugar de solo resolver el problema para iOS 7 y 8.

El problema para mí fue que la clase que era CLLocationManagerDelegate era privada, lo que impedía que se CLLocationManagerDelegate todos los métodos de delegado. Supongo que no es una situación muy común, pero pensé que lo mencionaría en caso de que ayude a alguien.

Agrego esas claves en InfoPlist.strings en iOS 8.4, iPad mini 2. También funciona. No configuro ninguna clave, como NSLocationWhenInUseUsageDescription , en mi Info.plist .


InfoPlist.strings :

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

La base de este hilo , decía, as in iOS 7 , se puede localizar en InfoPlist.strings. En mi prueba, esas claves se pueden configurar directamente en el archivo InfoPlist.strings .

So the first thing you need to do is to add one or both of the > following keys to your Info.plist file:

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

Both of these keys take a string which is a description of why you need location services. You can enter a string like “Location is required to find out where you are” which, as in iOS 7 , can be localized in the InfoPlist.strings file.


ACTUALIZAR:

I think @IOS ‘s method is better. Add key to Info.plist with empty value and add localized strings to InfoPlist.strings .