iOS开发-国外坐标逆地理编码

前言

在开发中,经常会用到地理编码和逆地理编码来获得地图的数据,地理编码的话还是比较简单的,下面来说说坐标逆地理编码中遇到的那些坑。
  • 这里面只针对国外坐标来说
  • 使用三种逆地理编码
  • CLGeocoder Google逆地理编码 OSM逆地理编码

CLGeocoder

对于iOS开发来说,逆地理编码首先想到的便是自带的CLGeocoder了,我们使用

- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;

来进行逆地理编码请求。

 [self.geocoder reverseGeocodeLocation: location completionHandler:
                 ^(NSArray *placemarks, NSError *error) {
                     if (error == nil) {
                         // 系统反地理编码成功
                         //得到自己当前最近的地名
                         CLPlacemark *placemark = [placemarks objectAtIndex:0];
                         NSDictionary *dic = placemark.addressDictionary;
                         NSString *locatedAt = placemark.locality;

                     } else {
                         // 系统自带反地理编码失败,由 Google 接管。
                         NSLog(@"反地理失败");
                     }
                }];

我传入CLLocation经纬度,会返回CLPlacemarkCLPlacemark中的属性对应为下:

  • location 地理位置
  • region 区域信息
  • addressDictionary 详细的地址信息字典
  • name 地址名称
  • locality 城市名称

解析后拿到想要的数据即可。

但是使用CLLocation来进行逆地理编码, 经常会返回错误,这里我们要注意的是,声明CLGeocoder时,我们要用全局变量。

@property (nonatomic ,strong) CLGeocoder * geocoder;

用懒加载即可:

- (CLGeocoder *)geocoder
{
    if(!_geocoder)
    {
        _geocoder = [[CLGeocoder alloc] init];
    }
    return _geocoder;
}

对于使用CLLocation返回的语言,网上的给出的回答是和设备设置的语言有关,代码如下

// 保存 Device 的现语言 (英语 法语 ,,,)
    NSMutableArray *userDefaultLanguages = [[NSUserDefaults standardUserDefaults]
    objectForKey:@"AppleLanguages"];
    // 强制 成 简体中文
    [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"zh-hans",nil] 
    forKey:@"AppleLanguages"];

在逆编码结束的时候使用

// 还原Device 的语言
[[NSUserDefaults standardUserDefaults] setObject:userDefaultLanguages forKey:@"AppleLanguages"];

然后我人身在韩国时,发现App中返回的语言是当地语言韩文,并非是手机设置的中文,上面的方法并没有什么用,便打消了使用自带的逆地理编码,决定使用google的逆地理编码API。

Google逆地理编码

只是用谷歌的逆地理编码不展示地图的话,并不需要pod谷歌地图的SDK,
Geocoding API 支持直接使用 latlng 参数进行反向地理编码。
Google Maps Geocoding API 请求必须采用以下形式:

https://maps.googleapis.com/maps/api/geocode/json?

其中的json可以换成xml来设定输出结果格式。使用谷歌在中国的api也很简单,如下:

https://maps.google.cn/maps/api/geocode/json?

可以参阅
谷歌开发人员指南
进行参数的增添修改,就不在这里指出了,值得注意的是这里有个language的语言属性,我们想要返回中文添加参数language=zh-CN
以韩国首尔经纬度为例,json返回结果:

{
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "101-41",
               "short_name" : "101-41",
               "types" : [ "political", "premise" ]
            },
            {
               "long_name" : "Garwol-dong",
               "short_name" : "Garwol-dong",
               "types" : [ "political", "sublocality", "sublocality_level_2" ]
            },
            {
               "long_name" : "Yongsan-gu",
               "short_name" : "Yongsan-gu",
               "types" : [ "political", "sublocality", "sublocality_level_1" ]
            },
            {
               "long_name" : "Seoul",
               "short_name" : "Seoul",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "韩国",
               "short_name" : "KR",
               "types" : [ "country", "political" ]
            },
            {
               "long_name" : "140-150",
               "short_name" : "140-150",
               "types" : [ "postal_code" ]
            }
         ],
         "formatted_address" : "101-41 Garwol-dong, Yongsan-gu, Seoul, 韩国",
         "geometry" : {
            "location" : {
               "lat" : 37.54168790000001,
               "lng" : 126.9725497
            },
            "location_type" : "ROOFTOP",
            "viewport" : {
               "northeast" : {
                  "lat" : 37.54303688029151,
                  "lng" : 126.9738986802915
               },
               "southwest" : {
                  "lat" : 37.54033891970851,
                  "lng" : 126.9712007197085
               }
            }
         },
         "place_id" : "ChIJJb_bI2uifDUR2iMpuxB-8nk",
         "types" : [ "political", "premise" ]
      },
      {
         "address_components" : [
            {
               "long_name" : "Hangang-daero",
               "short_name" : "Hangang-daero",
               "types" : [ "political", "sublocality", "sublocality_level_4" ]
            },
            {
               "long_name" : "Yongsan-gu",
               "short_name" : "Yongsan-gu",
               "types" : [ "political", "sublocality", "sublocality_level_1" ]
            },
            {
               "long_name" : "汉城",
               "short_name" : "汉城",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "Seoul",
               "short_name" : "Seoul",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "韩国",
               "short_name" : "KR",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "Hangang-daero, Yongsan-gu, Seoul, 韩国",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 37.55429470000001,
                  "lng" : 126.9749276
               },
               "southwest" : {
                  "lat" : 37.5228766,
                  "lng" : 126.9620252
               }
            },
            "location" : {
               "lat" : 37.5359824,
               "lng" : 126.9713509
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 37.55429470000001,
                  "lng" : 126.9749276
               },
               "southwest" : {
                  "lat" : 37.5228766,
                  "lng" : 126.9620252
               }
            }
         },
         "place_id" : "ChIJL5DexhOifDURWBfn8qBML-Q",
         "types" : [ "political", "sublocality", "sublocality_level_4" ]
      },
      {
         "address_components" : [
            {
               "long_name" : "Garwol-dong",
               "short_name" : "Garwol-dong",
               "types" : [ "political", "sublocality", "sublocality_level_2" ]
            },
            {
               "long_name" : "Yongsan-gu",
               "short_name" : "Yongsan-gu",
               "types" : [ "political", "sublocality", "sublocality_level_1" ]
            },
            {
               "long_name" : "汉城",
               "short_name" : "汉城",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "Seoul",
               "short_name" : "Seoul",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "韩国",
               "short_name" : "KR",
               "types" : [ "country", "political" ]
            },
            {
               "long_name" : "140-150",
               "short_name" : "140-150",
               "types" : [ "postal_code" ]
            }
         ],
         "formatted_address" : "Garwol-dong, Yongsan-gu, Seoul, 韩国",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 37.549912,
                  "lng" : 126.97553
               },
               "southwest" : {
                  "lat" : 37.5394515,
                  "lng" : 126.9707327
               }
            },
            "location" : {
               "lat" : 37.5473301,
               "lng" : 126.9722574
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 37.549912,
                  "lng" : 126.97553
               },
               "southwest" : {
                  "lat" : 37.5394515,
                  "lng" : 126.9707327
               }
            }
         },
         "place_id" : "ChIJUaBoK2qifDURsVR938xIY0M",
         "types" : [ "political", "sublocality", "sublocality_level_2" ]
      },
      {
         "address_components" : [
            {
               "long_name" : "Namyeong-dong",
               "short_name" : "Namyeong-dong",
               "types" : [ "political", "sublocality", "sublocality_level_2" ]
            },
            {
               "long_name" : "Yongsan-gu",
               "short_name" : "Yongsan-gu",
               "types" : [ "political", "sublocality", "sublocality_level_1" ]
            },
            {
               "long_name" : "汉城",
               "short_name" : "汉城",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "Seoul",
               "short_name" : "Seoul",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "韩国",
               "short_name" : "KR",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "Namyeong-dong, Yongsan-gu, Seoul, 韩国",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 37.5548939,
                  "lng" : 126.9803823
               },
               "southwest" : {
                  "lat" : 37.5340845,
                  "lng" : 126.9690066
               }
            },
            "location" : {
               "lat" : 37.5455655,
               "lng" : 126.9744151
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 37.5548939,
                  "lng" : 126.9803823
               },
               "southwest" : {
                  "lat" : 37.5340845,
                  "lng" : 126.9690066
               }
            }
         },
         "place_id" : "ChIJ98WRHWqifDURY67M57zL0S0",
         "types" : [ "political", "sublocality", "sublocality_level_2" ]
      },
      {
         "address_components" : [
            {
               "long_name" : "龙山区",
               "short_name" : "龙山区",
               "types" : [ "political", "sublocality", "sublocality_level_1" ]
            },
            {
               "long_name" : "汉城",
               "short_name" : "汉城",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "首尔",
               "short_name" : "首尔",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "韩国",
               "short_name" : "KR",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "韩国汉城龙山区",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 37.555498,
                  "lng" : 127.0180284
               },
               "southwest" : {
                  "lat" : 37.5055435,
                  "lng" : 126.943906
               }
            },
            "location" : {
               "lat" : 37.5384272,
               "lng" : 126.9654442
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 37.555498,
                  "lng" : 127.0180284
               },
               "southwest" : {
                  "lat" : 37.5055435,
                  "lng" : 126.943906
               }
            }
         },
         "place_id" : "ChIJ0z8xfjyifDURF7H5KqUsNKQ",
         "types" : [ "political", "sublocality", "sublocality_level_1" ]
      },
      {
         "address_components" : [
            {
               "long_name" : "汉城",
               "short_name" : "汉城",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "首尔",
               "short_name" : "首尔",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "韩国",
               "short_name" : "KR",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "韩国汉城",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 37.7017495,
                  "lng" : 127.1835899
               },
               "southwest" : {
                  "lat" : 37.4259627,
                  "lng" : 126.7645827
               }
            },
            "location" : {
               "lat" : 37.566535,
               "lng" : 126.9779692
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 37.6956,
                  "lng" : 127.1823
               },
               "southwest" : {
                  "lat" : 37.4346,
                  "lng" : 126.7968
               }
            }
         },
         "place_id" : "ChIJzWXFYYuifDUR64Pq5LTtioU",
         "types" : [ "locality", "political" ]
      },
      {
         "address_components" : [
            {
               "long_name" : "140-150",
               "short_name" : "140-150",
               "types" : [ "postal_code" ]
            },
            {
               "long_name" : "Garwol-dong",
               "short_name" : "Garwol-dong",
               "types" : [ "political", "sublocality", "sublocality_level_2" ]
            },
            {
               "long_name" : "Yongsan-gu",
               "short_name" : "Yongsan-gu",
               "types" : [ "political", "sublocality", "sublocality_level_1" ]
            },
            {
               "long_name" : "汉城",
               "short_name" : "汉城",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "Seoul",
               "short_name" : "Seoul",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "韩国",
               "short_name" : "KR",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "Garwol-dong, Yongsan-gu, Seoul, 韩国",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 37.549912,
                  "lng" : 126.97553
               },
               "southwest" : {
                  "lat" : 37.5394515,
                  "lng" : 126.9707327
               }
            },
            "location" : {
               "lat" : 37.5460327,
               "lng" : 126.9722407
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 37.549912,
                  "lng" : 126.97553
               },
               "southwest" : {
                  "lat" : 37.5394515,
                  "lng" : 126.9707327
               }
            }
         },
         "place_id" : "ChIJUaBoK2qifDURKKoMkEX5m-M",
         "types" : [ "postal_code" ]
      },
      {
         "address_components" : [
            {
               "long_name" : "首尔",
               "short_name" : "首尔",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "汉城",
               "short_name" : "汉城",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "韩国",
               "short_name" : "KR",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "韩国首尔",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 37.7017495,
                  "lng" : 127.1835899
               },
               "southwest" : {
                  "lat" : 37.4259627,
                  "lng" : 126.7645827
               }
            },
            "location" : {
               "lat" : 37.566535,
               "lng" : 126.9779692
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 37.7017495,
                  "lng" : 127.1835899
               },
               "southwest" : {
                  "lat" : 37.4259627,
                  "lng" : 126.7645827
               }
            }
         },
         "place_id" : "ChIJzzlcLQGifDURm_JbQKHsEX4",
         "types" : [ "administrative_area_level_1", "political" ]
      },
      {
         "address_components" : [
            {
               "long_name" : "韩国",
               "short_name" : "KR",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "韩国",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 38.63400000000001,
                  "lng" : 131.1603
               },
               "southwest" : {
                  "lat" : 33.0041,
                  "lng" : 124.5863
               }
            },
            "location" : {
               "lat" : 35.907757,
               "lng" : 127.766922
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 38.63400000000001,
                  "lng" : 131.1603
               },
               "southwest" : {
                  "lat" : 33.0041,
                  "lng" : 124.5863
               }
            }
         },
         "place_id" : "ChIJm7oRy-tVZDURS9uIugCbJJE",
         "types" : [ "country", "political" ]
      }
   ],
   "status" : "OK"
}

它返回了多个数组,地址将按照具体程度由高到低的顺序返回;最确切的地址将作为最显著的结果,你需要解析拿到自己最想的数据。

OSM逆地理编码

OSM就是OpenStreetMap,维基世界地图,一个开源的在线地图项目,包括软件和地图数据。官方网址:OpenStreetMap,同样,使用OSM逆地理编码国外坐标,我们也不需要安装其SDK,直接使用它的API,文档如下

http://wiki.openstreetmap.org/wiki/Nominatim#Reverse_Geocoding

值得注意的是,它的参数中有一个zoom对象,根据你设置的zoom大小来返回数据信息,zoom可以设置 0-18之间的数字,0代表国家,18代表房屋细节等。
这里我们使用zoom=15来返回数据如下:

{
  "place_id": "173520939",
  "licence": "Data © OpenStreetMap contributors, ODbL 1.0. http:\/\/www.openstreetmap.org\/copyright",
  "osm_type": "relation",
  "osm_id": "3884169",
  "lat": "37.53768915",
  "lon": "126.967325078037",
  "display_name": "원효로1동 (Wonhyoro 1-dong), 원효로동 (Wonhyoro-dong), Yongsan-gu, 首尔特别市, 韩国",
  "address": {
    "city_district": "원효로1동 (Wonhyoro 1-dong)",
    "city": "首尔特别市",
    "town": "Yongsan-gu",
    "country": "韩国",
    "country_code": "kr"
  },
  "boundingbox": [
    "37.5331412",
    "37.5421558",
    "126.9600356",
    "126.9711928"
  ]
}

它所返回的数据,虽然没有看到设置的返回语言,但是我在韩国的时候,真机测试,返回的语言为中文,可能根据手机系统语言设置有关。
我查看了关于OSM的许可证书,至少不修改它的地图只是用它逆地理编码,并不会涉及到法律问题。

总结如下

  • 1.苹果自带的CLGeocoder在国外逆地理编码时候并不好用,经常解析失败。使用的话注意定义全局变量,返回的数据语言是否是随手机设置语言还有待考证,至少我身在韩国的时候返回的是当地语言。
  • 2.使用谷歌逆地理编码,返回的数据注意解析它精确度及语言设置。对于我只想要中文的,返回数据并不算好用。
  • 3.OSM的逆地理编码,注意甚至zoom,不修改它源码情况下,只是用api,并不涉及法律问题。

如上。
若有问题和更好的解决方法,请留言,谢谢。

文 / 丶伊眸冷
LEAVE A REPLY
总访问数 16
loading