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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8534496/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 15:55:11  来源:igfitidea点击:

Get device location (only country) in iOS

ioscore-location

提问by johan

I need to get the country location of a iOS device.

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

I've been trying to use CoreLocation with MKReverseGeocoder. However this seems to return erraneous quite frequently. And I only need the country, no need for streets and such.

我一直在尝试将 CoreLocation 与 MKReverseGeocoder 一起使用。然而,这似乎经常返回错误。我只需要国家,不需要街道之类的。

How can this be done in a more stable way?

如何以更稳定的方式做到这一点?

采纳答案by Denis

NSLocaleis just a setting about currently used regional settings, it doesn't mean the actual country you're in.

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

Use CLLocationManagerto get current location & CLGeocoderto perform reverse-geocoding. You can get country name from there.

使用CLLocationManager来获取当前位置及CLGeocoder执行反向地理编码。您可以从那里获取国家/地区名称。

回答by Martin Gjaldbaek

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

will get you an identifier like e.g. "US" (United States), "ES" (Spain), etc.

将为您提供一个标识符,例如“US”(美国)、“ES”(西班牙)等。



In Swift 3:

Swift 3 中

let countryCode = NSLocale.current.regionCode

In Swift 2.2:

Swift 2.2 中

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

Compared to a solution based on CLLocationManager this approach has pros and cons. The primary con is that it doesn't guarantee that this is where the device is physically if the user configures it differently. This can however also be seen as a pro since it instead shows which country a user is mentally/culturally aligned with - so if e.g. I go abroad on vacation then the locale is still set to my home country. However a pretty big pro is that this API doesn't require user permission like CLLocationManager does. So if you haven't already gotten permission to use the user's location, and you can't really justify throwing a popup dialog in the user's face (or they already rejected that popup and you need a fallback) then this is probably the API you want to use. Some typical use cases for this could be personalization (e.g. culturally relevant content, default formats, etc.) and analytics.

与基于 CLLocationManager 的解决方案相比,这种方法有利有弊。主要的缺点是,如果用户以不同的方式配置它,它不能保证这是设备的物理位置。然而,这也可以被视为专业人士,因为它显示了用户在精神/文化上与哪个国家保持一致 - 因此,例如,如果我去国外度假,那么语言环境仍然设置为我的祖国。然而,一个非常大的优点是这个 API 不需要像 CLLocationManager 那样的用户许可。因此,如果您尚未获得使用用户位置的许可,并且您无法真正证明在用户面前抛出一个弹出对话框(或者他们已经拒绝该弹出窗口并且您需要回退)那么这可能是您的 API想用。这方面的一些典型用例可能是个性化(例如

回答by Matt

@Denis's answer is good -- here is some code putting his answer into practice. This is for a custom class that you have set to conform to the CLLocationManagerDelegateprotocol. It's a little simplified (e.g. if the location manager returns multiple locations, it just goes with the first one) but should give folks a decent start...

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

回答by lindanordstrom

Here is @Denis's and @Matt's answers put together for a Swift 3solution:

以下是 @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")
        }
    }
}

Don't forget to set the NSLocationAlwaysUsageDescriptionor NSLocationWhenInUseUsageDescriptionin Info.plistas well!

不要忘记设置NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescriptionInfo.plist的!

回答by scott_at_skritter

Here's an alternative, perhaps overly circuitous method. The other solutions are based on manual settings (NSLocale) or on requesting for permission to use location services which can be denied (CLLocationManager), so they have drawbacks.

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

You can get the current country based on the local timezone. My app is interfacing with a server running Python with pytz installed, and that module provides a dictionary of country codes to timezone strings. I only really need to have the server know the country so I don't have to set it up entirely on iOS. On the Python side:

您可以根据当地时区获取当前国家/地区。我的应用程序与安装了 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']
...

On the iOS side:

在 iOS 方面:

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

I have my server send in the local timezone name and look it up in the pytz country_timezones dictionary.

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

If you make an iOS version of the dictionary available in pytz or some other source, you can use it to immediately look up the country code without the help of a server, based on timezone settings, which are often up to date.

如果您在 pytz 或其他一些来源中提供了字典的 iOS 版本,您可以使用它根据时区设置立即查找国家代码,而无需服务器的帮助,这些设置通常是最新的。

I may be misunderstanding NSLocale though. Does it give you the country code through regional formatting preferences or timezone settings? If the latter, then this is just a more complicated way of getting the same result...

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

回答by Teja Kumar Bethina

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

回答by Shaked Sayag

For Swift 3 it's even simpler:

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

let countryCode = Locale.current.regionCode

回答by Van

Swift 4.0 code for getting the Country name as per region set:

用于根据区域集获取国家/地区名称的 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: Optional("NG") Optional("Nigeria"). //for nigeria region set

打印:可选(“NG”)可选(“尼日利亚”)。//为尼日利亚地区集

回答by grep

As mentioned by @Denis Localeis just a setting about currently used regional settings, it doesn't mean the actual country you're in.

正如@Denis 所提到的,这Locale只是关于当前使用的区域设置的设置,并不意味着您所在的实际国家/地区。

However, suggested use of CLLocationManagerto get current location & CLGeocoderto perform reverse-geocoding, means prompting user access to Location Services.

但是,建议使用CLLocationManager来获取当前位置并CLGeocoder执行反向地理编码,这意味着提示用户访问位置服务。

How about getting country code from mobile carrier?

如何从移动运营商获取国家代码?

import CoreTelephony

guard carrier = CTTelephonyNetworkInfo().subscriberCellularProvider else {
    //iPad
    return
}

let countryST = carrier.isoCountryCode!

回答by slatvick

You can get NSTimeZone from CLLocation: https://github.com/Alterplay/APTimeZonesand works locally.

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