MapKit을 활용한 위치 기반 서비스를 개발하며 겪은 시행착오

MapKit을 활용한 위치 기반 서비스를 개발하며 겪은 시행착오

요약: 카카오페이 클라이언트팀 스위리가 MapKit 프레임워크를 활용해 위치 기반 서비스 ‘포춘레이더’와 ‘내 주변 혜택’을 개발한 경험을 공유합니다. 본 글은 MapKit 활용 시 자주 마주할 문제와 해결 방안을 제시하며, 비슷한 고충을 가진 개발자들에게 유용한 인사이트를 제공합니다.

💡 리뷰어 한줄평

napster.x 대한민국에서 공짜 지도 SDK 쓰는 방법

sean.me MapKit에 대한 레퍼런스가 많이 없어 사용을 주저한 적이 있었는데요, 글을 읽어보니 간단한 사용에는 전혀 문제없고 오히려 더 편하게 사용할 수 있겠다는 생각이 들었어요.

시작하며

안녕하세요, 카카오페이 앱의 얼굴! 홈탭과 결제탭 개발을 담당하는 클라이언트서비스팀 iOS 개발자 스위리입니다. 2024년에 지도로 시각화된 사용자 위치 기반 서비스 두 개를 릴리즈했습니다. 상반기에는 실시간 위치 정보를 활용하는 미션형 혜택 서비스인 ‘포춘레이더’를, 하반기에는 카카오페이로 결제 시 혜택을 제공하는 주변 매장을 보여주는 ‘내 주변 혜택’ 카드 작업을 진행했습니다.

포춘레이더와 결제탭 화면
포춘레이더와 결제탭 화면

도메인 관점에서 각각 혜택 그리고 결제로 두 서비스의 소속은 다릅니다. 그러나 개발 관점에서 두 서비스 모두 MapKit 프레임워크를 활용한 점은 공통점입니다. MapKit 프레임워크는 카카오페이에서 처음 도입해 보는 프레임워크이기도 하고, 특히 참고할만한 국내 서비스가 적어 개발 과정이 매끄럽지 않았습니다. 따라서 오늘 이 글에서는 MapKit 프레임워크를 사용하면서 겪은 시행착오를 공유함으로써 유사한 문제로 개발에 난항을 겪고 계신 분들에게 도움이 되고 싶습니다.

MapKit 프레임워크

iOS 네이티브 앱 개발 시 지도를 사용하고 싶다면 다양한 선택지가 있습니다. 기획에 적합해 보이는 SDK를 검토한 결과, 최종적으로 네이버 지도 SDK, 카카오 지도 SDK, MapBox, OSM, MapKit 다섯 가지 선택지가 남았습니다. 이들의 장단점을 살펴본 후 개발 환경과 조건에 가장 적합한 MapKit을 선택했습니다. 특히 비용과 한글 지원 두 가지 측면에서 검토를 진행했습니다.

고려사항

  1. 비용
    지도 SDK의 경우 기업에서 제공하는 것과 오픈소스로 나눠 볼 수 있습니다. 특히 사기업에서 제공하는 SDK는 API 호출 제한 조건이 존재합니다. 특정 조건 달성 시 호출이 막히거나 초과 사용에 대한 비용을 지불해야 합니다. 네이버 지도의 경우 월 600만 건의 API 호출을 무료로 사용할 수 있고, 카카오 지도는 그보다 조금 더 많은 수준인 일 30만 건의 호출을 지원합니다. MapBox는 해외에서 잘 알려진 SDK로(BMW 내장 내비게이션, CNN의 지리 자료 제작 등에 사용) 앞선 두 회사와 달리 일 방문자 수 25,000명까지 호출을 무료로 지원합니다.
    당시 기획에서 산정한 예상 방문자 수와 현재 DAU(Daily Active Users)를 종합적으로 고려해 봤을 때 과금 발생 가능성이 높았습니다. SDK에 사용할 수 있는 비용이 제한적이었기 때문에 네이버 지도, 카카오 지도 그리고 MapBox 모두 선택지에서 배제했습니다. 이제 OSM과 MapKit, 2개의 선택지가 남았습니다.

  2. 한글 지원
    카카오페이를 사용하는 대부분의 사용자는 한국인이기 때문에 한글 지원이 중요합니다. 언어를 지원하는 것뿐만 아니라 한글로 서비스를 제공했을 때 이질감이 없어야 합니다. 이 측면에서만 보면 네이버와 카카오 지도만 한 것도 없습니다. 남은 두 개의 선택지 중 OSM은 한글을 지원하지만 자간이 맞지 않거나 폰트가 깨지는 현상을 발견했습니다. 이런 시각적 불편함은 사용성을 해치기 때문에 최종적으로 MapKit을 선정하게 되었습니다.

  3. 그 외
    물론, MapKit이 애플의 First Party Library라는 점을 생각해 보면 MapKit을 선택하는 게 가장 합리적인 선택이라고 느꼈습니다. 어떤 SDK를 택해도 러닝 커브가 발생한다면, 지금까지 합을 맞춰 온 애플의 개발 철학이 녹아든 SDK를 사용하고 외부 의존성을 줄이는 것이 좋으니까요!

SDK비용한글 지원 시 이슈
네이버 지도OX
카카오 지도OX
MapBoxOX
OSMXO
MapKitXX

Case 1. 현재 위치를 주소로 변환하기

현재 위치를 주소로 변환하는 기술에 대해 간략히 살펴본 후 한국의 주소 체계에 맞게 변환하기 위한 방법을 공유합니다.

Geocoding

Geocoding은 위경도와 주소정보를 활용하여 각각으로 변환하는 기술로 변환하는 방향에 따라 부르는 이름이 다릅니다.

  • Forward-Geocoding: 주소 → 위경도 변환 작업
  • Reverse-Geocoding : 위경도 → 주소 변환 작업

우리 일상 속에서 이 기술들이 녹아 있는 서비스들을 쉽게 찾아볼 수 있습니다. 배달 앱에서 우리 집 주소를 설정할 때 또는 공유 차량 서비스나 택시 호출 서비스에서 지도를 움직여 내 위치를 설정할 때 모두 geocoding 기술이 사용됩니다. 가령 배달 앱에서 우리 집 주소를 입력하면 forward-geocoding을 통해 입력된 주소를 위경도로 변환하여 라이더 분들의 내비게이션 경로에 활용됩니다. 반대로 택시 호출 서비스에서 지도를 움직여 내 현재 위치를 설정한다면 reverse-geocoding으로 핀 위치의 주소를 보여주어 해당 호출 위치를 크로스 체크하는데 쓰이기도 합니다.

Geocoding 기술에 대한 설명
Geocoding 기술에 대한 설명

CoreLocation 활용하여 Geocoding 구현하기

iOS에서 Geocoding은 CoreLocation 프레임워크를 활용하여 구현할 수 있습니다. 이때 CLGeocoder 객체를 활용하게 되는데요, 아래와 같이 간단하게 구현할 수 있습니다.

[예시코드 A]

let geocoder = CLGeocoder()

/// Forward Geocoding

// 한글 주소를 활용하여,
geocoder.geocodeAddressString(한글주소) { placemark, error in
     guard let placemarks = placemarks, let location = placemarks.first?.location else { return }
        // 위경도를 구할 수 있습니다.
	let lat = location.coordinate.latitude
	let long = location.coordinate.longitude
}

/// Reverse Geocoding

// 위경도값을 활용하여,
let location = CLLocation(latitude: 위도값, longitude: 경도값)
geocoder.reverseGeocoding(location) { placemarks, error in
     guard let placemark = placemarks?.first else { return }
     // 한글 주소를 구할 수 있습니다.
     let address = placemark.address
}

그러나 geocoding API는 호출에 제한이 있어 사용 시 주의해야 합니다. 단시간에 반복적으로 변환을 요청하면 아래와 같은 에러를 맞이할 수 있습니다.

Throttled “PlaceRequest.REQUEST_TYPE_REVERSE_GEOCODING” request: Tried to make more than 50 requests in 60 seconds, will reset in 13 seconds - Error Domain=GEOErrorDomain Code=-3

공식문서에 따르면 사용자가 멀리 움직였거나 유의미한 시간이 흐르고 난 후 호출을 재개하라고 주의를 하고 있지만 아쉽게도 그 명확한 기준을 제시하고 있지는 않습니다. 그러나 애플이 제공하는 아티클 내의 예시 코드를 읽어보면 어림짐작으로 그들이 바라는 기준을 예상해 볼 수 있습니다.

[예시코드 B]

/// 출처 : [Apple Article] Converting a user's location to a descriptive placemark

func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
     guard let newLocation = userLocation.location else { return }

     let currentTime = Date()
     let lastLocation = self.currentLocation
     self.currentLocation = newLocation
	
     if let lastLocation = lastLocation,
        newLocation.distance(from: lastLocation) <= 1000,
	let lastTime = lastGeocodeTime,
	currentTime.tiimeIntervalSince(lastTime) < 60 {
	
	return	
     }
	
	// reverse geocode를 진행하라
	...
 }

위 [예시코드 B]에 의하면 reverse geocoding API 호출 시 직전 호출 대비 1km 이상 차이가 나고, 1분 초과의 시간이 흘렀는지 확인을 합니다. 문서와 예시코드는 모두 AND로 두 조건을 엮고 있지만 경험한 바로는 하나의 조건만 달성해도 API 호출이 가능했습니다.

CLPlacemark 객체와 한계

Core Location을 사용하여 geocoding을 할 때는 위치 정보를 담고 있는 CLPlacemark 객체를 활용하여 원하는 정보를 얻을 수 있습니다. [예시코드 A]를 살펴보면 geocodeAddressString과 reverseGeocoding 메서드 모두 placemark(s) 값을 활용함을 확인할 수 있습니다. CLPlacemark가 담고 있는 위치 정보의 예시로는 위경도 정보, 국가명, 시/도명, 타임존 등이 있기 때문에 이들을 추출하거나 조합해서 원하는 정보를 만들 수 있습니다. 사람이 읽을 수 있는 주소를 만들기 위해 사용되는 프로퍼티를 살펴볼까요?

CLPlacemark 프로퍼티
administrativeArea주 또는 도
locality시 또는 군
sublocality동네나 유명한 명소처럼 같은 작은 지역
thoroughfare거리 주소
subThoroughfare가장 세부적인 거리 정보. 건물 번호

위 값들을 활용하여 두 장소에 대한 주소를 만들어 보겠습니다. 첫 번째 예시는 제가 현재 일하고 있는 ‘카카오 판교아지트’이고 두 번째 예시는 즐겨 찾는 간장 게장 맛집 ‘진미식당’입니다.

CLPlacemark 프로퍼티카카오 판교아지트진미식당
country대한민국대한민국
administrativeArea경기도서울특별시
locality성남시서울특별시
sublocality백현동공덕동
thoroughfare판교역로공덕동
subThoroughfare166105-127
  • 카카오판교아지트: 경기도 성남시 백현동 판교역로 166
  • 진미식당: 서울특별시 서울특별시 공덕동 공덕동 105-127

CLPlacemark 프로퍼티들을 활용해서 주소를 만들었더니 이상한 점 2가지가 있습니다. 혹시 찾으셨나요?

  1. 진미식당의 행정구역인 마포구 정보가 유실됨.
  2. 카카오 판교아지트와 진미식당이 서로 다른 주소 체계를 사용함. 왜 이런 일이 발생할까요?

원인 1. 현실과 데이터베이스의 정합성

데이터베이스가 최신화되지 않아 발생하는 현실 정보와의 정합성 이슈는 비단 애플 프레임워크에서만 발생하는 문제는 아닙니다. 그러나 국내 사용자가 적기 때문에 문제가 있어도 발견이 쉽지 않은 점이 데이터베이스 최신화를 저해하는 큰 요소입니다. 최신화가 더딘 대표적인 예시가 주소체계입니다. 한국은 약 10년 전 지번 주소 체계에서 도로명 주소 체계로 변경한 이력이 있는데요, 진미식당처럼 최신 도로명 주소가 등록되어 있지 않으면 과거 주소로 보이는 경우가 발생합니다. 구식 주소 체계가 노출되는 것뿐만 아니라 폐업한 장소가 노출되거나, 반대로 변경된 사업장이 미노출되는 문제 역시 빈번합니다.

당연히 국내만을 전문적으로 타겟팅하여 서빙하는 네이버나 카카오 지도 모두 동일한 문제를 겪습니다. 그러나 사용자가 많고, 사용자가 직접 정보 수정을 제안하는 시스템 및 확인 절차가 빠르게 이루어지기 때문에 상대적으로 사용자가 겪는 불편함이 적습니다. 반대로 애플 지도는 국내 사용자가 적기 때문에 이슈 리포팅 수가 부족하여 업데이트가 느린 편입니다.

원인 2. 한국의 행정구역 체계에 완벽히 대응되지 않는 CLPlacemark

CLPlacemark의 프로퍼티를 정리한 표를 다시 살펴보면 administrative area는 가장 상위 계층 구역, locality는 도시를 뜻합니다. 한국의 행정구역 체계는 도/특별시/광역시 > 시/군/구 > 읍/면/동 로 편제되어 운영하고 있습니다. 그래서 서울특별시가 경기도와 함께 administrative area에 속하지만 서울은 지역 전체를 도시로 취급하기 때문에 locality에도 속하게 됩니다. 따라서 서울특별시를 비롯한 6개의 광역시 그리고 세종특별자치시까지 adminsitrative area와 locality가 동일하게 표시되는 문제가 발생합니다.

여담으로 지금은 개선되었지만 불과 몇 달 전에 경험한 다른 행정구역 체계 문제도 공유해보려고 합니다. 포춘레이더를 출시하고 얼마 되지 않아 아래와 같은 CS를 받았습니다. 광주 시민분께서 서비스에 주소가 ‘전라남도 광주광역시’로 표기된다고 보내셨습니다.

포춘레이더 CS 내용
포춘레이더 CS 내용

지금은 행정구역 체계를 어느 정도 잘 따르고 있기 때문에 광역시에 대한 표기가 잘 되지만, 2024년 초에는 지리적 위치상 광주가 전라남도에 속해 있어서 광주를 광주광역시라고 표기하는 버그가 있었습니다. 포춘레이더를 개발할 당시에는 MapKit과 Core Location이 처음이라 미숙했는데, 전혀 예상치 못한 문제가 발생해서 꽤 당황스러웠던 기억이 있습니다.

어떻게 해결할 수 있을까?

그렇다면 카카오페이에서는 어떻게 이 문제를 해결할 수 있었을까요? CLPlacemark의 한계를 극복할 수 있는 방법을 살펴보겠습니다.

방법 1. addressDictionary 프로퍼티 활용

addressDictionary는 지금처럼 CLPlacemark에 프로퍼티들이 없을 때 사용하던 방식입니다. 과거 자료를 찾아보면 직접 “City”, “Name”과 같은 키 값으로 추출을 하여 원하는 정보를 사용했습니다. 주소를 추출하기 위해서는 “FormattedAddressLines” 키를 사용할 수 있습니다.

let formattedAddressLines = placemark.addressDictionary?["FormattedAddressLines"] as? [String]

이때 배열로 반환하는 값들 중 주소값을 추출하여 활용하면 됩니다. 진미식당의 위경도를 활용해 formattedAddressLines 값을 살펴보면 [“대한민국 서울특별시 마포구 공덕동 105-127”, “04207”]가 튀어나오는데요. CLPlacemark의 프로퍼티에서는 찾을 수 없었던 ‘마포구’가 포함되어 있고 중복된 지명은 없음을 확인할 수 있습니다. 진미식당 예시처럼 늘 dictionary가 반환하는 값이 [주소, 우편번호] 형태는 아닙니다. 가령 부산에 있는 감전초등학교 위경도의 placemark를 활용해 보면 [“감전초등학교”, “대한민국 부산광역시 사상구 괘감로 132”, “46984”], 즉 [건물명, 주소, 우편번호]로 반환해 주기 때문에 새로운 반환값이 생길 수 있음에 유의하면 좋겠습니다.

카카오페이에서는 위 방법으로 원하는 주소 값을 추출해서 사용했습니다. 서비스에서는 ‘마포구 공덕동’까지의 주소만 요구했었기 때문에 먼저 배열을 역순으로 이어 붙인 문자열을 만들고, 이어서 정규식을 이용해 추출했습니다. 해당 방식대로 한다면 진미식당의 경우 “04207 대한민국 서울특별시 마포구 공덕동 105-127”로 문자열을 생성한 후 행정구역에만 해당하는 “대한민국 서울특별시 마포구 공덕동”이 추출될 수 있도록 정규식을 사용한 후 뒤에 2개 값인 “마포구 공덕동”을 활용하였습니다.

하지만 다시 개발을 한다면 다른 방법을 선택할 것 같은데요. addressDictionary의 공식 문서를 찾아보면 deprecated 된 프로퍼티이기 때문입니다. 그래서 저처럼 addressDictionary 방식을 사용할 경우 Xcode에서 'addressDictionary' was deprecated in iOS11.0: Use @properties 워닝을 마주하게 됩니다. 그러나 아시다시피 deprecated 프로퍼티나 메서드들은 하위 OS 호환을 위해 완전히 제거되지 않기 때문에 접근하여 사용할 수는 있지만 애플이 권장하지 않는 방식입니다. 따라서 다시 개발을 한다면 아래의 두 번째 방식인 debugDescription을 선택할 것 같습니다.

방법 2. debugDescription 활용

CLPlacemark 객체의 debugDescription을 출력하면 프로퍼티로는 확인할 수 없는 다양한 메타 데이터들이 담겨있습니다. 애플 문서에서도 debugDescription이 어떻게 구성되는지 공식적으로 알려진 바는 없습니다. 그러나 개발자 커뮤니티 등에서는 출력된 주소가 CLPLacemark의 프로퍼티들의 조합이 아니라는 점, MapKit JS (웹에서 사용하는 MapKit)의 경우 프로퍼티들 뿐만 아니라 완성형 주소를 별도로 제공하는 것을 보아 CoreLocation이 reverse-geocoding 시 개발자들에게 제공되는 정보보다 더 많은 값을 활용할 수 있게 만들어졌을 수 있다는 등의 추측들이 존재합니다.

진미식당의 debugDescription은 다음과 같이 출력됩니다.

공덕동 105-127, 대한민국 서울특별시 마포구 공덕동 105-127, 04207 @ <+37.55056340,+126.95577150> +/- 100.00m, region id: <+37.55058720,+126.95579060> radius 70.65 | center: 37.5505872, 126.9557906 | ratius: 70.65 | entry: true | exit: true

여기서도 addressDictionary의 FormattedAddressLines에서 반환해 주는 값과 동일하게 ‘대한민국 서울특별시 마포구 공덕동 105-127’로 찾아볼 수 있습니다. 역시 필요한 정보를 추출하여 활용하면 비록 도로명 주소가 반영된 최신 주소는 아니지만 서비스에서 활용하기에 지장은 없는 주소를 적용할 수 있습니다.

지도 공급자는 지도 내에 공급업체의 로고를 비롯하여 법적으로 고지해야 할 내용들이 담긴 외부 웹으로의 연결 수단을 제공합니다. 애플의 경우 애플 로그와 법적 정보 링크를 하단 구석에 노출하고(OS 마다 좌측, 우측 위치가 다름) 네이버는 로고만 노출하는 대신 로고를 누르면 외부 페이지로 연결됩니다.

위치가 서비스 UI를 해치는데 꼭 필요할까?

통상적으로 하단 구석에 자리 잡는 로고와 함께 서비스 개발을 하다 보면 디자인적 제약이 생깁니다. 우선 미관적으로 예쁘지 않아서 가리고 싶은 욕구가 생기기도 하고, 서비스에 필요한 다양한 컴포넌트를 배치시킬 때 지도 하단을 활용하게 되면 해당 컴포넌트가 가려지기 때문입니다. 포춘레이더를 개발할 때 사용자가 진행 중인 미션을 보여주는 뷰가 하단 영역에 배치되자 이런 의문이 들었습니다.

“가리면 안 되나?”

가리면 안 되나?

애플에게서 위 질문에 대한 답을 찾기는 쉽지 않았습니다. 로고와 법적 정보 링크가 노출되어야 한다고 문서화가 되어 있지 않아서 확신이 서지 않은 상태였습니다. 문득 다른 SDK는 가이드를 어떻게 내리고 있는지 궁금해졌고, 타 SDK를 참고하면 ‘애플도 비슷한 경향을 갖지 않을까?‘라는 전제로 더 깊은 검색을 할 수 있다는 확신이 생겼습니다. 그렇게 네이버와 카카오 지도 SDK를 살펴봤습니다.

네이버 지도는 로고를 비활성화할 수는 없으나 로고의 위치 조정에 대한 인터페이스를 제공하고 있었습니다. 여기에 더해 혹여 로고 탭을 통해 외부 웹으로 가는 기능을 비활성화할 경우 앱 내의 메뉴에서 해당 내용을 확인할 수 있는 메뉴를 만들 것을 요청합니다. 카카오지도도 유사하게 가이드하고 있습니다. 우하단에 위치한 로고의 변경 또는 가림은 허용되지 않지만 위치를 옮길 수 있는 인터페이스를 제공하여 개발자에게 옵션을 제공하고 있습니다.

[예시코드 C]

/// 네이버
naverMap.mapView.logoAlign = .rightTop
naverMap.mapView.logoMargin = UIEdgeInsets(top: 52, left: 0, bottom: 0, right: 0)

/// 카카오
kakaoMap.setLogoPosition(
	origin: GuiAlignment(vAlign: .middle, hAlign: .right),
	position: CGPooint(x: 2.0, y: 2.0)
)

이를 살펴보면 두 SDK 모두 공통적으로 로고 자체를 영구적으로 덮는 행위는 금지하고 있고 대신 로고의 레이아웃을 변경할 수 있는 옵션을 제공하고 있었습니다. 애플은 MapKit 문서에서 위와 같은 내용은 언급을 일절하고 있지 않지만 ‘Apple 지도 이용 약관’을 읽어보면 다음과 같은 문구를 찾아볼 수 있습니다.

귀하는 제3자의 다음 행위를 허용하거나 인가하지 않습니다. (생략) (ii) 서비스에 표시되거나 서비스를 통해 제공될 수 있는 저작권 고지, 상표 또는 기타 소유권 또는 법적 고지, 문서 또는 하이퍼링크를 제거하거나, 가리거나, 변경하는 행위

이를 통해 MapKit 역시 로고의 변경 및 법적 고지 안내 요소들을 변경 또는 제거하면 안 됨을 알 수 있습니다. 거기에 네이버 또는 카카오와는 다르게 해당 요소들의 위치를 제어할 수 있는 방법을 제공하고 있지 않습니다. 애플에서 직접적으로 로고나 법정 정보 레이블 객체에 접근할 수 있는 방법을 열어두지 않았기 때문에 애플의 기조는 어느 정도 짐작 할 수 있습니다. 그러나 서비스 개발자로서 사용자에게 가장 좋은 사용자 경험을 제공해야 하기 때문에 방법을 찾고 싶었습니다.

어떻게 해결할 수 있을까?

포춘레이더 서비스에서 제공하는 미션 뷰는 사용자가 현재 수행하고 있는 미션을 보여주고, 다양한 미션 옵션을 확인할 수 있는 페이지로 연결됩니다. 그러나 위치가 애플 로고와 법적 공지 레이블을 가리고 있고 무엇보다 치명적인 부분은 법적 공지 레이블을 탭 할 수 있는 방법이 막혔다는 점입니다.

접근 가능한 방법을 찾아 이동하기

이들의 위치를 변경하기에 앞서 우선 애플 로고와 법적 정보 레이블에 접근할 수 있는 방법을 찾아야 합니다. 공식 문서에서는 찾아볼 수 없으니 뷰 디버거를 활용해 볼 수 있습니다. 뷰 디버거에서 계층 정리를 해가며 확인해 보니 다음과 같은 정보를 알 수 있었습니다.

  1. 애플 로고와 법적 정보 레이블은 별도의 객체라는 점
  2. 애플 로고는 MKAppleLogoLabel이라는 점
  3. 법적 정보 레이블은 MKAttributionLabel이라는 점

지도의 하위 뷰를 순회하면서 MKAppleLogo와 MKAttributionLabel을 찾은 후에 원하는 바를 이룰 수 있습니다. 포춘레이더 서비스에서는 로고와 레이블의 y축을 하단으로 이동시켜서 미션 뷰가 두 컴포넌트를 영구적으로 가리거나, 법적 공지 화면의 터치를 막는 문제를 해결할 수 있습니다.

[예시코드 D]

extension MKMapView {
   var appleLogoView: UIView? {
      subviews.first { "\(type(of: $0))" == "MKAppleLogo" }
   }
   
   var legalLabelView: UIView? {
      subviews.first { "\(type(of: $0))" == "MKAttributionLabel" }
   }
}

사용 시 주의할 점

제시한 방법을 사용할 때 주의할 점이 몇 가지 있습니다.

  1. 변경 가능성
    당연히 애플에서 정식으로 제공하는 방식이 아니기 때문에 언제든지 해당 객체의 이름이 예고 없이 바뀔 수 있습니다. 실제로 구 버전 OS는 로고에 MKAppleLogoImageView를 사용했었는데요, 카카오페이는 iOS 최소 타겟을 16.0으로 잡고 있어 영향 범위에 없지만 언제든지 변경 가능성은 열어두어야 합니다.
    비슷한 문제로 로고와 레이블의 위치도 기기와 OS별로 상이할 수 있습니다. 우선 기종에 따라 노치의 유무가 다르기 때문에 safe area를 고려하여 로고와 레이블의 위치를 바꾸어야 합니다. 또한 OS별로 지도에 노출되는 위치가 다릅니다. 로고와 레이블이 늘 같은 방향에 놓이는 것이 아니라 각각 좌하단 우하단에 놓이기도 하기 때문에 위치 변경 시 x 값 변경도 함께 고려하고 있다면, 최초 위치가 어딘지 파악할 필요가 있습니다.

  2. 수행 시점 고려
    지도의 하위 뷰들을 순회하면서 로고와 레이블을 찾고 있기 때문에 지도의 레이아웃이 완성이 된 상태에서 수행해야 합니다. 그래서 viewDidAppear 시점에서 객체를 찾고 위치를 이동시키는 것을 권장합니다. 그러나 서비스에 따라 viewDidAppear가 다중 호출 될 가능성이 있다면 성능적인 측면을 고려해서 레이아웃을 완성하는 최초 시점에만 움직일 수 있도록 하는 것을 권장합니다.

위와 같은 주의점들이 있지만 애플 로고와 법적 정보 레이블이 서비스의 미관을 해친다면 뷰 디버거를 적극 활용하여 앞서 제시한 방법을 통해 두 요소들의 위치를 움직이면 문제를 해소할 수 있을 것입니다.

마치며

위치 기반의 서비스를 만들 때 가장 어려운 점은 다양한 환경에서의 검증이 어려운 점인 듯 합니다. 광주광역시가 전라남도라고 노출되어 CS를 받은 경험처럼 고려하지 못한 다양한 케이스가 존재합니다. 지금도 도서 지역에서는 잘 노출이 되고 있는지, 특수 지역(ex. 대학교 캠퍼스, 공항, 놀이공원 등)에서는 어떻게 노출되고 있는지 확인 못 해본 것들도 많습니다. 장소뿐만 아니라 KTX처럼 빠른 속도로 움직이거나 유리 건물이 많은 거리를 걸을 때 GPS가 튀는 현상들 등 아직 검증 못 해 본 환경들도 존재합니다. 이렇듯 사용자들의 CS와 사내 버그 제보들과 함께 성장하고 있는 위치/지도 서비스입니다.

물론 아직도 ‘한국에 더 잘 맞는 지도 SDK를 활용할 수 있었으면 좋지 않았을까?‘라는 생각이 들기도 합니다. 그럼에도 불구하고 애플의 지도 SDK인 MapKit은 가용할 수 있는 비용에 제한이 있거나, MVP로 내놓아 빠르게 실험을 해보는 경험을 하고 싶은 경우 위치 기반 서비스를 시각화하기에는 손색없는 선택지인 것 같습니다.

이번 글에서 소개한 내용들은 애플에서 정식 지원하지 않는 내용들이라 위험 요소들이 다소 존재합니다. 그러나 MapKit을 활용한 서비스 개발 시 비슷한 문제 상황을 흔히 겪을 것이고 해소 방법을 찾는데 조금이라도 도움이 될 것 같습니다.

Reference

sueaty.cho
sueaty.cho

카카오페이 클라이언트서비스팀에서 iOS 개발을 하고 있습니다. 서비스에 대한 깊은 애정과 깊은 관찰력을 바탕으로 사용자향 개발을 지향합니다.