objective c - que - Los servicios de localización no funcionan en iOS 8
que hace el sos del iphone (26)
Mi aplicación que funcionó bien en iOS 7 no funciona con el SDK de iOS 8.
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 surgió nada. ¿Qué podría estar mal?
Agregue la clave
NSLocationWhenInUseUsageDescription
oNSLocationAlwaysUsageDescription
(uso de GPS de fondo) con una cadena que solicita el uso de GPS en cadainfo.plist
de cada objetivo.Pida permiso ejecutando:
[self initLocationManager: locationManager];
Donde initLocationManager
esta
// 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 una info.plist
para cada objetivo, la aplicación no preguntará al usuario. El if
proporciona compatibilidad con iOS 7 y el respondsToSelector:
método garantiza la compatibilidad futura en lugar de resolver el problema para iOS 7 y 8.
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.
) 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
y
NSLocationAlwaysUsageDescription
con NSLocationWhenInUseUsageDescription
.
El código antiguo para pedir la ubicación no funcionará en iOS 8. Puedes probar este método para la 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, debe hacer dos cosas adicionales para que la ubicación funcione: agregue una clave a su lista de información y solicite autorización al administrador de la ubicación para que comience
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>
Agrega esto a tu código
if (IS_OS_8_OR_LATER)
{
[locationmanager requestWhenInUseAuthorization];
[locationmanager requestAlwaysAuthorization];
}
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 como tal:
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:
Note que no llené el valor para esta clave. Esto todavía funciona, y no me preocupa porque esta es una aplicación interna. Además, ya existe un título que solicita el uso de los 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:
es llamada:
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus: (CLAuthorizationStatus)status
{
[self gotoCurrenLocation];
}
Y ahora todo funciona bien. Como siempre, echa un vistazo a la documentation .
Este es un problema con iOS 8 Agrega esto a tu código
if (IS_OS_8_OR_LATER)
{
[locationmanager requestWhenInUseAuthorization];
[locationmanager requestAlwaysAuthorization];
}
ya 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>
Mantenga la información de Cocoa Keys siempre a su alcance para esas actualizaciones, aquí está el enlace:
Disfrutar.
Me estaba sacando el pelo con el mismo problema. Xcode te da el error:
Intentando iniciar las actualizaciones de ubicación de
MapKit
sinMapKit
autorización de ubicación. Debe llamar-[CLLocationManager requestWhenInUseAuthorization]
o-[CLLocationManager requestAlwaysAuthorization]
primero.
Pero incluso si implementa uno de los métodos anteriores, no le preguntará al usuario a menos que haya una entrada en info.plist para NSLocationAlwaysUsageDescription
o NSLocationWhenInUseUsageDescription
.
Agregue las siguientes líneas a su lista de información donde los valores de cadena representan la razón por la que necesita acceder a la ubicación de los usuarios
<key>NSLocationWhenInUseUsageDescription</key>
<string>This application requires location services to work</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This application requires location services to work</string>
Creo que estas entradas pueden haber faltado desde que inicié este proyecto en Xcode 5. Supongo que Xcode 6 podría agregar entradas predeterminadas para estas claves, pero no las he confirmado.
Puede encontrar más información sobre estas dos configuraciones here
Mi solución que se puede compilar 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];
Para acceder a la ubicación de los usuarios en iOS. Necesitas añadir dos llaves.
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
en el archivo 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>
Vea esta imagen abajo.
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, ya que no estaba disponible en los menús desplegables de Xamarin 5.5.3 Build 6 o XCode 6.1; solo NSLocationUsageDescription
estaba en la lista, y eso causó el CLLocationManager
Continuar fallando en silencio.
Para asegurarse de que esto sea compatible con iOS 7, debe verificar si el usuario está ejecutando 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];
Recibo un error similar en iOS9 (que funciona con Xcode 7 y Swift 2): al intentar iniciar las actualizaciones de ubicación de MapKit sin pedir autorización de ubicación. Debe llamar - [CLLocationManager requestWhenInUseAuthorization] o - [CLLocationManager requestAlwaysAuthorization] primero. Estaba siguiendo un tutorial pero el tutor estaba usando 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
Según los documentos de Apple:
- https://developer.apple.com/documentation/corelocation/requesting_permission_to_use_location_services
- https://developer.apple.com/documentation/corelocation/cllocationmanager/1620562-requestwheninuseauthorization
A partir de iOS 8, se requiere la presencia de un valor clave NSLocationWhenInUseUsageDescription
o NSLocationAlwaysUsageDescription
en el archivo Info.plist de su aplicación. También es necesario solicitar permiso del usuario antes de registrarse para [self.myLocationManager requestWhenInUseAuthorization]
actualizaciones de ubicación, ya sea llamando a [self.myLocationManager requestWhenInUseAuthorization]
o [self.myLocationManager requestAlwaysAuthorization]
según sus necesidades. La cadena que ingresó en la lista de información se mostrará en el cuadro de diálogo que sigue.
Si el usuario concede permiso, es el negocio habitual. Si niegan el permiso, entonces el delegado no está informado de las actualizaciones de ubicación.
Solución con compatibilidad con versiones anteriores 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 la versión 11.0+ de iOS : configure la clave NSLocationAlwaysAndWhenInUseUsageDescription
en su Info.plist
. junto con otras 2 llaves.
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
Terminé resolviendo mi propio problema.
Aparentemente, en el SDK de iOS 8, la requestAlwaysAuthorization
(para la ubicación en segundo plano) o la requestWhenInUseAuthorization
(la ubicación solo cuando está en primer plano) es necesaria en CLLocationManager
antes de iniciar 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 indicador. Añadiendo estos resuelto mi problema.
Espero que ayude a alguien más.
EDITAR: Para obtener información más extensa, eche un vistazo a: nevan.net/2014/09/core-location-manager-changes-in-ios-8
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.
Procedimiento de Objective-C Siga las instrucciones a continuación:
Para iOS-11 Para iOS 11, eche un vistazo a esta Respuesta: acceso a la ubicación de iOS 11
Debe agregar dos claves a la lista y enviar un mensaje como se muestra en la siguiente imagen:
1. NSLocationAlwaysAndWhenInUseUsageDescription
2. NSLocationWhenInUseUsageDescription
3. NSLocationAlwaysUsageDescription
NSLocationWhenInUseUsageDescription
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
if([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]){
[locationManager requestWhenInUseAuthorization];
}else{
[locationManager startUpdatingLocation];
}
Métodos de Delegado
#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 rápido
Siga las instrucciones a continuación:
Para iOS-11 Para iOS 11, eche un vistazo a esta Respuesta: acceso a la ubicación de iOS 11
Debe agregar dos claves a la lista y enviar un mensaje como se muestra en la siguiente imagen:
1. NSLocationAlwaysAndWhenInUseUsageDescription
2. NSLocationWhenInUseUsageDescription
3. NSLocationAlwaysUsageDescription
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()
}
}
Métodos de Delegado
//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
}
Un error común para los desarrolladores de Swift:
Primero asegúrese de agregar un valor a la lista para NSLocationWhenInUseUsageDescription
o NSLocationAlwaysUsageDescription
.
Si aún no ve una ventana emergente que solicita autorización, vea si está colocando la línea var locationManager = CLLocationManager()
en el método viewDidLoad
su controlador de viewDidLoad
. Si lo haces, incluso si llamas a locationManager.requestWhenInUseAuthorization()
, no aparecerá nada. Esto se debe a que después de que se ejecuta viewDidLoad, la variable locationManager se desasigna (se borra).
La solución es ubicar la línea var locationManager = CLLocationManager()
en la parte superior del método de clase.
Añado clave en los que InfoPlist.strings
en iOS 8.4, mini iPad 2. Funciona también. No pongo ninguna tecla, como NSLocationWhenInUseUsageDescription
, en mi Info.plist
.
InfoPlist.strings :
"NSLocationWhenInUseUsageDescription" = "I need GPS information....";
nevan.net/2014/09/core-location-manager-changes-in-ios-8 , dijo as in iOS 7
, se puede localizar en las InfoPlist.strings. En mi prueba, esas claves se pueden configurar directamente en el archivo InfoPlist.strings
.
Entonces, lo primero que debe hacer es agregar una o las dos claves siguientes a su archivo Info.plist:
- NSLocationWhenInUseUsageDescription
- NSLocationAlwaysUsageDescription
Ambas claves toman una cadena que es una descripción de por qué necesita servicios de ubicación. Puede ingresar una cadena como "Se requiere ubicación para saber dónde se encuentra" que, como en iOS 7 , se puede localizar en el archivo InfoPlist.strings.
ACTUALIZAR:
Creo que @IOS
el método es mejor. Agregar clave a Info.plist
con valor vacío y agregar cadenas localizadas a InfoPlist.strings
.
El problema para mí fue que la clase que era la clase CLLocationManagerDelegate
era privada, lo que evitó que se llamara a 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.
// ** 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]);
}
- (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
- (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 lista de información y solicite autorización al administrador de la 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 (ya que nunca se inició, no puede fallar). También fallará si agrega una o las dos claves pero se olvida de solicitar explícitamente la autorización. Entonces, lo primero que debe hacer es agregar una o las dos claves siguientes a su archivo Info.plist:
- NSLocationWhenInUseUsageDescription
- NSLocationAlwaysUsageDescription
Ambas claves toman una cuerda
que es una descripción de por qué necesita servicios de ubicación. Puede ingresar una cadena como "Se requiere ubicación para saber dónde se encuentra" que, como en iOS 7, se puede localizar en el archivo InfoPlist.strings.