正在進行的項目中有這樣的需求:定位獲得當前經緯度,再用百度Place API使用經緯度查詢周邊信息。這裡不需要顯示地圖,只需要定位。看似思路很順暢,做起來卻不容易。
iPhone的GPS定位(CLLocationManager)獲得的經緯坐標是基於WGS-84坐標系(世界標准),Google地圖使用的是GCJ-02坐標系(中國特色的火星坐標系),這就是為什麼獲得的經緯坐標在google地圖上會發生偏移。我項目需求是使用百度Place API,百度的經緯坐標在GCJ-02的基礎上再做了次加密,就是DB-09坐標系。就想使用百度地圖的IOS SDK,裡面的坐標系統都是一致的而不用轉換,由於不想讓項目太大,所以沒有用百度的sdk,所以另辟蹊徑了。
在網上搜索一番,有現成百度的接口轉換坐標,經試驗 從WGS-84到GCJ-02,再到DB-09,經兩次轉換後,順利獲得當前正確地理位置信息和周邊信息,當然這些信息是來自百度的。
ZYLocationManager.h
[objc] view plaincopy
- #import <Foundation/Foundation.h>
- #import <CoreLocation/CoreLocation.h>
- #import "Singleton.h"
- typedef void(^locationBlock)(CLLocationCoordinate2D coor);
- typedef void(^addressBlock)(NSString *address);
- @interface ZYLocationManager : NSObject
- singleton_interface(ZYLocationManager)
- /**
- * 獲取糾偏後的經緯度(百度地圖經緯度)
- */
- - (void) getLocationCoordinate:(locationBlock) locaiontBlock;
- /**
- * 獲取糾偏後的經緯度(百度地圖經緯度)和地址
- */
- - (void) getLocationCoordinate:(locationBlock) locaiontBlock address:(addressBlock) addressBlock;
- @end
ZYLocationManager.m
[objc] view plaincopy
- #import "ZYLocationManager.h"
- #import "AFNetworking.h"
- #define IOS_Version [[UIDevice currentDevice].systemVersion floatValue]
- @interface ZYLocationManager ()<CLLocationManagerDelegate>{
- // 保存block
- locationBlock _locationBlock;
- addressBlock _addressBlock;
- }
- @property (nonatomic, strong) CLLocationManager *lm;
- @end
- @implementation ZYLocationManager
- singleton_implementation(ZYLocationManager)
- /**
- * 懶加載
- */
- - (CLLocationManager *)lm
- {
- if (!_lm) {
- _lm = [[CLLocationManager alloc] init];
- _lm.delegate = self;
- // 定位精准度
- _lm.desiredAccuracy = kCLLocationAccuracyBest;
- // 重新定位的距離
- _lm.distanceFilter = 1000.0f;
- }
- return _lm;
- }
- /**
- * 類第一次使用的時候被調用
- */
- + (void)initialize
- {
- ZYLocationManager *manager = [self sharedZYLocationManager];
- // ios8後需要向用戶請求權限
- if (IOS_Version >= 8.0) {
- [manager.lm requestWhenInUseAuthorization];
- [manager.lm requestAlwaysAuthorization];
- }
- // 開始定位
- [manager.lm startUpdatingLocation];
- }
- #pragma mark - CLLocationManager獲取經緯度的代理方法
- - (void)locationManager:(CLLocationManager *)manager didUpdateLocationsNSArray *)locations
- {
- CLLocation *location = [locations lastObject];
- CLLocationCoordinate2D coor = location.coordinate;
- // NSLog(@"緯度:%.6f 經度%.6f", coor.latitude, coor.longitude);
- NSString *x1 = [NSString stringWithFormat:@"%f", coor.longitude];
- NSString *y1 = [NSString stringWithFormat:@"%f", coor.latitude];
- // http://api.map.baidu.com/ag/coord/convert?from=0&to=2&x=113.377346&y=23.132648
- __block NSDictionary *dict1 = @{@"from":@"0",
- @"to":@"2",
- @"x"1,
- @"y":y1
- };
- AFHTTPRequestOperationManager *roManager = [AFHTTPRequestOperationManager manager];
- // 1、ios系統經緯度(國際標准)轉谷歌經緯度
- [roManager GET:@"http://api.map.baidu.com/ag/coord/convert" parameters:dict1 success:^(AFHTTPRequestOperation *operation, id responseObject) {
- __block NSString *resultX = [self base64Decode:responseObject[@"x"]];
- __block NSString *resultY = [self base64Decode:responseObject[@"y"]];
- dict1 = @{@"from":@"2",
- @"to":@"4",
- @"x":resultX,
- @"y":resultY
- };
- // 2、谷歌經緯度轉百度經緯度
- [roManager GET:@"http://api.map.baidu.com/ag/coord/convert" parameters:dict1 success:^(AFHTTPRequestOperation *operation, id responseObject) {
- resultX = [self base64Decode:responseObject[@"x"]];
- resultY = [self base64Decode:responseObject[@"y"]];
- CLLocationCoordinate2D resultCoor = CLLocationCoordinate2DMake([resultY floatValue], [resultX floatValue]);
- // 給block賦值
- if (_locationBlock) {
- _locationBlock(resultCoor);
- }
- [self getAddressWithCoordinate:resultCoor];
- } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
- NSLog(@"%@", error);
- }];
- } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
- NSLog(@"%@", error);
- }];
- // 停止定位
- [self.lm stopUpdatingLocation];
- }
- - (void)getLocationCoordinate:(locationBlock)locaiontBlock
- {
- _locationBlock = locaiontBlock;
- }
- - (void)getLocationCoordinate:(locationBlock)locaiontBlock address:(addressBlock)addressBlock
- {
- _locationBlock = locaiontBlock;
- _addressBlock = addressBlock;
- }
- #pragma mark - base64解密
- - (NSString *)base64Decode:(NSString *)str
- {
- // 1、加密字符串轉二進制數據
- NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];
- // 2、二進制數據轉字符串
- return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- }
- #pragma mark - 經緯度轉地址
- - (void)getAddressWithCoordinate:(CLLocationCoordinate2D)coor
- {
- if (coor.latitude == 0 || coor.longitude == 0) return;
- CLLocation *loca = [[CLLocation alloc] initWithLatitude:coor.latitude longitude:coor.longitude];
- CLGeocoder *geocoder = [[CLGeocoder alloc] init];
- [geocoder reverseGeocodeLocation:loca completionHandler:^(NSArray *placemarks, NSError *error) {
- if (placemarks.count == 0 || error) return;
- CLPlacemark *pm = [placemarks lastObject];
- if (_addressBlock) {
- _addressBlock(pm.thoroughfare);
- }
- }];
- }
- @end
IOS8後,請求定位需要請求權限,代碼ZYLocationManager.m已經寫好了,不過還需要在info.plist中,添加兩個屬性NSLocationAlwaysUsageDescription和NSLocationWhenInUseUsageDescription,屬性值即是你需要提示給用戶的信息,如下圖所示:
將ZYLocationManager.h和ZYLocationManager.m拖入項目中,即可直接調用ZYLocationManager.h定義的兩個方法,獲取到百度經緯度和地址。