在iOS中获取设备位置(仅限国家/地区)

问题描述 投票:53回答:12

我需要获取iOS设备的国家/地区位置。

我一直在尝试将CoreLocation与MKReverseGeocoder一起使用。然而,这似乎经常发生错误。我只需要这个国家,不需要街道等。

如何以更稳定的方式完成?

ios core-location
12个回答
38
投票

NSLocale只是关于当前使用的区域设置的设置,它并不意味着您所在的实际国家/地区。

使用CLLocationManager获取当前位置和CLGeocoder以执行反向地理编码。你可以从那里获得国家名称。


0
投票

这是Swift 3中的一个快速循环,它返回一个完整的国家/地区代码列表。

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

0
投票

@抢

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

使用这些代码,您将获得您所在地区的国家/地区代码,如果您没有静止,请更改它,只需进入手机设置 - >常规 - >语言和地区,然后设置您想要的地区


0
投票

用于根据区域集获取国家/地区名称的Swift 4.0代码:

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

prints:可选(“NG”)可选(“尼日利亚”)。 //为尼日利亚地区设置


92
投票
NSString *countryCode = [[NSLocale currentLocale] objectForKey: NSLocaleCountryCode];

会得到一个标识符,例如“美国”(美国),“ES”(西班牙)等


在Swift 3中:

let countryCode = NSLocale.current.regionCode

在Swift 2.2中:

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

与基于CLLocationManager的解决方案相比,这种方法有利有弊。主要的缺点是,如果用户以不同方式配置设备,则无法保证这是设备的物理位置。然而,这也可以被视为专业人士,因为它反而显示用户在精神/文化上与哪个国家保持一致 - 因此,例如,我出国度假,然后现场仍然是我的祖国。然而,一个非常大的专业人士是这个API不需要像CLLocationManager那样的用户权限。因此,如果你还没有获得使用用户位置的权限,并且你无法证明在用户面前抛出弹出对话框(或者他们已经拒绝了弹出窗口而你需要回退),那么这可能是你的API想用。对此的一些典型用例可以是个性化(例如,与文化相关的内容,默认格式等)和分析。


15
投票

@Denis的答案很好 - 这里有一些代码将他的答案付诸实践。这适用于您已设置为符合CLLocationManagerDelegate协议的自定义类。它有点简化(例如,如果位置管理器返回多个位置,它只是与第一个位置一起),但应该给人们一个不错的开始......

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

11
投票

这是@Denis和@Matt的答案,为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")
        }
    }
}

别忘了在NSLocationAlwaysUsageDescription设置NSLocationWhenInUseUsageDescriptionInfo.plist


7
投票

这是另一种可能过于迂回的方法。其他解决方案基于手动设置(NSLocale)或请求允许使用可拒绝的位置服务(CLLocationManager),因此它们有缺点。

您可以根据当地时区获取当前国家/地区。我的应用程序与安装了pytz的运行Python的服务器连接,该模块为时区字符串提供了国家代码字典。我只需要让服务器知道这个国家,所以我不必完全在iOS上进行设置。在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']
...

在iOS方面:

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

我让我的服务器以本地时区名称发送,并在pytz country_timezones字典中查找。

如果您在pytz或其他来源中提供字典的iOS版本,则可以使用它在没有服务器帮助的情况下立即查找国家/地区代码,具体取决于时区设置(通常是最新的)。

我可能会误解NSLocale。它是否通过区域格式设置首选项或时区设置为您提供国家/地区代码?如果是后者,那么这只是获得相同结果的一种更复杂的方式......


5
投票
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

3
投票

对于Swift 3来说,它甚至更简单:

let countryCode = Locale.current.regionCode

1
投票

您可以从CLLocation获取NSTimeZone:https://github.com/Alterplay/APTimeZones并在本地工作。


0
投票

如果您只对电话设备感兴趣,那么这里提到的技术可能对您有用:Determine iPhone user's country

© www.soinside.com 2019 - 2024. All rights reserved.