Profile

생각정리..

Lunight

[iOS] CoreLocation 위치서비스(CoreLocation + google places API)




환경


OS : macOS High Sierra 10.13.3


Xcode : 9.2(9C40b) 


0. Project 생성


iOS App - Ojbective-C로 선택



1. CoreLocation Framework 추가


[Build Phases] - [Link Binary With Libraries]에 CoreLocation.framework를 추가



2. 위치기반허용


기기의 위치정보는 개인정보이기 때문에 반드시 필요하다.



3. Source code


ViewController.h



#import <UIKit/UIKit.h>


#import <CoreLocation/CoreLocation.h>


@interface ViewController : UIViewController <CLLocationManagerDelegate>{

    

    IBOutlet UITextView     *loclogview;

    

    IBOutlet UITextField    *corelocation_address;

    

}


@end



ViewController.m



#import "ViewController.h"


@interface ViewController ()


@property (nonatomic , strong) CLLocationManager *locationManager;


@end


@implementation ViewController


- (void)viewDidLoad {

    

    [super viewDidLoad];


    // Do any additional setup after loading the view, typically from a nib.

    

    self.locationManager = [[CLLocationManager alloc]init];

    self.locationManager.delegate = self;

    

    // 사용중에만 위치 정보 요청

    if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])

    {

        [self.locationManager requestWhenInUseAuthorization];

    }

    

    //    // 항상 위치 정보 사용 요청

    //    if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])

    //    {

    //        [self.locationManager requestAlwaysAuthorization];

    //    }

    



    corelocation_address.text = @"";


}



-(void)logAddView:(NSString *)log{

    

    NSDate                       *localDate;

    NSDateFormatter              *dateFormatter = [[NSDateFormatter alloc]init];

    NSDateFormatter              *timeFormatter = [[NSDateFormatter alloc]init];

    

    localDate = [NSDate date];

    

    dateFormatter.dateFormat = @"MM/dd/yy";

    timeFormatter.dateFormat = @"HH:mm:ss";

    

    NSString *tmr = [NSString stringWithFormat:@"[%@__%@]",

                     [dateFormatter stringFromDate:localDate],[timeFormatter stringFromDate:localDate]];

    

    [loclogview insertText:[NSString stringWithFormat:@"%@  :   %@\n",tmr,log]];

    

}


-(IBAction)btn_CoreLocation_Address:(id)sender{

    

    CLGeocoder* geocoder = [[CLGeocoder alloc] init];

    

    

    [geocoder geocodeAddressString:corelocation_address.text

                 completionHandler:^(NSArray *placemarks, NSError *error)

     

     {

         

         //        NSLog(@"%@",[placemarks description]);

         

         NSLog(@"plcaemarks count = %lu",(unsigned long)[placemarks count]);

         

         if ([placemarks count] == 0) //검색결과가 아무것도 없을 때

             

         {

             

             NSLog(@"result = nil");

             

             //경고창

                             [self logAddView:@"[btn_CoreLocation_Address] 주소의 검색결과를 찾을수 없습니다. 위도 : 0.0 // 경도 : 0.0"];

             

             return ;

             

         }

         

         else

             

         {

             

             CLPlacemark* p = [placemarks objectAtIndex:0]; //첫번째 검색결과 사용

             

             CLCircularRegion* region = (CLCircularRegion *)p.region;

             //             region.center.latitude

             //             region.center.longitude

                             [self logAddView:[NSString stringWithFormat:@"[btn_CoreLocation_Address] 주소 : %@ 위도 : %f // 경도 : %f" ,

                   corelocation_address.text,region.center.latitude,region.center.longitude ]];

             

         }


     }];

    

}


-(IBAction)btn_CoreLocation_nowLocation:(id)sender{

    

    if(self.locationManager == nil)

    {

        self.locationManager = [[CLLocationManager alloc]init];

        self.locationManager.delegate = self;

    }

    

    [self.locationManager startUpdatingLocation];


//    if([CLLocationManager locationServicesEnabled])

//    {

//        [self.locationManager stopUpdatingLocation];

//    }

//    else

//    {

//       [self.locationManager startUpdatingLocation];

//    }

    

}


- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {

    

    [self logAddView:[locations lastObject]];

    

}


-(IBAction)clearLogView:(id)sender{

    

    loclogview.text = @"";

    

}



- (void)didReceiveMemoryWarning {


    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}



@end



3. 테스트 


기본적으로 테스트만 빠르게 진행하기 위해 급하게 작성


오차범위 테스트 , 구글 , 다음 API 테스트는 추후진행





4. 중간평(초반이긴하지만...)



기기의 LTE 모드 , Wi-Fi모드 .. 센서 등등 환경에 따라 굉장히 예민하게 작용되는 부분이기 때문에 추가적으로 공부가 필요한듯하다.



5. Google places API 적용해보기 


Goole Places API 홈페이지 접속

https://developers.google.com/places/ios-api/?hl=ko


프로젝트 이름을 생성하고 키를 생성해준다(키값은 따로 저장)




아래 주소에 아주아주 친절하게 써있다 그래도 따라해본다.

https://developers.google.com/places/ios-api/start?hl=ko


현재 위치정보는 다음 주소를 통해서 확인해보았다.

https://developers.google.com/places/ios-api/current-place?hl=ko


6. Source code


ViewController.h



#import <UIKit/UIKit.h>

#import <CoreLocation/CoreLocation.h>

#import <GooglePlaces/GooglePlaces.h>


@interface ViewController : UIViewController <CLLocationManagerDelegate >{

    

    IBOutlet UITextView     *loclogview;

    

    IBOutlet UITextField    *corelocation_address;

    

    GMSPlacesClient *_placesClient;

    

}


@end



ViewController.m


- (void)viewDidLoad {

    

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

    

   

    

    // google

      _placesClient = [GMSPlacesClient sharedClient];


}



-(IBAction)btn_GoogleLocation_nowLocation:(id)sender{

    

    [_placesClient currentPlaceWithCallback:^(GMSPlaceLikelihoodList *placeLikelihoodList, NSError *error){

        if (error != nil) {

            NSLog(@"Pick Place error %@", [error localizedDescription]);

            return;

        }

        

       


        if (placeLikelihoodList != nil) {

            GMSPlace *place = [[[placeLikelihoodList likelihoods] firstObject] place];

            if (place != nil) {

                

        /*

        

        ##     GMSPlace Class      ##


        name – 장소의 이름.

        placeID – 장소의 텍스트 식별자. 이 페이지의 나머지 부분에서 장소 ID에 대해 더 자세히 알아보세요.

        coordinate – 장소의 지리적 위치로, 위도와 경도 좌표로 지정됩니다.

        openNowStatus – 장소 정보를 요청했을 때 장소가 열리는지 여부를 나타냅니다.

        phoneNumber – 국제 형식의 장소 전화번호.

        formattedAddress – 사람이 읽을 수 있는 형식의 장소 주소.

        rating – 장소의 합산 평점으로, 합산 사용자 리뷰에 근거하여 1.0 ~ 5.0 범위의 값을 가진 소수로 반환됩니다.

        priceLevel – 이 장소의 가격 레벨로, 0(가장 쌈) ~ 4(가장 비쌈) 범위의 값을 가진 정수로 반환됩니다.

        types – 이 장소를 특징짓는 장소 유형 목록. 지원 유형 문서를 참조하세요.

        website – 장소의 웹사이트 URI(알려진 경우). 장소와 연관된 사업체나 기타 주체가 관리하는 웹사이트입니다.

        attributions – 앱이Google Places API for iOS에서 검색한 장소 세부정보를 사용할 경우, 사용자에게 표시해야 하는 특성이 포함된 NSAttributedString. 특성 검색 및 표시에 대한 자세한 내용은 특성 가이드를 참조하세요.

        addressComponents – 장소의 주소 구성 요소를 나타내는 GMSAddressComponent 객체의 배열입니다. 이러한 구성 요소는 장소의 주소에 대한 구조화된 정보를 추출하기 위한 목적(예: 장소가 위치한 도시 찾기)으로 제공됩니다. 주소 형식에 이 구성 요소를 사용하지 마십시오. 대신 현지화된 기본 제공 주소를 제공하는 formattedAddress 속성을 사용하십시오.

         

        */


        [self logAddView:[NSString stringWithFormat:@"google places API location : %f . %f (%@,%@)" , place.coordinate.latitude , place.coordinate.longitude ,place.name ,[[place.formattedAddress componentsSeparatedByString:@", "]                                                                                                  componentsJoinedByString:@"\n"] ]];

                

            }

        }

    }];

    

}



6. Project File


Corelocation + Google place API 적용버전


단순 테스트용

google framework 용량이 100메가 넘어서 Framework 별도로 넣고 테스트해야함


MyLocation.zip



7. Daum API 적용해보기 


DaumMap API 제공 Url


http://apis.map.daum.net/


iOS SDK 1.3.0을 다운로드하였다.(역시다...Framework)




자세한 가이드는 아래 주소에 친절하게 설명되어 있다. bundle id 등록 Key 생성.. Google과 거의 비슷한 방법이다.


http://apis.map.daum.net/ios/guide/


아래 에러가 발생하면 다음과 같이 수정한다. 



[Build Settings] - [Enable Bitcode] -> No 변경할것


 

설명대로 적용하면 delegate가 정상적으로 동작하지 않는데 MTMap...이 아니라 mapView로 바뀌었고 델리게이트가 정상적으로 잘 동작하지 않았다.

- (void)MTMapView:(MTMapView *)mapView centerPointMovedTo:(MTMapPoint *)mapCenterPoint {

    

//    [self.eventResultLabel setText:[NSString stringWithFormat:@"Camera Position: lat:%f, lng: %f", mapCenterPoint.mapPointGeo.latitude, mapCenterPoint.mapPointGeo.longitude]];

    NSLog(@"%@",[NSString stringWithFormat:@"Camera Position: lat:%f, lng: %f", mapCenterPoint.mapPointGeo.latitude, mapCenterPoint.mapPointGeo.longitude]);

}


하지만 지도에 현재위치를 가져오는건 성공!

-(void)viewDidAppear:(BOOL)animated{

    

    MTMapPOIItem* poiItem1 = [MTMapPOIItem poiItem];

    poiItem1.itemName = @"City on a Hill";

    poiItem1.mapPoint = [MTMapPoint mapPointWithGeoCoord:MTMapPointGeoMake(37.541889,127.005470)];

    poiItem1.markerType = MTMapPOIItemMarkerTypeBluePin;

    poiItem1.showAnimationType = MTMapPOIItemShowAnimationTypeDropFromHeaven;

    poiItem1.draggable = YES;

    poiItem1.tag = 153;

    

    [mapView addPOIItems:[NSArray arrayWithObjects:poiItem1,nil]];

    [mapView fitMapViewAreaToShowAllPOIItems];

    

    MTMapCircle *circle = [MTMapCircle circle];

    circle.circleCenterPoint = [MTMapPoint mapPointWithGeoCoord:MTMapPointGeoMake(37.541889, 127.005470)];

    circle.circleLineColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.5];

    circle.circleFillColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.5];

    circle.circleRadius = 300;

    

    [mapView addCircle:circle];

    [mapView fitMapViewAreaToShowCircle:circle];

    

    [mapView currentLocationTrackingMode];

    [mapView setCurrentLocationTrackingMode:MTMapCurrentLocationTrackingOnWithHeading];

}




8. 정리


일단 위치정보를 가져오는 중요한 이유는 바로 현재 위치 또는 원하는 곳의 지역정보를 확인하기 위함인데 Google , 카카오 , Corelocation 세가지를 테스트해본 결과 


Google은 자체적으로 위도 경도를 구하는 메서드가 있는것 같은데 카카오는 CoreLocation으로 현재 위치를 가져오는 것 같았다. 

근데 Google Place API를 적용할때도 Corelocation.Framework가 기본적으로 추가하라고 나오는것 보니... 구글도 Corelocation으로 정보를 가져오는 것 같기도 하다(추측)




2018-03-08 15:35:27.965508+0900 MyLocation[2260:2425251] Info: core location updates new location ... <+37.57526932,+126.88835749> +/- 65.00m (speed -1.00 mps / course -1.00) @ 2018. 3. 8. 오후 3 35 27 대한민국 표준시


카카오 API로 실시간 지도를 확인할때 로그에 다음과 같이 Corelocation log가 남았다.


지도 표기는 카카오가 정확한것 같아 한개의 프로젝트에 카카오(지도) + Corelocation(위도경도정보) + Google(비교자료용)으로 

테스트 app으로 작업을 해보자 



9. SourceCode


ViewController.h



#import <UIKit/UIKit.h>

#import <CoreLocation/CoreLocation.h>

#import <GooglePlaces/GooglePlaces.h>

#import <DaumMap/MTMapView.h>

#import <DaumMap/MTMapGeometry.h>

#import <DaumMap/MTMapPOIItem.h>

#import <DaumMap/MTMapPolyline.h>



#import <DaumMap/MTMapView.h>

#import <DaumMap/MTMapCameraUpdate.h>

#import <DaumMap/MTMapReverseGeoCoder.h>


@interface ViewController : UIViewController <CLLocationManagerDelegate , MTMapViewDelegate , MTMapReverseGeoCoderDelegate>{

    

    IBOutlet UITextView     *loclogview;

    

    IBOutlet UITextField    *corelocation_address;

    

    GMSPlacesClient *_placesClient;

    MTMapView       *mapView;


    

}

@end


ViewController.m



#import "ViewController.h"


@interface ViewController ()


@property (nonatomic , strong) CLLocationManager *locationManager;


@end



@implementation ViewController


- (void)viewDidLoad {

    

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

    

    self.locationManager = [[CLLocationManager alloc]init];

    self.locationManager.delegate = self;

    

    // 사용중에만 위치 정보 요청

    if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])

    {

        [self.locationManager requestWhenInUseAuthorization];

    }

    

    //    // 항상 위치 정보 사용 요청

    //    if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])

    //    {

    //        [self.locationManager requestAlwaysAuthorization];

    //    }

    

    // google

      _placesClient = [GMSPlacesClient sharedClient];


    corelocation_address.text = @"";


    // Daum

    mapView = [[MTMapView alloc]init];

    mapView = [[MTMapView alloc] initWithFrame:CGRectMake(10, 84, 300, 300)];

    mapView.delegate = self;

    mapView.baseMapType = MTMapTypeStandard;


    [self.view addSubview:mapView];

    

   

}



-(void)viewDidAppear:(BOOL)animated{

    

    [mapView currentLocationTrackingMode];

    [mapView setCurrentLocationTrackingMode:MTMapCurrentLocationTrackingOnWithHeading];


}


- (void)viewWillDisappear:(BOOL)animated {

    if (mapView != nil) {

        mapView = nil;

    }

}



-(IBAction)btn_CoreLocation_Address:(id)sender{

    

    if([corelocation_address.text isEqualToString:@""])

    {

        [loclogview insertText:@"주소를 입력해주세요\n"];

    }

    else

    {

        CLGeocoder* geocoder = [[CLGeocoder alloc] init];

        

        [geocoder geocodeAddressString:corelocation_address.text

                     completionHandler:^(NSArray *placemarks, NSError *error)

         

         {

             

             //        NSLog(@"%@",[placemarks description]);

             

             NSLog(@"plcaemarks count = %lu",(unsigned long)[placemarks count]);

             

             if ([placemarks count] == 0) //검색결과가 아무것도 없을 때

                 

             {

                 

                 NSLog(@"result = nil");

                 

                 //경고창

                 [self logAddView:@"[btn_CoreLocation_Address] 주소의 검색결과를 찾을수 없습니다. 위도 : 0.0 // 경도 : 0.0"];

                 

                 return ;

                 

             }

             

             else

                 

             {

                 

                 CLPlacemark* p = [placemarks objectAtIndex:0]; //첫번째 검색결과 사용

                 

                 CLCircularRegion* region = (CLCircularRegion *)p.region;

                 

                 //             region.center.latitude

                 //             region.center.longitude


                 [self logAddView:[NSString stringWithFormat:@"[btn_CoreLocation_Address] 주소 : %@ 위도 : %f // 경도 : %f" ,

                                   corelocation_address.text,region.center.latitude,region.center.longitude ]];

                 

             }

         }];

    }

    

}


-(IBAction)btn_CoreLocation_nowLocationStart:(id)sender{


    [self.locationManager startUpdatingLocation];

    [self logAddView:@"iOS Corelocation location start"];

}


-(IBAction)btn_CoreLocation_nowLocationStop:(id)sender{

    

    [self.locationManager stopUpdatingLocation];

    [self logAddView:@"iOS Corelocation location stop"];


}



- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {

    

    if([locations count] != 0)

    {

        for(int i=0 ; i < [locations count] ; i++)

        {

            //        CLLocation *currentLocation = [locations lastObject];

            CLLocation *currentLocation = [locations objectAtIndex:i];

            [self logAddView:[NSString stringWithFormat:@"iOS Corelocation location : %f , %f" , currentLocation.coordinate.latitude , currentLocation.coordinate.longitude]];

            

        }

        

    }

    

//    CLGeocoder *geocoder  = [[CLGeocoder alloc]init];

//    [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {

//        if(!error)

//        {

//            CLPlacemark *placemark = [placemarks lastObject];

//            NSString *placemarkAt = [NSString stringWithFormat:@"\ncountry : %@\nthoroughfare : %@\nsubThoroughfare : %@\npostalCode :  %@\npostalAddress :  %@\npostalCode :  %@\nlocality : %@\nadministrativearea : %@",

//                                     placemark.country,

//                                     placemark.thoroughfare,

//                                     placemark.subThoroughfare,

//                                     placemark.postalCode,

//                                     placemark.postalAddress,

//                                     placemark.postalCode,

//                                     placemark.locality,

//                                     placemark.administrativeArea

//                                     ];

//

//            [self logAddView:[NSString stringWithFormat:@"iOS Corelocation location : %f , %f" , currentLocation.coordinate.latitude , currentLocation.coordinate.longitude]];

//            [self logAddView:[NSString stringWithFormat:@"%@",placemarkAt]];

//

//

//        }

//    }];

}



-(IBAction)btn_GoogleLocation_nowLocation:(id)sender{


    [self logAddView:@"지금은 사용할 수 없습니다.(Google places api)"]; 

        return;

    

        [_placesClient currentPlaceWithCallback:^(GMSPlaceLikelihoodList *placeLikelihoodList, NSError *error){


        if (error != nil) {


            NSLog(@"Pick Place error %@", [error localizedDescription]);


            return;


        }


        if (placeLikelihoodList != nil) {


            GMSPlace *place = [[[placeLikelihoodList likelihoods] firstObject] place];


            if (place != nil) {




                /*




                 ##     GMSPlace Class      ##




                 name – 장소의 이름.


                 placeID – 장소의 텍스트 식별자. 이 페이지의 나머지 부분에서 장소 ID에 대해 더 자세히 알아보세요.


                 coordinate – 장소의 지리적 위치로, 위도와 경도 좌표로 지정됩니다.


                 openNowStatus – 장소 정보를 요청했을 때 장소가 열리는지 여부를 나타냅니다.


                 phoneNumber – 국제 형식의 장소 전화번호.


                 formattedAddress – 사람이 읽을 수 있는 형식의 장소 주소.


                 rating – 장소의 합산 평점으로, 합산 사용자 리뷰에 근거하여 1.0 ~ 5.0 범위의 값을 가진 소수로 반환됩니다.


                 priceLevel – 이 장소의 가격 레벨로, 0(가장 쌈) ~ 4(가장 비쌈) 범위의 값을 가진 정수로 반환됩니다.


                 types – 이 장소를 특징짓는 장소 유형 목록. 지원 유형 문서를 참조하세요.


                 website – 장소의 웹사이트 URI(알려진 경우). 장소와 연관된 사업체나 기타 주체가 관리하는 웹사이트입니다.


                 attributions – 앱이Google Places API for iOS에서 검색한 장소 세부정보를 사용할 경우, 사용자에게 표시해야 하는 특성이 포함된 NSAttributedString. 특성 검색 및 표시에 대한 자세한 내용은 특성 가이드를 참조하세요.


                 addressComponents – 장소의 주소 구성 요소를 나타내는 GMSAddressComponent 객체의 배열입니다. 이러한 구성 요소는 장소의 주소에 대한 구조화된 정보를 추출하기 위한 목적(예: 장소가 위치한 도시 찾기)으로 제공됩니다. 주소 형식에 이 구성 요소를 사용하지 마십시오. 대신 현지화된 기본 제공 주소를 제공하는 formattedAddress 속성을 사용하십시오.




                 */




                [self logAddView:[NSString stringWithFormat:@"google places API location : %f . %f (%@,%@)" , place.coordinate.latitude , place.coordinate.longitude ,place.name ,[[place.formattedAddress componentsSeparatedByString:@", "]                                                                                                  componentsJoinedByString:@"\n"] ]];




            }


        }

    

    }];


    

}


-(IBAction)clearLogView:(id)sender{

    

    loclogview.text = @"";

    

}



- (void)didReceiveMemoryWarning {

    

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}



-(void)logAddView:(NSString *)log{

    

    NSDate                       *localDate;

    NSDateFormatter              *dateFormatter = [[NSDateFormatter alloc]init];

    NSDateFormatter              *timeFormatter = [[NSDateFormatter alloc]init];

    

    localDate = [NSDate date];

    

    dateFormatter.dateFormat = @"MM/dd/yy";

    timeFormatter.dateFormat = @"HH:mm:ss";

    

    NSString *tmr = [NSString stringWithFormat:@"[%@__%@]",

                     [dateFormatter stringFromDate:localDate],[timeFormatter stringFromDate:localDate]];

    

    [loclogview insertText:[NSString stringWithFormat:@"%@  :   %@\n",tmr,log]];

    

}

@end











'Apple > Objective - C' 카테고리의 다른 글

[Objective C] base64EncodedStringWithOptions  (0) 2018.09.27
[iOS] NetworkExtension  (0) 2018.03.07