it-swarm-pt.tech

Obter localização do dispositivo (único país) no iOS

Preciso obter a localização do país de um dispositivo iOS.

Eu tenho tentado usar o CoreLocation com o MKReverseGeocoder. No entanto, isso parece retornar erraneous com bastante freqüência. E eu só preciso do país, não há necessidade de ruas e tal.

Como isso pode ser feito de maneira mais estável?

51
johan

NSLocale é apenas uma configuração sobre as configurações regionais utilizadas atualmente, isso não significa o país real em que você está.

Use CLLocationManager para obter a localização atual e CLGeocoder para executar a geocodificação reversa. Você pode obter o nome do país de lá.

36
Denis
NSString *countryCode = [[NSLocale currentLocale] objectForKey: NSLocaleCountryCode];

vai te dar um identificador como por exemplo "EUA" (Estados Unidos), "ES" (Espanha), etc.


Em Swift 3 :

let countryCode = NSLocale.current.regionCode

Em Swift 2.2 :

let countryCode = NSLocale.currentLocale().objectForKey(NSLocaleCountryCode) as String

Em comparação com uma solução baseada em CLLocationManager, essa abordagem tem vantagens e desvantagens. O principal problema é que isso não garante que este seja o lugar onde o dispositivo está fisicamente se o usuário o configurar de maneira diferente. No entanto, isso também pode ser visto como um profissional, já que ele mostra com qual país um usuário está mentalmente/culturalmente alinhado - por exemplo, se Eu vou para o exterior em férias, em seguida, o local ainda está definido para o meu país de origem. No entanto, um grande profissional é que essa API não requer permissão do usuário, como o CLLocationManager. Então, se você ainda não obteve permissão para usar o local do usuário, e não pode justificar lançar uma caixa de diálogo pop-up na face do usuário (ou eles já rejeitaram esse pop-up e você precisa de um fallback), quer usar. Alguns casos de uso típicos para isso podem ser personalização (por exemplo, conteúdo culturalmente relevante, formatos padrão etc.) e análises.

86
Martin Gjaldbaek

@ A resposta de Denis é boa - aqui está algum código colocando sua resposta em prática. Isso é para uma classe personalizada que você definiu para estar em conformidade com o protocolo CLLocationManagerDelegate. É um pouco simplificado (por exemplo, se o gerenciador de localização retorna vários locais, ele apenas acompanha o primeiro), mas deve dar às pessoas um bom começo ...

- (id) init //designated initializer
{
    if (self)
    {
        self.locationManager = [[CLLocationManager alloc] init];
        self.geocoder = [[CLGeocoder alloc] init];
        self.locationManager.delegate = self;
        [self.locationManager startMonitoringSignificantLocationChanges];
    }
    return self;
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    if (locations == nil)
        return;

    self.currentLocation = [locations objectAtIndex:0];
    [self.geocoder reverseGeocodeLocation:self.currentLocation completionHandler:^(NSArray *placemarks, NSError *error)
    {
        if (placemarks == nil)
            return;

        self.currentLocPlacemark = [placemarks objectAtIndex:0];
        NSLog(@"Current country: %@", [self.currentLocPlacemark country]);
        NSLog(@"Current country code: %@", [self.currentLocPlacemark ISOcountryCode]);
    }];
}
15
Matt

Aqui estão as respostas de @ Denis e @ Matt juntas para uma solução Swift 3:

import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {

    let locationManager = CLLocationManager()
    let geoCoder = CLGeocoder()

    override func viewDidLoad() {
        super.viewDidLoad()

        locationManager.requestAlwaysAuthorization()
        if CLLocationManager.locationServicesEnabled() {
            locationManager.delegate = self
            locationManager.startMonitoringSignificantLocationChanges()
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let currentLocation = locations.first else { return }

        geoCoder.reverseGeocodeLocation(currentLocation) { (placemarks, error) in
            guard let currentLocPlacemark = placemarks?.first else { return }
            print(currentLocPlacemark.country ?? "No country found")
            print(currentLocPlacemark.isoCountryCode ?? "No country code found")
        }
    }
}

Não se esqueça de definir o NSLocationAlwaysUsageDescription ou NSLocationWhenInUseUsageDescription em Info.plist também!

11
lindanordstrom

Aqui está um método alternativo, talvez excessivamente tortuoso. As outras soluções são baseadas em configurações manuais (NSLocale) ou em solicitar permissão para usar serviços de localização que podem ser negados (CLLocationManager), então eles têm desvantagens.

Você pode obter o país atual com base no fuso horário local. Meu aplicativo está interagindo com um servidor executando Python com pytz instalado, e esse módulo fornece um dicionário de códigos de país para seqüências de fuso horário. Eu realmente só preciso que o servidor conheça o país para que eu não precise configurá-lo totalmente no iOS. No lado do Python:

>>> import pytz
>>> for country, timezones in pytz.country_timezones.items():
...     print country, timezones
... 
BD ['Asia/Dhaka']
BE ['Europe/Brussels']
BF ['Africa/Ouagadougou']
BG ['Europe/Sofia']
BA ['Europe/Sarajevo']
BB ['America/Barbados']
WF ['Pacific/Wallis']
...

No lado do iOS:

NSTimeZone *tz = [NSTimeZone localTimeZone];
DLog(@"Local timezone: %@", tz.name); // prints "America/Los_Angeles"

Eu tenho meu servidor enviar o nome do fuso horário local e procurá-lo no dicionário pytz country_timezones.

Se você criar uma versão iOS do dicionário disponível em pytz ou alguma outra fonte, poderá usá-la para procurar imediatamente o código do país sem a ajuda de um servidor, com base nas configurações de fuso horário, que geralmente estão atualizadas.

Eu posso estar entendendo errado o NSLocale. Dá-lhe o código do país através de preferências de formatação regional ou configurações de fuso horário? Se este último, então esta é apenas uma maneira mais complicada de obter o mesmo resultado ...

7
scott_at_skritter
NSLocale *countryLocale = [NSLocale currentLocale];  
NSString *countryCode = [countryLocale objectForKey:NSLocaleCountryCode];
NSString *country = [countryLocale displayNameForKey:NSLocaleCountryCode value:countryCode];
NSLog(@"Country Locale:%@  Code:%@ Name:%@", countryLocale, countryCode, country);
//Country Locale:<__NSCFLocale: 0x7fd4b343ed40>  Code:US   Name:United States
5
Teja Kumar Bethina

Para o Swift 3, é ainda mais simples:

let countryCode = Locale.current.regionCode
3
Shaked Sayag

Você pode obter o NSTimeZone de CLLocation: https://github.com/Alterplay/APTimeZones e funciona localmente.

1
slatvick

@Roubar

let locale = Locale.current
let code = (locale as NSLocale).object(forKey: NSLocale.Key.countryCode) as! String?

usando este código, você obterá o código do país da sua região e, se não ficar parado, altere-o. Basta ir em Configuração do telefone-> geral-> idioma e região e defina sua região desejada 

0
Harikesh

Se você estiver interessado apenas em aparelhos telefônicos, a técnica mencionada aqui pode ser útil para você: Determinar o país do usuário do iPhone

0
ThomasW

Aqui está um loop rápido no Swift 3 que retorna uma lista completa de códigos de países.

let countryCode = NSLocale.isoCountryCodes
    for country in countryCode {
        print(country)
    }
0
user7684436

Código Swift 4.0 para obter o nome do país conforme a região definida:

    let countryLocale = NSLocale.current
    let countryCode = countryLocale.regionCode
    let country = (countryLocale as NSLocale).displayName(forKey: NSLocale.Key.countryCode, value: countryCode)
    print(countryCode, country)

prints: Opcional ("NG") Opcional ("Nigéria"). // para conjunto de região da Nigéria

0
Van