I servizi di localizzazione non funzionano in iOS 8


608

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

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


Puoi anche utilizzarlo come app di riferimento per la soluzione github.com/jbanford/ConstantLocationUpdates
ashok vadivelu,

19
Ho pubblicato alcune modifiche al gestore della posizione in iOS 8 qui: nevan.net/2014/09/core-location-manager-changes-in-ios-8
nevan king

2
Potresti provare a utilizzare questa libreria che semplifica le API della posizione principale ed espone una bella interfaccia basata su blocchi e normalizza tutte le differenze tra le diverse versioni di iOS (Informativa completa: sono l'autore): github.com/lmirosevic/GBLocation
lms

Ho trovato alcuni riferimenti qui datacalculation.blogspot.in/2014/11/…
Test iOS

2
@nevanking Signore! ho bisogno di una corona! Ho combattuto con questo problema dal cambiamento e non ho ancora trovato una "guida" su come risolverlo, che era amichevole per nessuno. La tua guida ha fatto un idiota come me, gestendo il problema da solo. Grazie mille per quel link.
Patrick R

Risposte:


1086

Ho finito per risolvere il mio problema.

Apparentemente in iOS 8 SDK, requestAlwaysAuthorization(per la posizione in background) o requestWhenInUseAuthorization(posizione solo in primo piano) CLLocationManagerè necessario chiamare prima di iniziare gli aggiornamenti della posizione.

È inoltre necessario essere NSLocationAlwaysUsageDescriptiono NSLocationWhenInUseUsageDescriptiondigitare Info.plistun messaggio da visualizzare nel prompt. L'aggiunta di questi ha risolto il mio problema.

inserisci qui la descrizione dell'immagine

Spero che aiuti qualcun altro.

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


6
puoi condividere il valore esatto aggiornato in Info.plist? Non riesco a vedere quella chiave nel mio Info.plist. L'ho aggiunto e ancora non sembra funzionare. Sto usando Swift, iOS8 e XCode 6 beta 4
Vijay Kumar AB

4
@Vjay - devi modificare il file Info.plist in un editor, non puoi impostare quelle chiavi in ​​Xcode (dalla beta 6).
Kendall Helmstetter Gelner,

11
Solo un promemoria, se non vuoi mostrare una spiegazione personalizzata all'utente, imposta questa chiave su una stringa vuota.
lucido

7
Devi conservare il tuo locationManager per farlo funzionare. quindi rendi il tuo CLLocationManager una proprietà forte
Vassily,

273
ADORO che non si ottengano errori, avvisi, messaggi di registro, NIENTE se si lascia fuori la voce di plist. Fondamentalmente Apple ha creato una chiamata API che non ha NULLA se non si dispone della voce plist appropriata. Grazie a @OrtwinGentz ​​per averlo capito.
MobileVet,

314

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

Tentativo di avviare gli MapKitaggiornamenti della posizione senza richiedere l'autorizzazione della posizione. Deve chiamare -[CLLocationManager requestWhenInUseAuthorization]o -[CLLocationManager requestAlwaysAuthorization]prima.

Ma anche se si implementa uno dei metodi di cui sopra, non verrà richiesto all'utente a meno che non sia presente una voce in info.plist per NSLocationAlwaysUsageDescriptiono NSLocationWhenInUseUsageDescription.

Aggiungi le seguenti righe al tuo info.plist dove i valori di stringa rappresentano il motivo per cui devi accedere alla posizione degli utenti

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

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

Penso che queste voci potrebbero essere mancate da quando ho iniziato questo progetto in Xcode 5. Immagino che Xcode 6 potrebbe aggiungere voci predefinite per queste chiavi ma non ho confermato.

Puoi trovare ulteriori informazioni su queste due impostazioni qui


13
xcode 6 non aggiunge queste chiavi per impostazione predefinita, se si intende implementare CLLocationManager è necessario aggiungerle manualmente
Wesley Smith

1
Ho anche dovuto aggiungere questi manualmente, non è stato possibile aggiungere tramite la vista RawValues ​​di info.plist in Xcode6!
Kendall Helmstetter Gelner,

1
ho cercato per sempre questo. Il mio messaggio [CLLLocationManager autorizzazioniStatus] restituiva solo un valore di <nil>. Dopo aver aggiunto le chiavi precedenti, ha iniziato a restituire le rispettive enumerazioni per l'output dei messaggi. Da quello che ho scoperto questo è un bug noto di iOS 8 ma non sono riuscito a trovare nulla nel mio contesto per anni. Grazie mille!
MrOli3000,

4
Mi piace il valore della stringa che hai inserito
Chris Chen,

1
Il messaggio verrà visualizzato come messaggio secondario nell'avviso che chiede se l'utente desidera condividere la propria posizione. In quanto tale, essere semplicemente vuoto (vuoto) sembra avere più senso nella mia applicazione. Una spiegazione del perché si desidera utilizzare la posizione avrebbe anche senso. Tuttavia, NSLocationWhenInUseUsageDescription non si è comportato come previsto per me (vale a dire che continuava a ottenere l'autorizzazione negata, anche se il valore restituito era corretto). NSLocationAlwaysUsageDescription ha funzionato bene.
arcady bob,

104

Per assicurarsi che sia compatibile con le versioni precedenti di iOS 7, è necessario verificare se l'utente esegue 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];

164
Un modo migliore di controllare la versione è verificare se l'oggetto ha quel selettore, ad esempio: if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { ...
progrmr

1
Ho avuto problemi a implementare la soluzione di @ progrmr quando si basava su Xcode 5, dal momento che non sa quale sia il requestAlwaysAuthorizationmetodo. La mia soluzione aggiuntiva era di usare questa linea nella ifdichiarazione invece di una normale chiamata di metodo: [self.locationManager performSelector:@selector(requestAlwaysAuthorization)];. Forse questo è ovvio per le altre persone, ma mi ci è voluto un po 'di tempo per capire. Penso che sia la soluzione giusta fino al rilascio dell'Xcode 6 finale.
VinceFior,

2
La soluzione giusta è compilare con Xcode 6. Se stai compilando con Xcode 5 non è necessario richiedere l'autorizzazione, è automatico.
progr

Potresti avere un punto. La mia preoccupazione era che volessi compilare il mio codice in Xcode 5 (anche se non funzionerà su iOS 8 se non compilato in Xcode 6) mentre il mio team passa a Xcode 6. Ma forse è un flusso di lavoro migliore per scrivere il codice normalmente e non unirlo finché non passiamo a Xcode 6 .. Grazie.
VinceFior,

@VinceFior l'approccio raccomandato è di compilare in modo condizionale usando la macro definita SDK __IPHONE_OS_VERSION_MAX_ALLOWED( #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000)
Steven Kramer

50
- (void)startLocationManager
{
    locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;
    locationManager.distanceFilter = kCLDistanceFilterNone; //whenever we move
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;

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


}

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


1
Trovata una soluzione simile in modo più descrittivo su datacalculation.blogspot.in/2014/11/…
Test iOS

2
@Hemang: secondo la documentazione di Apple Dev: è sicuro avviare i servizi di localizzazione prima di determinare lo stato di autorizzazione dell'app. Sebbene sia possibile avviare i servizi di localizzazione, tali servizi non forniscono alcun dato fino a quando lo stato dell'autorizzazione non cambia in kCLAuthorizationStatusAuthorizedAlways o kCLAuthorizationStatusAuthorizedWhenInUse.
Andrew,

Un po 'tardi, ma ti consiglio di nascondere parti irrilevanti del tuo file plist, in particolare FacebookAppID
Przemysław Wrzesiński

Grazie Ma questo è solo un esempio fittizio :)
neo D1

È anche importante che il progetto punti al giusto info.plist (quello in cui è definita la chiave). Ciò è determinato nelle impostazioni di compilazione del progetto in File Info.plist.
Clearlight il

30

Secondo i documenti di Apple:

A partire da iOS 8, è richiesta la presenza di un NSLocationWhenInUseUsageDescriptiono un NSLocationAlwaysUsageDescriptionvalore chiave nel file Info.plist della tua app. È inoltre necessario richiedere l'autorizzazione all'utente prima di registrarsi per gli aggiornamenti della posizione, chiamando [self.myLocationManager requestWhenInUseAuthorization]o in [self.myLocationManager requestAlwaysAuthorization]base alle proprie esigenze. La stringa immessa in Info.plist verrà quindi visualizzata nella finestra di dialogo che segue.

Se l'utente concede l'autorizzazione, è come al solito. Se negano l'autorizzazione, il delegato non viene informato degli aggiornamenti della posizione.


Ho trovato una semplice descrizione qui su datacalculation.blogspot.in/2014/11/…
Test iOS

28
- (void)viewDidLoad
{

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

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

>  #pragma mark - CLLocationManagerDelegate

    - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
    {
        NSLog(@"didFailWithError: %@", error);
        UIAlertView *errorAlert = [[UIAlertView alloc]
                                   initWithTitle:@"Error" message:@"Failed to Get Your Location" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [errorAlert show];
    }

    - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
    {
        NSLog(@"didUpdateToLocation: %@", newLocation);
        CLLocation *currentLocation = newLocation;

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

In iOS 8 devi fare due cose extra per far funzionare la posizione: aggiungi una chiave al tuo Info.plist e richiedi l'autorizzazione al gestore della posizione chiedendogli di avviarla. Esistono due chiavi Info.plist per la nuova autorizzazione di posizione. È richiesta una o entrambe queste chiavi. Se nessuna delle chiavi è presente, è possibile chiamare startUpdatingLocation ma il gestore della posizione non si avvierà effettivamente. Non invierà nemmeno un messaggio di errore al delegato (poiché non è mai stato avviato, non può non riuscire). Non funzionerà anche se aggiungi una o entrambe le chiavi ma dimentichi di richiedere esplicitamente l'autorizzazione. Quindi la prima cosa che devi fare è aggiungere una o entrambe le seguenti chiavi al tuo file Info.plist:

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

Entrambe queste chiavi prendono una stringa

che è una descrizione del motivo per cui hai bisogno dei servizi di localizzazione. Puoi inserire una stringa come "Posizione richiesta per scoprire dove ti trovi" che, come in iOS 7, può essere localizzata nel file InfoPlist.strings.

inserisci qui la descrizione dell'immagine


19

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

2
Bella soluzione dinamica, da utilizzare in tutte le app. Vorrei modificare l'ordine però e invece di controllare per iPhone 8.0, vorrei verificare se il gestore della posizione risponde all'autorizzazione e quindi eseguire lo stato di autorizzazione per ottenere il codice. Questo lo renderà più universale.
zirinisp,

Ha funzionato anche su xCode 7.2.
Totoro,

17

Il vecchio codice per chiedere la posizione non funzionerà in iOS 8. Puoi provare questo metodo per l'autorizzazione 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];
    }
}

UIAlertView è stato deprecato. Si dovrebbe usare UIAlertController invece.
Pasan Premaratne,

Sì, lo so che è deprecato, ma funzionerà anche. ma sì, meglio usare UIAlertController per IOS8.
Nits007ak,

12

In iOS 8 devi fare due cose extra per far funzionare la posizione: aggiungi una chiave al tuo Info.plist e richiedi l'autorizzazione dal gestore della posizione chiedendogli di iniziare

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>

Aggiungi questo al tuo codice

if (IS_OS_8_OR_LATER)
{
    [locationmanager requestWhenInUseAuthorization];

    [locationmanager requestAlwaysAuthorization];
}

1
non è chiaro se il tuo pseudocodice è una chiamata preprocessore o una chiamata normale
El Dude,

1
Aggiungi questo al tuo file constants.h o .pch: #define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] .systemVersion floatValue]> = 8.0)
OxenBoxen,

Perché dovresti richiedere entrambi, dovresti aggiungere un commento menzionando solo di usare l'uno o l'altro a seconda delle esigenze della tua applicazione
powerj1984,

la parte info.plist è abbastanza facile da fare in Unity3d, ma come aggiungerei la parte di codice se utilizzassi unity3d? dove ?
CthulhuJon

11

Un errore comune per gli sviluppatori Swift:

Innanzitutto assicurati di aggiungere un valore al plist per uno NSLocationWhenInUseUsageDescriptiono NSLocationAlwaysUsageDescription.

Se non stai ancora visualizzando una finestra che richiede l'autorizzazione, cerca di inserire la linea var locationManager = CLLocationManager()nel viewDidLoadmetodo del tuo controller di visualizzazione . Se lo fai, quindi 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 classe.


9

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

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

Modifica la tua app Info.pliste aggiungi la chiave NSLocationAlwaysUsageDescriptioncon il valore di stringa che verrà visualizzato all'utente (ad esempio We do our best to preserve your battery life.)

Se la tua app necessita di servizi di localizzazione solo mentre è aperta, sostituisci:

requestAlwaysAuthorizationcon requestWhenInUseAuthorizatione

NSLocationAlwaysUsageDescriptioncon NSLocationWhenInUseUsageDescription.


9

Stavo lavorando su un'app che è stata aggiornata a iOS 8 e i servizi di localizzazione hanno smesso di funzionare. Probabilmente avrai un errore nell'area di 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 invadente. Per prima cosa aggiungi la NSLocationAlwaysUsageDescriptionvoce al tuo info.plist:

Inserisci qui la descrizione dell'immagine

Si noti che non ho compilato il valore per questa chiave. Funziona ancora e non mi preoccupo perché si tratta di un'app interna. Inoltre, esiste già un titolo che chiede di utilizzare 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 è chiamato:

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

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


7

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 la chiave NSLocationWhenInUseUsageDescription in Info.plist


2
Questo non è corretto, che dire del caso kCLAuthorizationStatusDenied? salta ad altro e inizia ad aggiornare la posizione che non è corretta!
electronix384128,

@BenMarten Non penso che dovrebbe importare. Dovresti gestirlo da solo locationManager: (CLLocationManager *)manager didFailWithError: (NSError *)error. Tuttavia, ha dimenticato di aggiungere startUpdatingLocation all'istruzione if, quindi dopo averlo accettato o negato, in realtà non chiama startUpdateLocation.
Chris,

6

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

NSLocationWhenInUseUsageDescriptionChiave di installazione nel tuo Info.plist.

Per iOS versione 11.0+ : NSLocationAlwaysAndWhenInUseUsageDescriptionchiave di installazione nel tuo Info.plist. insieme ad altri 2 tasti.


Questo non è corretto, che dire del caso kCLAuthorizationStatusDenied? salta ad altro e inizia ad aggiornare la posizione che non è corretta!
electronix384128,

Questo è abbastanza strano, questo funziona bene per me non va bene perfettamente sia con permetti che con non permessi. Anche la soluzione Jacob sembra accurata ma non ha funzionato per me. Strano ma ha funzionato !!!
Josh,

Chiamare [self.locationManager startUpdatingLocation] subito dopo la richiestaWhenInUseAuthorization non ha senso
Kostia Kim

5

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:

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

NSLocationUsageDescriptionnon viene utilizzato su iOS8 +
Carlos Ricardo il

4

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

NSLocationAlwaysUsageDescription in the Info.plist 

Ciò richiederà all'utente l'autorizzazione per ottenere la posizione corrente.


4

Procedura Obiettivo-C Seguire le istruzioni seguenti:

Per iOS-11 Per iOS 11 dai un'occhiata a questa risposta:accesso alla posizione di iOS 11

È necessario aggiungere due chiavi in ​​plist e fornire il messaggio come sotto l'immagine:

 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription
 3. NSLocationAlwaysUsageDescription

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

NSLocationWhenInUseUsageDescription

inserisci qui la descrizione dell'immagine

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

Seguire le istruzioni seguenti:

Per iOS-11 Per iOS 11 dai un'occhiata a questa risposta: accesso alla posizione di iOS 11

È necessario aggiungere due chiavi in ​​plist e fornire il messaggio come sotto l'immagine:

 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription
 3. NSLocationAlwaysUsageDescription

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

inserisci qui la descrizione dell'immagine

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

}

Assicurati di aggiungere anche NSLocationAlwaysUsageDescription, altrimenti visualizzerai un errore durante il caricamento su App Store.
Alok,

Il tuo messaggio dovrebbe anche essere informativo altrimenti Apple rifiuterà l'app durante il processo di reviwing.
Alok,

3

Per quelli che usano Xamarin , ho dovuto aggiungere la chiave NSLocationWhenInUseUsageDescriptiona info.plist manualmente poiché non era disponibile nei menu a discesa in Xamarin 5.5.3 Build 6 o XCode 6.1 - NSLocationUsageDescriptionera solo nell'elenco e ciò ha causato il CLLocationManagerproseguimento del fallire in silenzio.


2
        // ** Don't forget to add NSLocationWhenInUseUsageDescription in MyApp-Info.plist and give it a string

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


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

}

2

Un piccolo aiuto per tutti voi che avete 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.



2

Ottengo un errore simile in iOS9 (lavorando con Xcode 7 e Swift 2): sto tentando di avviare gli aggiornamenti della posizione di MapKit senza richiedere l'autorizzazione della posizione. Deve chiamare prima [CLLocationManager requestWhenInUseAuthorization] o - [CLLocationManager requestAlwaysAuthorization]. Stavo seguendo un tutorial ma il tutor stava usando iOS8 e Swift 1.2. Ci sono alcune modifiche 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, lo inserisco in info.plist: Elenco proprietà informazioni: NSLocationWhenInUseUsageDescription Valore: l' app richiede server di localizzazione per il personale


2

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

NSLocationWhenInUseUsageDescription

NSLocationAlwaysUsageDescription

nel file 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>

Vedi questa immagine sotto.

Immagine info.plist


1
  1. Aggiungi chiave NSLocationWhenInUseUsageDescriptiono NSLocationAlwaysUsageDescription(uso GPS in background) con una stringa che chiede di utilizzare il GPS su ciascuno info.plistdi ciascun target.

  2. Chiedi l'autorizzazione 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 ciascuna info.plistper ogni target l'app non chiederà all'utente. Il iffornisce la compatibilità con iOS 7 e il respondsToSelector:metodo garantisce la compatibilità futura e non solo risolvere il problema per iOS 7 e 8.


0

Il problema per me era che la classe che era CLLocationManagerDelegateera privata, il che impediva di chiamare tutti i metodi delegati. Immagino che non sia una situazione molto comune, ma ho pensato di menzionarlo nel caso t aiuti qualcuno.


0

Aggiungo quelli chiave InfoPlist.stringsdi iOS 8.4, mini iPad 2. Funziona anche. Non inserisco alcuna chiave, tipo NSLocationWhenInUseUsageDescription, nel mio Info.plist.


InfoPlist.strings :

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

Base su questo thread , ha detto as in iOS 7, può essere localizzato in InfoPlist.strings. Nel mio test, quelle chiavi possono essere configurate direttamente nel file InfoPlist.strings.

Quindi la prima cosa che devi fare è aggiungere una o entrambe le seguenti> chiavi al tuo file Info.plist:

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

Entrambe queste chiavi prendono una stringa che è una descrizione del motivo per cui hai bisogno dei servizi di localizzazione. Puoi inserire una stringa come "Posizione richiesta per scoprire dove ti trovi" che, come in iOS 7 , può essere localizzata nel file InfoPlist.strings.


AGGIORNARE:

Penso che @IOSil metodo sia migliore. Aggiungi chiave a Info.plistcon valore vuoto e aggiungi stringhe localizzate a InfoPlist.strings.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.