I servizi di localizzazione non funzionano su iOS 8

La mia app che ha funzionato bene su iOS 7 non funziona con l’SDK di iOS 8.

CLLocationManager non restituisce una posizione e non vedo la mia app in Impostazioni -> Servizi di localizzazione . Ho effettuato una ricerca su Google sul problema, ma non è venuto fuori nulla. Cosa potrebbe esserci di sbagliato?

Ho finito per risolvere il mio problema.

Apparentemente in iOS 8 SDK, è richiesta la richiesta requestAlwaysAuthorization (per il percorso in background) o requestWhenInUseAuthorization (location only when foreground) su CLLocationManager prima di avviare gli aggiornamenti della posizione.

Inoltre, deve essere NSLocationAlwaysUsageDescription chiave NSLocationAlwaysUsageDescription o NSLocationWhenInUseUsageDescription in Info.plist con un messaggio da visualizzare nel prompt. Aggiungendo questi ho risolto il mio problema.

inserisci la descrizione dell'immagine qui

Spero che aiuti qualcun altro.

EDIT: per informazioni più dettagliate, dare un’occhiata a: Core-Location-Manager-Changes-in-ios-8

Mi stavo strappando i capelli con lo stesso problema. Xcode ti dà l’errore:

Cercando di avviare MapKit aggiornamenti della posizione di MapKit senza chiedere l’authorization della posizione. Deve chiamare per prima cosa -[CLLocationManager requestWhenInUseAuthorization] o -[CLLocationManager requestAlwaysAuthorization] .

Ma anche se si implementa uno dei metodi precedenti, non verrà richiesto all’utente a meno che non ci sia una voce in info.plist per NSLocationAlwaysUsageDescription o NSLocationWhenInUseUsageDescription .

Aggiungi le seguenti linee al tuo info.plist dove i valori della stringa rappresentano il motivo per cui hai bisogno di accedere alla posizione degli utenti

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

Penso che queste voci potrebbero essersi perse da quando ho avviato questo progetto in Xcode 5. Suppongo che Xcode 6 possa aggiungere voci predefinite per queste chiavi ma non aver confermato.

Puoi trovare ulteriori informazioni su queste due impostazioni qui

Per garantire che questo sia retrocompatibile con iOS 7, dovresti controllare se l’utente sta usando iOS 8 o iOS 7. Ad esempio:

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

E al tuo file info.plist inserisci la descrizione dell'immagine qui

Secondo i documenti Apple:

A partire da iOS 8, è richiesta la presenza di un valore di chiave NSLocationWhenInUseUsageDescription o NSLocationAlwaysUsageDescription nel file Info.plist dell’app. È inoltre necessario richiedere l’authorization dell’utente prima di effettuare la registrazione per gli aggiornamenti di posizione, chiamando [self.myLocationManager requestWhenInUseAuthorization] o [self.myLocationManager requestAlwaysAuthorization] base alle proprie esigenze. La stringa inserita in Info.plist verrà quindi visualizzata nella finestra di dialogo seguente.

Se l’utente concede l’authorization, è come al solito. Se negano l’authorization, il delegato non viene informato degli aggiornamenti di posizione.

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

In iOS 8 devi fare due cose in più per far funzionare la posizione: aggiungi una chiave al tuo Info.plist e richiedi l’authorization al gestore di posizione per chiedergli di iniziare. Esistono due chiavi Info.plist per la nuova authorization di posizione. È necessaria una o entrambe queste chiavi. Se nessuna delle chiavi è presente, è ansible chiamare startUpdatingLocation ma il gestore della posizione non verrà effettivamente avviato. Non invierà neanche un messaggio di errore al delegato (poiché non è mai iniziato, non può fallire). Fallirà anche se aggiungi una o entrambe le chiavi ma dimentichi di richiedere esplicitamente l’authorization. Quindi la prima cosa che devi fare è aggiungere uno o entrambi i seguenti tasti al tuo file Info.plist:

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

Entrambi questi tasti accettano una stringa

che è una descrizione del motivo per cui hai bisogno di servizi di localizzazione. Puoi inserire una stringa come “La posizione è necessaria per scoprire dove sei” che, come in iOS 7, può essere localizzata nel file InfoPlist.strings.

inserisci la descrizione dell'immagine qui

La mia soluzione che può essere compilata in 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]; 

Il vecchio codice per chiedere la posizione non funzionerà in iOS 8. Puoi provare questo metodo per l’authorization della posizione:

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

In iOS 8 devi fare due cose in più per far funzionare la posizione: aggiungi una chiave al tuo Info.plist e richiedi l’authorization al gestore di posizione per chiedergli di iniziare

info.plist:

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

Aggiungi questo al tuo codice

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

Un errore comune per gli sviluppatori Swift:

Innanzitutto assicurati di aggiungere un valore al plist per NSLocationWhenInUseUsageDescription o NSLocationAlwaysUsageDescription .

Se non visualizzi ancora una finestra che richiede l’authorization, controlla se stai inserendo la riga var locationManager = CLLocationManager() nel metodo viewDidLoad View Controller. Se lo fai, anche se chiami locationManager.requestWhenInUseAuthorization() , non verrà visualizzato nulla. Questo perché dopo l’esecuzione di viewDidLoad, la variabile locationManager viene deallocata (cancellata).

La soluzione è individuare la riga var locationManager = CLLocationManager() nella parte superiore del metodo di class.

Prima di [locationManager startUpdatingLocation]; , aggiungi una richiesta di servizi di localizzazione iOS8:

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

Modifica l’ Info.plist di app e aggiungi la chiave NSLocationAlwaysUsageDescription con il valore di stringa che verrà visualizzato all’utente (ad esempio, We do our best to preserve your battery life. )

Se la tua app richiede servizi di localizzazione solo mentre l’app è aperta, sostituisci:

requestAlwaysAuthorization with requestWhenInUseAuthorization e

NSLocationAlwaysUsageDescription con NSLocationWhenInUseUsageDescription .

Stavo lavorando su un’app che è stata aggiornata a iOS 8 e i servizi di localizzazione hanno smesso di funzionare. Probabilmente otterrai ed errore nell’area Debug in questo modo:

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

Ho fatto la procedura meno intrusiva. Per prima cosa aggiungi la voce NSLocationAlwaysUsageDescription al tuo info.plist:

Inserisci qui la descrizione dell'immagine

Avviso Non ho compilato il valore per questa chiave. Funziona ancora, e non mi interessa perché questa è un’app interna. Inoltre, c’è già un titolo che chiede di usare i servizi di localizzazione, quindi non volevo fare nulla di ridondante.

Successivamente ho creato un condizionale per iOS 8:

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

Dopo questo il locationManager:didChangeAuthorizationStatus: metodo è call:

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

E ora tutto funziona bene. Come sempre, controlla la documentazione .

Soluzione con retrocompatibilità:

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

Imposta NSLocationWhenInUseUsageDescription nella tua Info.plist

Soluzione con retrocompatibilità che non genera avvisi 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]; } 

Imposta NSLocationWhenInUseUsageDescription nella tua Info.plist .

Per iOS versione 11.0+ : Imposta NSLocationAlwaysAndWhenInUseUsageDescription nel tuo Info.plist . insieme ad altri 2 tasti.

Questo è un problema con iOS 8 Aggiungi questo al tuo codice

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

e per info.plist:

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

Per accedere alla posizione dell’utente in iOS 8 dovrai aggiungere,

 NSLocationAlwaysUsageDescription in the Info.plist 

Questo chiederà all’utente il permesso di ottenere la loro posizione corrente.

Per coloro che utilizzano Xamarin , ho dovuto aggiungere manualmente la chiave NSLocationWhenInUseUsageDescription a info.plist poiché non era disponibile nei menu a discesa in Xamarin 5.5.3 Build 6 o XCode 6.1 – solo NSLocationUsageDescription era presente nell’elenco e che ha causato CLLocationManager continuare a fallire silenziosamente.

Procedura Objective-C Seguire le seguenti istruzioni:

Per iOS-11 Per iOS 11 dare un’occhiata a questa risposta: iOS 11 accesso alla posizione

È necessario aggiungere due chiavi in ​​plist e fornire un messaggio come sotto immagine:

  1. NSLocationAlwaysAndWhenInUseUsageDescription 2. NSLocationWhenInUseUsageDescription 3. NSLocationAlwaysUsageDescription 

inserisci la descrizione dell'immagine qui Per iOS-10 e versioni successive:

 NSLocationWhenInUseUsageDescription 

inserisci la descrizione dell'immagine qui

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

Metodi delegati

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

Procedura rapida

Segui le seguenti istruzioni:

Per iOS-11 Per iOS 11 dare un’occhiata a questa risposta: iOS 11 accesso alla posizione

È necessario aggiungere due chiavi in ​​plist e fornire un messaggio come sotto immagine:

  1. NSLocationAlwaysAndWhenInUseUsageDescription 2. NSLocationWhenInUseUsageDescription 3. NSLocationAlwaysUsageDescription 

inserisci la descrizione dell'immagine qui Per iOS-10 e versioni successive:

inserisci la descrizione dell'immagine qui

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

Metodi delegati

 //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 piccolo aiuto per tutti quelli che hanno più di un file Info.plist …

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

Aggiungerà il tag necessario a tutti i file Info.plist nella directory corrente (e nelle sottocartelle).

Un altro è:

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

Aggiungerà la tua descrizione a tutti i file.

Tieni le informazioni di Cocoa Keys sempre a portata di mano per gli aggiornamenti, ecco il link:

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

Godere.

Ottengo un errore simile in iOS9 (lavorando con Xcode 7 e Swift 2): cercando di avviare gli aggiornamenti di posizione di MapKit senza chiedere l’authorization della posizione. Deve chiamare per prima cosa [richiesta CLLocationManagerWhenInUseAuthorization] o [RequestAlwaysAuthorization [CLLocationManager]]. Stavo seguendo un tutorial ma il tutor stava usando iOS8 e Swift 1.2. Ci sono alcuni cambiamenti in Xcode 7 e Swift 2, ho trovato questo codice e funziona bene per me (se qualcuno ha bisogno di aiuto):

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

Infine, l’ho messo in Info.plist: Elenco proprietà informazioni: NSLocationWhenInUseUsageDescription Value: l’ app richiede server di localizzazione per il personale

Per accedere alla posizione degli utenti in iOS. Devi aggiungere due chiavi

NSLocationWhenInUseUsageDescription

NSLocationAlwaysUsageDescription

nel file Info.plist.

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

Vedi questa immagine qui sotto.

Info.plista immagine

  1. Aggiungi chiave NSLocationWhenInUseUsageDescription o NSLocationAlwaysUsageDescription (uso GPS in background) con stringa chiedendo di utilizzare il GPS su ogni info.plist da ciascun target.

  2. Richiedi il permesso eseguendo:

    [self initLocationManager: locationManager];

Dove initLocationManager è:

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

Ricorda che se le chiavi non sono su ogni info.plist per ogni target, l’app non chiederà all’utente. if fornisce compatibilità con iOS 7 e respondsToSelector: metodo garantisce la compatibilità futura piuttosto che risolvere il problema per iOS 7 e 8.

Il problema per me era che la class che era CLLocationManagerDelegate era privata, il che impediva di chiamare tutti i metodi delegati. Guess it’s not a very common situation but thought I’d mention it in case t helps anyone.

I add those key in InfoPlist.strings in iOS 8.4, iPad mini 2. It works too. I don’t set any key, like NSLocationWhenInUseUsageDescription , in my Info.plist .


InfoPlist.strings :

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

Base on this thread , it said, as in iOS 7 , can be localized in the InfoPlist.strings. In my test, those keys can be configured directly in the file 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.


AGGIORNARE:

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