Je dois connaître l'emplacement du pays d'un appareil iOS.
J'ai essayé d'utiliser CoreLocation avec MKReverseGeocoder. Cependant, cela semble revenir assez souvent de manière erronée. Et je n'ai besoin que du pays, pas besoin de rues et autres.
Comment cela peut-il être fait de manière plus stable?
NSLocale
est simplement un paramètre relatif aux paramètres régionaux actuellement utilisés, cela ne signifie pas le pays dans lequel vous vous trouvez.
Utilisez CLLocationManager
pour obtenir l'emplacement actuel et CLGeocoder
pour effectuer un géocodage inversé. Vous pouvez obtenir le nom du pays à partir de là.
NSString *countryCode = [[NSLocale currentLocale] objectForKey: NSLocaleCountryCode];
vous obtiendrez un identifiant comme par exemple "US" (États-Unis), "ES" (Espagne), etc.
Dans Swift 3 :
let countryCode = NSLocale.current.regionCode
Dans Swift 2.2 :
let countryCode = NSLocale.currentLocale().objectForKey(NSLocaleCountryCode) as String
Comparée à une solution basée sur CLLocationManager, cette approche présente des avantages et des inconvénients. Le principal inconvénient est qu'il ne garantit pas que le périphérique est physiquement si l'utilisateur le configure différemment. Cela peut toutefois aussi être considéré comme un pro, car il indique plutôt à quel pays un utilisateur est aligné mentalement/culturellement - de sorte que, par exemple, Je pars en vacances à l'étranger, les paramètres régionaux sont toujours définis dans mon pays d'origine. Cependant, un gros avantage est que cette API ne nécessite pas l'autorisation de l'utilisateur, contrairement à CLLocationManager. Donc, si vous n'avez pas encore obtenu l'autorisation d'utiliser l'emplacement de l'utilisateur, et que vous ne pouvez vraiment pas justifier de lancer une boîte de dialogue contextuelle sur le visage de l'utilisateur (ou que celui-ci l'a déjà rejeté et que vous ayez besoin d'une solution de secours), il s'agit probablement de l'API que vous utilisez. vouloir utiliser. La personnalisation (par exemple, un contenu adapté à la culture, les formats par défaut, etc.) et l’analyse constituent des cas d’utilisation typiques.
La réponse de @ Denis est bonne - voici un code qui met sa réponse en pratique. Ceci concerne une classe personnalisée que vous avez définie pour se conformer au protocole CLLocationManagerDelegate
. C'est un peu simplifié (par exemple, si le gestionnaire d'emplacement renvoie plusieurs emplacements, il va simplement avec le premier) mais devrait donner aux gens un bon départ ...
- (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]);
}];
}
Voici les réponses de @ Denis et @ Matt réunies pour une solution 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'oubliez pas de définir également NSLocationAlwaysUsageDescription
ou NSLocationWhenInUseUsageDescription
dans Info.plist
!
Voici une méthode alternative, peut-être trop détournée. Les autres solutions sont basées sur des paramètres manuels (NSLocale) ou sur une demande d'autorisation d'utiliser des services de localisation qui peuvent être refusés (CLLocationManager), ce qui présente des inconvénients.
Vous pouvez obtenir le pays actuel en fonction du fuseau horaire local. Mon application s'interface avec un serveur exécutant Python avec pytz installé, et ce module fournit un dictionnaire de codes de pays pour les chaînes de fuseau horaire. Je dois seulement que le serveur connaisse le pays afin de ne pas le configurer entièrement sur iOS. Du côté 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']
...
Du côté iOS:
NSTimeZone *tz = [NSTimeZone localTimeZone];
DLog(@"Local timezone: %@", tz.name); // prints "America/Los_Angeles"
J'ai mon serveur envoyer le nom du fuseau horaire local et le rechercher dans le dictionnaire pytz country_timezones.
Si vous rendez une version iOS du dictionnaire disponible dans pytz ou dans une autre source, vous pouvez l'utiliser pour rechercher immédiatement le code pays sans l'aide d'un serveur, en fonction des paramètres de fuseau horaire, qui sont souvent à jour.
Je peux cependant mal comprendre NSLocale. Vous donne-t-il le code du pays via les préférences de formatage régionales ou les paramètres de fuseau horaire? Dans ce dernier cas, il s’agit là d’une manière plus compliquée d’obtenir le même résultat ...
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
Pour Swift 3, c'est encore plus simple:
let countryCode = Locale.current.regionCode
Vous pouvez obtenir NSTimeZone à partir de CLLocation: https://github.com/Alterplay/APTimeZones et fonctionne localement.
@Rob
let locale = Locale.current
let code = (locale as NSLocale).object(forKey: NSLocale.Key.countryCode) as! String?
en utilisant ce code, vous obtiendrez le code de pays de votre région et si vous ne vous êtes pas arrêté, changez-le, allez dans Paramètres du téléphone-> Général-> Langue et région et définissez la région de votre choix.
Si vous n'êtes intéressé que par les appareils téléphoniques, la technique mentionnée ici peut vous être utile: Déterminez le pays de l'utilisateur de l'iPhone
Voici une petite boucle dans Swift 3 qui renvoie une liste complète des codes de pays.
let countryCode = NSLocale.isoCountryCodes
for country in countryCode {
print(country)
}
Code Swift 4.0 permettant d’obtenir le nom du pays selon la région définie:
let countryLocale = NSLocale.current
let countryCode = countryLocale.regionCode
let country = (countryLocale as NSLocale).displayName(forKey: NSLocale.Key.countryCode, value: countryCode)
print(countryCode, country)
impressions: facultatif ("NG") facultatif ("Nigeria"). // pour la région du Nigeria