Core Location, CLLocationManager, CLLocationManagerDelegate

Jake Yeon·2021년 1월 21일
0

iOS

목록 보기
4/5
post-thumbnail

iOS 기기에서 사용자의 위치 정보를 사용하려면 어떻게 해야할까?

우리가 사용하는 앱 중에서는 사용자의 위치를 추적하거나, 현재 위치를 사용하는 앱들이 있다.
예를 들면 NikeRun과 같이 사용자의 위치를 추적하는 앱,
지도 앱에서 검색을 하고 현재 위치 근처에서 결과보기와 같이 현재 위치를 사용하는 앱이 있다.

그렇다면 이러한 기능은 어떻게 구현해야할까?
이번 포스팅에서 알아보자.
(실제로 코드를 사용한 구현보다는 사용하는 framework, class, protocol등에 관련해서 나옵니다.)
참고에 있는 공식문서들을 기반으로 작성했습니다.

Core Location Framework

Core Location은 Framework로 기기의 지리적인 location이나 orientation을 획득하는데 사용한다.
Core Location은 deivce의 지리적인 위치, 고도, 방향 그리고 주변의 iBeacon 기계의 위치까지 제공해준다.
이 Framework는 사용 가능한 device의 구성요소들을 이용하여 데이터를 얻는데 Wi-Fi, GPS, Bluetooth, magneotmeter, barometer, 핸드폰의 하드웨어들을 이용한다.

CLLocationmanger 클래스 객체를 활용하여 Core Location 서비스를 구성하고, 시작하고 중지할 수 있다.
location manager 객체는 다음과 같은 location과 관련된 활동들을 지원해준다.

  • Standard and significant location updates : 사용자의 현재 위치에서 크고 작은 사항들을 각도 단위의 정확도로 추적한다.
  • Region monitoring : 관심있는 특별한 지역을 모니터링 하다가 해당 지역을 벗어나거나 들어갈 때 이벤트를 발생시킬 수 있다.
  • Beacon ranging : 근처에 있는 비콘을 탐지하고 찾는다.
  • Compass headings : 나침반의 가르키는 방향의 변화를 보고해준다.

그러나 이러한 location service를 활용하기 위해서는 사용자한테 권한을 물어봐야한다. (승인이나 거절이 가능한)

iOS 기계에서는 location service는 Setting에서 모든 앱들이나 특정한 앱들로 들어가서 설정을 변경할 수 있다.
만약 사용자가 앱의 권한 설정을 중간에 변경하는 경우에는 CLLocationManagerDelegate 프로토콜을 채택한 location manager의 delegate 객체에 의해서 앱의 권한이 변경되었다는 이벤트를 받게된다.

Adding Location Services to Your App

그렇다면 앱에 location service를 적용하려면 어떻게 해야할까?

먼저 CLLocationManager와 delegate를 사용해야하며 앱에 필요한 권한 모드를 결정해야한다.
그리고 나서 앱이 실행되면 해당 기기가 location service를 지원하는지 검사하고,
지원한다면 location service를 구성하고 시작하게 된다.

또한 이때 사용자로부터 사용자의 위치를 사용해도 괜찮냐는 권한을 물어보게 된다.
승인을 받는다면 이제 앱은 Core Location service에 필요한 location event들을 받기 시작하게 된다.

Determine If the User's Device Supports Location Services

Core Location 서비스의 경우에는 모든 기기에서 지원하는 것이 아닌 특정 기기에서만 지원한다.
따라서 먼저 해당 기기가 Core Location Service를 지원하는지에 대한 검사부터
아래의 함수를 실행해서 확인해보자.
만약 함수의 return 값이 거짓이라면, 해당 기기는 서비스를 지원받지 못하는 것이다.

  • SignificantLocationChangeMonitoringAvailable() : significant-change location service를 활용해서 사용자 위치를 얻을 수 있는지 판단
  • isMonitoringAvailable(for :) : 해당 기기가 특별 지역이나 비콘의 범위에서 들어갔다, 나갔다를 인식할 수 있는지 판단
  • headingAvailable() : 해당 기기가 나침반을 사용하여 가르킬 수 있는지에 대한 여부를 판단
  • isRangingAvailable() : 근처의 iBeacon 기기 위치를 찾을 수 있는지 판단

만약 앱이 하드웨어적인 성능이 부족한 기기에 대해서 서비스를 지원하지 못한다면
해당 서비스를 Info.plist의 필수 조건에 넣어두면 된다. 그러면 성능이 안되는 앱들은 사용이 불가능하다.

Create the Location Manager and Delegate

CLLocationManager 클래스 객체를 생성하고 앱의 어딘가에 strong reference 상태로 저장해야한다.
해당 객체가 수행해야하는 업무가 끝날 때까지 location manager 객체는
strong reference를 유지하고 있어야만 한다.
왜냐하면 대부분의 location manager 업무들은 비동기적으로 실행되기 때문에 지역변수로 location manager를 가지고 있는것은 비 효율적이다.

CLLocationManagerDelegate 프로토콜을 준수하는 delegate property에 커스텀 객체를 할당해야한다.
그리고 delegate는 location service들을 시작하기 전에 할당되어야한다.
시스템은 해당 위치 서비스를 시작한 스레드에서 delegate 객체 메서드를 호출한다.
그리고 이 thread는 앱의 main thread와 같이 스스로 active한 run loop를 가져야만 한다.

Handle Errors in the Delegate Methods

해당 기기에서 location servicer 실행이 안 될 경우를 대비해서
delegate에 실패에 관련된 메서드들을 구현해야한다.

만약 사용할 수 없는 서비스를 시작하려고 한다면 CLLocationManager 객체는
delegate 실패에 관련된 메서드를 호출하게 된다.

예를 들어 region monitoring이 불가능하다면, 객체는 locationManager(_:monitoringDidFailFor:withError:)메서드를 호출한다.

따라서 만약 앱이 특정 location service를 사용하지 못한다면 저러한 delegate 실패 함수를 통해서
UI에 알맞은 업데이트를 해줄 수 있다.

Ask for Authorization and Handle Changes

앱이 필요한 권한 상태를 결정해야한다.
그리고 사용자가 앱에서 위치 관련 기능에 접근할 때 위치 서비스를 사용할 수 있는 권한을 요청해야한다.

이러한 요청에는 다음과 같은 종류들이 있다. 이에 대해서는 나중에 한 번 더 다룰 예정이다.

  • When In Use
  • Always

delegate의 locationManager(_:didChangeAuthorization:) 메서드를 구현해놓으면
location manager가 생성된 직후부터 앱의 권한 상태가 변경되면 알림
을 주게 된다.

따라서 이 메서드를 사용해서 각각의 권한 상태에 알맞은 기능을 하도록 구현하면된다.
예를 들어서 권한이 바뀌었을 때 location service를 on/off 하도록 할 수 있을 것이다.

Start Location Services and Receive Evnets

CLLocationManager 객체의 메서드를 사용하기 전에 반드시 delegate 객체를 설정해야한다.

그리고 나서 반드시

  • call the appropriate method in CLLocationManager to start the delivery of events
    (이벤트들을 전달 시작하기 위해서 적절한 CLLocationManager의 함수를 호출해야한다.)

  • Receive location and heading related updates in the associated delegate object
    (location을 받고 delegate 객체에서 관련된 업데이트를 해준다.)

  • Call the appropriate method in CLLocationManager to stop the service when your app no longer needs to receive the location event
    (만약 더 이상 앱에서 위치 정보를 받을 필요가 없다면 service를 중지해주는 CLLocationManager 메서드를 호출해야한다.)

사용하는 서비스의 경우에는 해당 서비스와 관련된 속성을 정확하게 구성해라.
그리고 Core Location은 필요하지 않을 때 hardware를 껴서 전력을 관리해야한다.

예를 들어 location event의 정확도를 1km로 설정해놓는다면 location manager는
GPS hardware를 끄고 WiFi 또는 cell 라디오에 의존할 수 있는 유연성을 가지게 되어
상당한 전력 절감 효과를 얻을 수 있다.

Choosing the Location Services Authorization to Request

그렇다면 앱이 필요한 location data 권한에 대해서 알아보도록 하자.
앱에게는 2가지 요청할 수 있는 권한이 있다.

  • When In Use : app이 사용되고 있는 동안에 location service와 이벤트들을 받을 수 있다.
    일반적으로 iOS 앱들은 foreground에 있거나 background에서 위치 사용 표시가
    활성화 된 상태
    로 사용되고 있다면 in use 상태에 있다고 한다.
  • Always : 사용자가 app이 실행되는지 몰라도 location service와 이벤트들을 받을 수 있다.
    만약 app이 실행되지 않았어도 시스템이 앱을 실행시켜 event를 전달해준다.

Prefer When In Use Authorization

그렇다면 When In Use 권한이 선호되는 것에는 어떠한 것들이 있을까?
When In Use는 다음과 같은 특징들을 가진다.

  • 사용자가 앱을 사용하는 동안 사용 가능한 모든 location service에 접근한다.
    그리고 만약 사용자가 앱의 사용을 멈추면, 다시 앱을 시작할 때 까지 요청들은 모두 중단된다.
  • 만약 Xcode project에서 Background에서도 location updates를 가능하게 설정해놓는다면
    background 상태에 들어가도 location update를 받아온다.
  • location notification을 앱 시작 트리거로 사용할 수 있다.
    만약 앱이 사용자의 interaction에 의지할 수 있다면, UNLocationNotificationTrigger를 사용해서
    특정 region에 들어갔을 때 알림을 줄 수 있다. 그리고 유저가 알림을 클릭하게 되면
    시스템이 앱을 실행시키고 위치 이벤트들을 받아올 수 있다. 이러한 방법을 통해서 특정 순간에
    사용자에게 그들의 위치를 앱에 공유할 지, 하지 않을지에 대해서 결정할 수 있게 해준다.

위치 서비스는 앱이 in use 상태일 때 CLAuthorizationStatus.authorizedWhenInUse 를 가진 앱들만 사용이 가능하다. 또한 When In Use 권한을 지원하는 모든 플랫폼에서 앱은 다음과 같은 상황을 in use 상태라고 한다.

  • 앱이 foreground에서 돌아가고 있을 때
  • app이 foreground에서 사라졌지만, 이미 사용자가 시작(요청)한 현재 위치 업무에 대해서 끊내는 짧은 시간
  • app이 background location usage indicator를 보여줄 때.
    iOS에서 indicator는 스크린의 맨 위에 파란색 bar나 pill이다.

Ask for Always Authorization

그렇다면 언제 Always 권한이 필요할까?

  • 앱이 신속하게 처리할 필요가 없는 일들에 대해서 업무를 자동으로 실행할 때.
    예를 들어 사용자가 특정 위치를 들어가면 자동적으로 휴대폰 조명을 켜야하는 경우에는
    Always 권한이 필요할 것이다.
  • 다이어리 앱처럼 하루종일 수많은 위치를 기록할 때.
    사용자는 Always 권한을 주어서 사용을 하지 않을 때에도 사용자에게 알림을
    띄워서 권한을 물어보는 것보다는, 물어보지 않고 기록 하는 것을 선호할 것이다.

물론 명심해야할 것은 Always 권한을 항상 묻는다고 사용자로 부터 승인이 되는 것이 아니다.
따라서 항상 When In Use 권한을 선택하였을 경우에 대해서도 준비를 해야한다.

앱이 사용자로 부터 When In Use 으로 요청을 받은 경우에는
나중에 다시 앱을 켜거나 할 때 또 Always 권한에 대해서 요청을 해볼 수는 있다.

그러나 앱은 Always 요청을 받는 경우에는 단 한번만 요청을 물어보게 된다.
(즉 이후에 앱을 다시 켜도 물어보지 않는다. )

iOS 12와 그 이전에 Request Authorization에 대해서는 어떠한 것들을 지원하는지
해당 사이트로 들어가서 표를 한번 확인해보자

CLLocationManager

CLLocationManager는 클래스타입이다.
앱의 location과 관련된 이벤트들의 전달을 시작하고 멈출 수 있게 하는 객체이다.
사용할 수 있는 함수의 종류가 엄청 많다.
실제로 필요할 때 참고해서 봐야할 것 같다.
👉🏻 Apple Document CLLocationManager

CLLocationManagerDelegate

CLLocationMangerDelegate는 location manager객체로부터 이벤트를 받을 때 사용하는 메서드들이다.
location manager는 이 delegate의 메서드들을 앱의 location 관련된 이벤트들을 보고할 때 사용하게 된다.
따라서 앱의 특정 객체에 이 프로토콜을 구현하고 메서드들을 사용해서 앱을 업데이트 할 수 있다.

예를 들면 지도에서 사용자의 위치를 표시하기 위해서 현재 위치가 필요할 수 있고,
사용자의 현재 위치 근처에서만 관련된 검색 결과를 반환할때도 사용할 수 있다.

location 관련된 데이터를 받을 때 항상 실패에 대해서도
핸들링할 수 있도록 구현하는 것이 매우 중요하다. ❗️❗️

Delegate 객체는 어떠한 서비스를 시작하기 전에
CLLocationmanager 객체의 delegate 프로퍼티에 할당해야한다.

Core Location은 서비스를 시작한 직후에 delegate에게 캐시에 저장된 값을 보고하고
이후에 더 최신 값을 보고할 수 있다.
따라서 데이터 객체를 사용하기 전에 수신한 모든 데이터 객체의 타임스탬프를 확인하고 사용해라!!

Info.plist

Property List Key에 NSLocationWhenInUseUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription
왜 앱이 사용자의 위치 정보에 접근해야하는지 원인을 작성해 줄 수 있다.

만약 foreground에서만 사용자의 위치에 접근하는 경우에는
NSLocationWhenInUseUsageDescription 만 작성해주면 된다.

앱이 background에서도 사용자의 위치에 접근해야하는 경우에는
NSLocationAlwaysAndWhenInUseUsageDescription 를 작성해주면 된다.

참고

  1. Apple Document Core Location
  2. Apple Document Adding Location Services to Your App
  3. Apple Document Choosing the Location Services Authorization to Request
  4. Apple Document CLLocationManager
  5. Apple Document CLLocationManagerDelegate
  6. Apple Document NSLocationWhenInUseUsageDescription
  7. Apple Document NSLocationAlwaysAndWhenInUseUsageLocation
profile
Hope to become an iOS Developer

0개의 댓글