Os Serviços de Localização não funcionam no iOS 8

608

Meu aplicativo que funcionou bem no iOS 7 não funciona com o SDK do iOS 8.

CLLocationManagernão retorna um local e também não vejo meu aplicativo em Configurações -> Serviços de localização . Eu fiz uma pesquisa no Google sobre o assunto, mas nada aconteceu. O que pode estar errado?

özg
fonte
Você também pode usar isso como aplicativo de referência para a solução github.com/jbanford/ConstantLocationUpdates
ashok Vadivelu
19
Eu postei sobre algumas das alterações para a locação no iOS 8 aqui: nevan.net/2014/09/core-location-manager-changes-in-ios-8
rei Nevan
2
Você pode tentar usar esta biblioteca que simplifica as APIs de localização central e expõe uma boa interface baseada em blocos e normaliza todas as diferenças entre as diferentes versões do iOS (divulgação completa: sou o autor): github.com/lmirosevic/GBLocation
lms
Encontrei alguma referência aqui datacalculation.blogspot.in/2014/11/…
Teste do iOS
2
@nevanking Você senhor! preciso de uma coroa! Eu tenho lutado com esse problema desde a mudança e ainda não encontrei um "guia" para consertá-lo, que fosse noob amigável. Seu guia fez um idiota como eu, lida com o problema sozinho. Muito obrigado por esse link.
Patrick R

Respostas:

1086

Acabei resolvendo meu próprio problema.

Aparentemente, no iOS 8 SDK, requestAlwaysAuthorization(para localização em segundo plano) ou requestWhenInUseAuthorization(localização somente em primeiro plano), ligueCLLocationManager é necessária a antes de iniciar as atualizações de localização.

Também precisa haver NSLocationAlwaysUsageDescriptionou NSLocationWhenInUseUsageDescriptiondigitar Info.plistuma mensagem a ser exibida no prompt. Adicionando estes resolveu o meu problema.

enter image description here

Espero que isso ajude mais alguém.

EDIT: Para obter informações mais abrangentes, consulte: Core-Location-Manager-Changes-in-ios-8

özg
fonte
6
você pode compartilhar o valor exato atualizado no Info.plist? Não estou conseguindo ver essa chave no meu Info.plist. Eu adicionei e ainda não parece funcionar. Eu estou usando Swift, iOS8 e XCode 6 beta 4
Vijay Kumar AB
4
@Vjay - você precisa editar o arquivo Info.plist em um editor, não pode definir essas chaves no Xcode (a partir da versão 6).
Kendall Helmstetter Gelner
11
Apenas um lembrete: se você não quiser mostrar uma explicação personalizada ao usuário, basta definir essa chave como uma string vazia.
nonamelive
7
Você precisa manter seu locationManager para fazê-lo funcionar. para fazer o seu CLLocationManager como uma propriedade forte
Vassily
273
EU AMO que você não receba nenhum erro, nenhum aviso, nenhuma mensagem de log, NADA se você deixar de fora a entrada do plist. Basicamente, a Apple criou uma chamada de API que não faz NADA se você não tiver a entrada plist apropriada. Obrigado a @OrtwinGentz ​​por descobrir isso.
MobileVet 22/09
314

Eu estava puxando meu cabelo com o mesmo problema. O Xcode fornece o erro:

Tentando iniciar MapKitatualizações de local sem solicitar autorização de local. Deve ligar -[CLLocationManager requestWhenInUseAuthorization]ou -[CLLocationManager requestAlwaysAuthorization]primeiro.

Mas mesmo se você implementar um dos métodos acima, ele não solicitará ao usuário, a menos que haja uma entrada no info.plist para NSLocationAlwaysUsageDescriptionouNSLocationWhenInUseUsageDescription .

Adicione as seguintes linhas ao seu info.plist em que os valores da sequência representam o motivo pelo qual você precisa acessar a localização dos usuários

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

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

Eu acho que essas entradas podem estar ausentes desde que iniciei este projeto no Xcode 5. Acho que o Xcode 6 pode adicionar entradas padrão para essas chaves, mas não foi confirmado.

Você pode encontrar mais informações sobre essas duas configurações aqui

Henry
fonte
13
xcode 6 não adicionar essas chaves por padrão, se você pretende implementar CLLocationManager você deve adicioná-los manualmente
Wesley Smith
1
Eu também tive que adicioná-los manualmente, não consegui adicionar através da visualização RawValues ​​do info.plist no Xcode6!
Kendall Helmstetter Gelner
1
Eu procurei eternamente por isso. Minha mensagem [CLLLocationManager authenticationStatus] estava retornando apenas um valor de <nil>. Após adicionar as teclas acima, ele começou a retornar as respectivas enumerações para a saída das mensagens. Pelo que encontrei, este é um bug conhecido do iOS 8, mas não consegui encontrar nada no meu contexto há séculos. Graças um mil!
precisa saber é o seguinte
4
Eu gosto do valor da string que você coloca #
Chris Chen
1
A mensagem aparecerá como a sub-mensagem no Alerta que pergunta se o usuário gostaria de compartilhar sua localização. Como tal, simplesmente estar vazio (em branco) parece fazer mais sentido no meu aplicativo. Uma explicação de por que você deseja usar o local também faria sentido. No entanto, NSLocationWhenInUseUsageDescription não se comportou conforme o esperado para mim (ou seja, continuou obtendo permissão negada, mesmo que o valor de retorno estivesse correto). NSLocationAlwaysUsageDescription funcionou bem.
bob Arcady
104

Para garantir que isso seja compatível com o iOS 7, verifique se o usuário está executando o iOS 8 ou iOS 7. Por exemplo:

#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];
JKoko
fonte
164
A melhor maneira de verificar a versão é verificar para ver se o objeto tem que seletor, por exemplo: if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { ...
progrmr
1
Tive problemas ao implementar a solução da @ progrmr ao criar no Xcode 5, pois ele não sabe qual é o requestAlwaysAuthorizationmétodo. Minha solução adicional era usar esta linha na ifdeclaração, em vez de uma chamada de método normal: [self.locationManager performSelector:@selector(requestAlwaysAuthorization)];. Talvez isso seja óbvio para outras pessoas, mas levei um tempo para descobrir. Eu acho que é a solução certa até o final do Xcode 6 ser lançado.
VinceFior 9/09/14
2
A solução certa é construir com o Xcode 6. Se você estiver construindo com o Xcode 5, não precisará solicitar autorização, é automático.
progrmr
Você pode ter razão. Minha preocupação era que eu queria que meu código fosse compilado no Xcode 5 (mesmo que ele não funcione no iOS 8, a menos que seja compilado no Xcode 6) enquanto minha equipe faz a transição para o Xcode 6. Mas talvez seja um fluxo de trabalho melhor escrever o código normalmente e não mesclá-lo até passarmos para o Xcode 6 .. Obrigado.
precisa saber é o seguinte
@VinceFior a abordagem recomendada é compilar condicionalmente usando a macro SDK definido __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 para o seu arquivo info.plist insira a descrição da imagem aqui

neo D1
fonte
1
Solução semelhante encontrada de maneira mais descritiva em datacalculation.blogspot.in/2014/11/…
Teste do iOS
2
@ Hemang: De acordo com a Apple Dev Documentation: É seguro iniciar os serviços de localização antes que o status de autorização do seu aplicativo seja determinado. Embora você possa iniciar os serviços de localização, esses serviços não entregam dados até que o status da autorização seja alterado para kCLAuthorizationStatusAuthorizedAlways ou kCLAuthorizationStatusAuthorizedWhenInUse.
28414 Andrew Andrew
Um pouco tarde, mas eu recomendo que você ocultar partes irrelevantes do seu arquivo plist, especialmente FacebookAppID
Przemysław Wrzesinski
Obrigado, mas isso é apenas uma amostra manequim :)
neo D1
Também é importante que o projeto esteja apontando para o info.plist correto (aquele em que a chave está definida). Isso é determinado nas configurações de criação do projeto em Arquivo Info.plist.
clearlight
30

De acordo com os documentos da Apple:

No iOS 8, é necessária a presença de um valor-chave NSLocationWhenInUseUsageDescriptionou NSLocationAlwaysUsageDescriptionno arquivo Info.plist do seu aplicativo. Também é necessário solicitar permissão do usuário antes de se registrar para atualizações de local, ligando [self.myLocationManager requestWhenInUseAuthorization]ou[self.myLocationManager requestAlwaysAuthorization] dependendo da sua necessidade. A seqüência que você inseriu no Info.plist será exibida na caixa de diálogo a seguir.

Se o usuário conceder permissão, os negócios serão normais. Se eles negarem permissão, o delegado não será informado das atualizações de local.

metateórico
fonte
Encontrei uma descrição simples aqui em datacalculation.blogspot.in/2014/11/…
Teste do 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];
        }
    }

No iOS 8, você precisa fazer duas coisas extras para que o local funcione: adicione uma chave ao seu Info.plist e solicite autorização ao gerente do local solicitando que ele inicie. Existem duas chaves Info.plist para a nova autorização de local. Uma ou ambas as chaves são necessárias. Se nenhuma das chaves estiver lá, você poderá chamar startUpdatingLocation, mas o gerenciador de local não será iniciado. Também não enviará uma mensagem de falha para o delegado (como nunca foi iniciado, não pode falhar). Também falhará se você adicionar uma ou ambas as chaves, mas esquecer de solicitar explicitamente a autorização. Portanto, a primeira coisa que você precisa fazer é adicionar uma ou ambas as seguintes chaves ao seu arquivo Info.plist:

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

Ambas as teclas recebem uma string

que é uma descrição do motivo pelo qual você precisa de serviços de localização. Você pode inserir uma sequência como "O local é necessário para descobrir onde você está" que, como no iOS 7, pode ser localizado no arquivo InfoPlist.strings.

insira a descrição da imagem aqui

Adarsh ​​GJ
fonte
19

Minha solução que pode ser compilada no 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];
Yinfeng
fonte
2
Solução dinâmica agradável, para usar em todos os aplicativos. Eu mudaria a ordem e, em vez de verificar o iphone 8.0, verificaria se o gerente de local responde à autorização e executaria o status da autorização para obter o código. Isso tornará mais universal.
Zirinisp
Também funcionou no xCode 7.2.
Totoro
17

O código antigo para perguntar a localização não funcionará no iOS 8. Você pode tentar este método para obter autorização de localização:

- (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];
    }
}
Nits007ak
fonte
O UIAlertView foi descontinuado. Você deve usar UIAlertController.
Pasan Premaratne
Sim, eu sei que está obsoleto, mas isso também vai funcionar. mas sim, é melhor usar UIAlertController para IOS8.
Nits007ak
12

No iOS 8, você precisa fazer duas coisas extras para que o local funcione: adicione uma chave ao seu Info.plist e solicite autorização ao gerente do local, solicitando que ele inicie

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>

Adicione isto ao seu código

if (IS_OS_8_OR_LATER)
{
    [locationmanager requestWhenInUseAuthorization];

    [locationmanager requestAlwaysAuthorization];
}
porJeevan
fonte
1
não está claro se o pseudocódigo é uma chamada pré-processador ou uma chamada normal
El Cara
1
Adicione isto a sua constants.h ou arquivo .pch: IS_OS_8_OR_LATER #define ([[UIDevice currentDevice] .systemVersion floatValue]> = 8,0)
OxenBoxen
Por que você iria solicitar tanto, você deve adicionar um comentário mencionar apenas para usar um ou o outro, dependendo de suas necessidades de aplicação
powerj1984
a parte info.plist é fácil de fazer no Unity3d, mas como eu adicionaria a parte do código se estivesse usando o unity3d? Onde ?
CthulhuJon
11

Um erro comum para desenvolvedores Swift:

Primeiro, certifique-se de adicionar um valor ao plist para um NSLocationWhenInUseUsageDescriptionou outro NSLocationAlwaysUsageDescription.

Se você ainda não estiver vendo uma janela solicitando autorização, verifique se está colocando a linha var locationManager = CLLocationManager()no viewDidLoadmétodo do seu View Controller . Se você o fizer, mesmo se ligar locationManager.requestWhenInUseAuthorization(), nada será exibido. Isso ocorre depois que o viewDidLoad é executado, a variável locationManager é desalocada (limpa).

A solução é localizar a linha var locationManager = CLLocationManager()na parte superior do método da classe.

st.derrick
fonte
9

Antes [locationManager startUpdatingLocation];, adicione uma solicitação de serviços de localização iOS8:

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

Edite o aplicativo Info.pliste adicione a chave NSLocationAlwaysUsageDescriptioncom o valor da string que será exibido ao usuário (por exemplo, We do our best to preserve your battery life.)

Se o seu aplicativo precisar de serviços de localização apenas enquanto o aplicativo estiver aberto, substitua:

requestAlwaysAuthorizationcom requestWhenInUseAuthorizatione

NSLocationAlwaysUsageDescriptioncom NSLocationWhenInUseUsageDescription.

budidino
fonte
9

Eu estava trabalhando em um aplicativo que foi atualizado para o iOS 8 e os serviços de localização pararam de funcionar. Você provavelmente receberá um erro na área de Depuração da seguinte forma:

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

Eu fiz o procedimento menos invasivo. Primeiro adicione a NSLocationAlwaysUsageDescriptionentrada ao seu info.plist:

Digite a descrição da imagem aqui

Observe que eu não preenchi o valor dessa chave. Isso ainda funciona e não estou preocupado porque esse é um aplicativo interno. Além disso, já existe um título solicitando o uso de serviços de localização, então não queria fazer nada redundante.

Em seguida, criei uma condicional para o iOS 8:

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

Depois disso, o locationManager:didChangeAuthorizationStatus:método é chamado:

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

E agora tudo funciona bem. Como sempre, confira a documentação .

Kris Utter
fonte
7

Solução com compatibilidade com versões anteriores:

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

Configure a chave NSLocationWhenInUseUsageDescription no seu Info.plist

hrchen
fonte
2
Isso não está correto, e o caso kCLAuthorizationStatusDenied? ele pula para o outro e começa a atualizar o local que não está correto!
electronix384128
@BenMarten Eu não acho que isso importe. Você deve lidar com isso sozinho locationManager: (CLLocationManager *)manager didFailWithError: (NSError *)error. No entanto, ele esqueceu de adicionar startUpdatingLocation na instrução if, portanto, depois que eles aceitam ou negam, na verdade, ele não chama startUpdateLocation.
Chris
6

Solução com compatibilidade com versões anteriores que não produz avisos do 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];
}

NSLocationWhenInUseUsageDescriptionChave de instalação no seu Info.plist.

Para iOS versão 11.0+ : NSLocationAlwaysAndWhenInUseUsageDescriptionchave de configuração no seu Info.plist. juntamente com outras 2 teclas.

Alexander Belyavskiy
fonte
Isso não está correto, e o caso kCLAuthorizationStatusDenied? ele pula para o outro e começa a atualizar o local que não está correto!
electronix384128
Isso é muito estranho, isso funciona bem para mim, não funciona perfeitamente bem com permitir e não permitir. Mesmo a solução Jacob parece precisa, mas não funcionou para mim. Estranho, mas funcionou !!!
josh
Chamando [self.locationManager startUpdatingLocation] logo após requestWhenInUseAuthorization não tem nenhum ponto
Kostia Kim
5

This is issue with ios 8 Adicione isso ao seu código

if (IS_OS_8_OR_LATER)
{
    [locationmanager requestWhenInUseAuthorization];

    [locationmanager requestAlwaysAuthorization];
}

e para 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>
Pooja Patel
fonte
NSLocationUsageDescriptionnão é usado em iOS8
Carlos Ricardo
4

Para acessar a localização do usuário no iOS 8, você precisará adicionar,

NSLocationAlwaysUsageDescription in the Info.plist 

Isso solicitará ao usuário a permissão para obter sua localização atual.

Annu
fonte
4

Procedimento Objective-C Siga as instruções abaixo:

Para iOS-11 Para iOS 11, consulte esta resposta: Acesso à localização do iOS 11

É necessário adicionar duas chaves ao plist e fornecer a mensagem conforme a imagem abaixo:

 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription
 3. NSLocationAlwaysUsageDescription

insira a descrição da imagem aqui Para iOS-10 e abaixo:

NSLocationWhenInUseUsageDescription

insira a descrição da imagem aqui

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

Métodos de delegação

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

Procedimento Rápido

Siga as instruções abaixo:

Para iOS-11 Para iOS 11, consulte esta resposta: Acesso à localização do iOS 11

É necessário adicionar duas chaves ao plist e fornecer a mensagem conforme a imagem abaixo:

 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription
 3. NSLocationAlwaysUsageDescription

insira a descrição da imagem aqui Para iOS-10 e abaixo:

insira a descrição da imagem aqui

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 delegação

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

}
Alok
fonte
Verifique se NSLocationAlwaysUsageDescription também foi adicionado, caso contrário, você receberá um erro ao fazer o upload na App Store.
Alok
Sua mensagem também deve ser informativa, caso contrário, a Apple rejeitará o aplicativo durante a revisão do processo.
Alok
3

Para aqueles que usam o Xamarin , tive que adicionar a chave NSLocationWhenInUseUsageDescriptionao info.plist manualmente, pois ela não estava disponível nas listas suspensas no Xamarin 5.5.3 Build 6 ou no XCode 6.1 - apenas NSLocationUsageDescriptionestava na lista e isso fez CLLocationManagercom que continuasse a falhar silenciosamente.

Derreck Dean
fonte
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]);

}
Prosenjit Goswami
fonte
2

Um pequeno auxiliar para todos vocês que têm mais de um arquivo Info.plist ...

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

Ele adicionará a marca necessária a todos os arquivos Info.plist no diretório atual (e subpastas).

Outro é:

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

Ele adicionará sua descrição a todos os arquivos.

Peter Mortensen
fonte
2

Eu recebo um erro semelhante no iOS9 (trabalhando com o Xcode 7 e Swift 2): Tentando iniciar as atualizações de localização do MapKit sem solicitar a autorização da localização. Deve chamar - [CLLocationManager requestWhenInUseAuthorization] ou - [CLLocationManager requestAlwaysAuthorization] primeiro. Eu estava seguindo um tutorial, mas o tutor estava usando o iOS8 e o Swift 1.2. Existem algumas alterações no Xcode 7 e no Swift 2, encontrei esse código e ele funciona bem para mim (se alguém precisar de ajuda):

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, coloquei isso em info.plist: Information Property List: NSLocationWhenInUseUsageDescription Value: aplicativo precisa de servidores de localização para a equipe

Jorge Luis Jiménez
fonte
2

Para acessar a localização dos usuários no iOS. Você precisa adicionar duas chaves

NSLocationWhenInUseUsageDescription

NSLocationAlwaysUsageDescription

no arquivo 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>

Veja esta imagem abaixo.

Imagem Info.plist

Vinoth Vino
fonte
1
  1. Adicione a tecla NSLocationWhenInUseUsageDescriptionou NSLocationAlwaysUsageDescription(uso em segundo plano do GPS) com a corda pedindo para usar o GPS em cada um info.plistde cada alvo.

  2. Peça permissão executando:

    [self initLocationManager: locationManager];

Onde initLocationManagerfica:

// asks for GPS authorization on iOS 8
-(void) initLocationManager:(CLLocationManager *) locationManager{

    locationManager = [[CLLocationManager alloc]init];

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

Lembre-se de que se as chaves não estiverem em cada uma info.plistpara cada destino, o aplicativo não perguntará ao usuário. Ele ifoferece compatibilidade com o iOS 7 e o respondsToSelector:método garante compatibilidade futura, em vez de apenas resolver o problema do iOS 7 e 8.

Juan Isaza
fonte
0

O problema para mim era que a classe CLLocationManagerDelegateera privada, o que impedia que todos os métodos delegados fossem chamados. Acho que não é uma situação muito comum, mas pensei em mencioná-la para o caso de ajudar alguém.

Lorenzo
fonte
0

Acrescento aqueles chave no InfoPlist.stringsno iOS 8.4, mini-iPad 2. Ele funciona também. Eu não ponho nenhuma chave NSLocationWhenInUseUsageDescriptionno meu Info.plist.


InfoPlist.strings :

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

A base desse segmento , segundo ele as in iOS 7, pode ser localizada no InfoPlist.strings. No meu teste, essas chaves podem ser configuradas diretamente no arquivoInfoPlist.strings .

Portanto, a primeira coisa que você precisa fazer é adicionar uma ou ambas as seguintes chaves ao seu arquivo Info.plist:

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

Ambas as chaves usam uma sequência que é uma descrição do motivo pelo qual você precisa de serviços de localização. Você pode inserir uma sequência como "O local é necessário para descobrir onde você está" que, como no iOS 7 , pode ser localizado no arquivo InfoPlist.strings.


ATUALIZAR:

Eu acho que @IOSo método é melhor. Adicione chave a Info.plistcom valor vazio e adicione cadeias localizadas a InfoPlist.strings.

AechoLiu
fonte