【问题标题】:Get device location (only country) in iOS在 iOS 中获取设备位置(仅限国家/地区)
【发布时间】:2012-01-21 23:58:57
【问题描述】:

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

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

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

【问题讨论】:

    标签: ios core-location


    【解决方案1】:
    NSString *countryCode = [[NSLocale currentLocale] objectForKey: NSLocaleCountryCode];
    

    会给你一个标识符,例如“US”(美国)、“ES”(西班牙)等


    Swift 3 中:

    let countryCode = NSLocale.current.regionCode
    

    Swift 2.2 中:

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

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

    【讨论】:

    • 嗨,马丁。这将检索设备所在的实际位置,或设备设置的语言。还是确实存在与“语言”分开的设备“区域”?
    • 在您的 iPhone 上转到设置->常规->国际。在那里,您可以分别更改语言、区域格式(对区域设置更友好的术语)和日历(公历、日语或佛教)。不同的组合是可能的 - 例如,我作为丹麦人仍然更喜欢英语界面,但丹麦语言环境(所以一周从星期一开始,我想要 dd/mm/yy 因为 mm/dd/yy 很奇怪;)这不是受设备物理位置的影响(我不希望它突然变成意大利语,只是因为我在度假……)
    • 很好的回答和很好的评论! :-)
    • 这和地点无关,只有语言。
    • 明确一点,NSLocaleCountryCode 返回的标识符将是用户的“区域格式”。语言独立于此。最终,您首选的日期/时间/电话号码格式,即区域格式,是您可能来自哪里的指标,但它肯定不是确定的。
    【解决方案2】:

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

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

    【讨论】:

    • 你有 iOS 4 的解决方案吗?
    • 对于 iOS4,您可以获取当前坐标 lat&long 并使用一些 Google 网络服务从这里进行反向地理编码 code.google.com/apis/maps/documentation/geocoding
    • 这是一个很好的答案,也是当我不得不解决这个问题时我最终这样做的方式。仅供参考,我在下面发布了我自己的答案,其中包含一些实际实现的示例代码,以帮助人们节省一点时间阅读文档以了解如何实现此解决方案...
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      这里是@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")
              }
          }
      }
      

      不要忘记在Info.plist 中设置NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription

      【讨论】:

      • 我正在尝试这样做,但它似乎并没有调用这个功能 locationManger,因此我没有在控制台中打印任何内容。我需要在某个地方调用这个方法吗?
      • 每次在设备中更新位置时都会自动调用它。确保 locationManager.delegate 像我在上面所做的那样设置为 self ,并将 CLLocationManagerDelegate 添加到顶部的类中。
      • 抱歉,如果您使用的是 swift 3,则该函数中应该有一个下划线 func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) 我将更新原始帖子以澄清这一点
      • @lindanordstrom 抱歉,我知道这是一个愚蠢的问题,但是有没有办法创建一个变量来存储 « currentLocPlacemark » 的值?如果用户在不同的国家/地区,我正在尝试访问它的价值来做不同的事情,但它不会让我这样做。谢谢!
      • 我很确定“currentLocPlacemark.isoCountryCode”和“currentLocPlacemark.country”存储为字符串,您可以将它们存储在变量中并根据您的需要做不同的事情。你得到什么错误?
      【解决方案5】:

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

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

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

      import CoreTelephony
      
      guard carrier = CTTelephonyNetworkInfo().subscriberCellularProvider else {
          //iPad
          return
      }
      
      let countryST = carrier.isoCountryCode!
      

      【讨论】:

      • subscriberCellularProvider 已被弃用,请改用 CTTelephonyNetworkInfo().serviceSubscriberCellularProviders 字典
      【解决方案6】:

      这是另一种可能过于迂回的方法。其他解决方案基于手动设置(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。它是否通过区域格式首选项或时区设置为您提供国家代码?如果是后者,那么这只是获得相同结果的更复杂的方法......

      【讨论】:

      • 听起来不错。但我刚刚检查了我的 iPad 时区(自动设置),它显示的是新加坡,而我住在马来西亚(距新加坡 300 英里)。
      【解决方案7】:
      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
      

      【讨论】:

        【解决方案8】:

        对于 Swift 3,它更简单:

        let countryCode = Locale.current.regionCode
        

        【讨论】:

          【解决方案9】:

          根据地区集获取国家/地区名称的 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)
          

          打印:可选(“NG”)可选(“尼日利亚”)。 //对于尼日利亚区域集

          【讨论】:

            【解决方案10】:

            如果 Locale.current.regionCode 由于某些原因不起作用,请使用 CoreTelephony 方法作为备用方法。

            import CoreTelephony
            
            if let carriers = CTTelephonyNetworkInfo().serviceSubscriberCellularProviders?.values, let countryCode = Array(carriers).compactMap { $0.isoCountryCode }.first {
                print("❤️ \(countryCode)")
            }
            

            【讨论】:

              【解决方案11】:

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

              【讨论】:

                【解决方案12】:

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

                【讨论】:

                  【解决方案13】:

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

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

                  【讨论】:

                    【解决方案14】:

                    @Rob

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

                    使用这些代码,您将获得您所在地区的国家/地区代码,如果您还没有得到静止,那么只需进入电话设置->通用->语言和地区并设置您想要的地区

                    【讨论】:

                      【解决方案15】:
                          if let countryCode = Locale.current.regionCode {
                              let country =   Locale.current.localizedString(forRegionCode: countryCode)
                          }
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 2019-01-13
                        • 1970-01-01
                        • 2012-11-21
                        • 1970-01-01
                        • 1970-01-01
                        • 2023-03-21
                        • 2013-10-24
                        相关资源
                        最近更新 更多