MapConductor란 무엇인가 ── 지도 SDK를 「나중에 고를 수 있게」 하기

주요 지도 SDK를 1장의 공통 API로 다루는 오픈 소스 SDK입니다. 무엇을 하는 것인지, 어떤 때에 도움이 되는지를 정리했습니다.

MapConductor는, 지도 SDK를 1장의 공통 API로 다루기 위한 오픈 소스 SDK입니다. Android(Jetpack Compose)・iOS(SwiftUI)・React(TypeScript)용으로 제공하고 있고, 지금은 15개의 프로바이더에 대응하고 있습니다. 라이선스는 Apache-2.0입니다.

첫 기사이므로, 이것이 무엇을 하는 것인지, 그리고 어떤 때에 도움이 되는지를 다시 한번 써 둡니다.

지도 SDK는, 어느 것이나 잘 만들어져 있다

Google Maps, Mapbox, HERE, ArcGIS, MapLibre, MapTiler, TomTom, Longdo, Mappls ── 지도 SDK는 어느 것이나 오랜 시간을 들여 다듬어져 있고, 저마다 잘하는 부분이 있습니다. 도로나 주소의 상세함, 내비게이션, GIS 자산과의 접속, 디자인의 자유도, 대응 지역. 「어느 것이 가장 좋은가」라는 물음에 일반해는 없고, 만드는 앱과 전달하는 지역에 따라 답이 달라집니다.

그럼에도 불구하고, 구현하는 쪽에서 보면, 그 선택은 처음 몇 줄에서 거의 확정됩니다. 지도를 내는 코드는 특정 SDK의 타입과 개념에 깊이 묶이므로, 나중에 비교하고 싶어졌을 때에는, 비교할 수단 쪽이 남아 있지 않습니다.

이것은 각 사의 설계가 나쁘다는 이야기가 아닙니다. 오히려 각 사가 자신의 잘하는 분야에 맞춰 꼼꼼히 설계해 온 결과로서, 개념도 명명도 맞춰져 있지 않다, 는 것뿐입니다. 맞춰져 있지 않은 것을 맞추는 것은, SDK를 제공하는 쪽이 아니라, 그 위에서 쓰는 쪽의 일이 됩니다. MapConductor는 그 1장을 떠맡습니다.

무엇을 하는 것인가

앱은 MapConductor의 통합 API에만 의존합니다. 프로바이더마다의 차이는 드라이버가 흡수하므로, 프로바이더를 바꿀 때 바꿔 쓰는 것은, 의존 모듈・지도 뷰의 타입・상태 객체의 타입의 3가지뿐입니다. 마커나 도형, 카메라 조작, 이벤트의 작성법은 달라지지 않습니다.

kotlin
// 오버레이의 선언은 분기의 밖에 둔다. 프로바이더를 교체해도 다시 쓰지 않는다
val overlays: @Composable MapViewScope.() -> Unit = {
    Marker(markerState)
    Polyline(routeState)
}

if (useMapLibre) {
    MapLibreMapView(state = maplibre, content = overlays)
} else {
    GoogleMapView(state = googlemaps, content = overlays)
}

같은 화면에 2개를 나란히 두고, 실행 시에 전환할 수도 있습니다. 전환하는 쪽으로 직전의 카메라를 이어받으면, 겉모습의 점프도 되지 않습니다.

맞춰지는 것은, 작성법만이 아니다

「공통의 API」라고 들었을 때 가장 걱정되는 것은, 작성법은 맞춰져도 결과가 맞춰지지 않는 것이라고 생각합니다. 줌 14의 보이는 모습이 환경에 따라 다르다, 2점 사이의 거리가 Android와 iOS에서 일치하지 않는다 ── 이것은 실제로 일어납니다.

MapConductor는, 그 부분을 SDK 쪽에서 가지고 있습니다.

자체적으로 가지고 있는 것그 덕분에 맞춰지는 것
지리 계산거리・방위・면적・보간을 Kotlin / Swift / TypeScript에서 같은 식으로 구현. SDK의 유틸리티에 의존하지 않으므로, 표시되는 수치가 플랫폼에서 어긋나지 않습니다
카메라줌과 카메라 고도를 상호 변환하고, 실측에 기반해 교정하고 있습니다. zoom 14는 어느 프로바이더에서도 같은 넓이입니다
마커 렌더링소수라면 네이티브 마커, 2,000개를 넘으면 내부에서 래스터 타일로 자동 전환. 수만 건이어도 카메라 조작은 매끄러운 채로, 앱 쪽의 코드는 한 줄도 달라지지 않습니다
도형구멍 뚫린 폴리곤이나 대권 코스 등, 네이티브에 기능이 없는 프로바이더에서는 래스터 타일로 그려, 같은 겉모습으로 만듭니다
출처 표기줌이나 표시 범위에 따라 출처를 전환하는 규칙을, 지도 디자인의 일부로 가집니다

각 SDK의 메서드를 나눠 호출하기만 하는 래퍼라면, 할 수 있는 것이 「가장 기능이 적은 SDK」에 맞춰지고 맙니다. 부족한 부분은 스스로 그려서 메운다, 는 방침을 취하고 있는 것은 그 때문입니다.

무엇에 도움이 되는가

외울 API가 1개로 끝난다

지도 SDK는 벤더마다 개념도 명명도 다르므로, 프로바이더를 바꿀 때마다, 플랫폼을 옮길 때마다 다시 외우는 일이 생깁니다. MapConductor에서 외우는 것은 1개의 API뿐이고, Android・iOS・React 어디에서도 같은 이름・같은 의미입니다. Android에서 얻은 지식은 그대로 iOS에서 통용되고, 팀에 사람이 들어올 때 읽어야 할 대상이 프로바이더의 수만큼 늘어나는 일도 없습니다.

지도 SDK의 이름이 나오지 않는 코드를 쓸 수 있다

GeoPointMarkerState는, 어느 지도 SDK에도 속하지 않는 타입입니다. 경로를 조립한다, 범위에 들어가는지를 판정한다, 무엇을 표시할지를 정한다 ── 이러한 로직을 SDK의 타입에서 떼어 내어 쓸 수 있습니다. 지도 주변의 공통 부품을, 프로바이더마다 따로 만들지 않고 라이브러리로 잘라낼 수도 있습니다.

사양의 논의가 1번으로 끝난다

Android・iOS・Web에서 각각 다른 지도 SDK를 쓰고 있으면, 마커의 거동도 카메라의 수치의 의미도 맞지 않아, 같은 기능의 사양을 3번 상의하게 됩니다. 공통의 모델이 있으면, 그 3번이 1번이 됩니다.

「고를 수 있다」는 상태를 만들고 싶다

여기까지는 지도를 넣는 쪽의 이야기입니다. MapConductor가 하고 싶은 것은, 그것만이 아닙니다.

지금은, 지도 SDK의 선택이 구현의 최초의 커밋이 되어 있습니다. 그러면 선정은 「시험해 보고 정한다」가 아니라 「정하고 나서 만든다」가 되고, 비교는 탁상에서 끝납니다. 이것은 선택되는 쪽에게도, 그다지 좋은 상태가 아닙니다. 좋은 SDK가, 품질이 아니라 「이미 다른 SDK로 써 버렸으니까」라는 이유로 후보에서 빠져 버리기 때문입니다.

공통 API가 있으면, 이 순서가 달라집니다. 실제로 움직여 보고, 같은 앱의 같은 화면에서 비교해 보고, 그 위에서 정할 수 있다. 결정타가 되는 것은, 가격・대응 지역・데이터의 새로움・렌더링의 품질 ── 즉 각 사가 본래 경쟁하고 있는 부분입니다.

그래서 MapConductor는, 각 사의 강점을 덮어 가리지 않는 만듦새로 하고 있습니다. 공통화하고 있는 것은, 어느 프로바이더에도 있는 기본적인 기능뿐입니다. 상태 객체의 getMapViewHolder()를 호출하면 네이티브의 지도 뷰와 지도 인스턴스를 그대로 꺼낼 수 있으므로, 그 프로바이더에만 있는 기능은 각 사의 API로 직접 쓸 수 있습니다. 전부를 덮어 가리는 래퍼라면 차별화 요인이 사라지지만, 그렇게는 하지 않았습니다. 「공통 부분은 MapConductor로, 승부처는 각 사의 API로」라는 병용이 보통으로 가능합니다.

브라우저가 HTML5로 구현을 맞춘 뒤, 각 브라우저는 호환성을 지키는 것 자체가 아니라, 속도나 기능 그 자체로 경쟁하게 되었습니다. 지도 SDK도 같아서, 공통의 인터페이스가 정해지면, 그 위에서 얼마나 빠르게・정확하게・넓은 지역을 그릴 수 있는지가 물어집니다. 공통화는 개별 SDK의 진화를 멈추게 하는 것이 아니라, 진화의 방향을 맞추는 것이라고 생각합니다.

또 하나, 이것은 앞으로의 방향에 대한 이야기입니다. 지도 데이터나 지오코딩은, 그것을 제공하는 벤더의 지도 SDK와 세트로 쓰는 것이 전제였습니다. 표시와 데이터를 떼어 놓을 수 있다면, 자체 표시 수단을 갖지 않은 제공자 ── 지오코딩만, 특정 분야의 데이터만 가진 곳 ── 에게도, 써 주는 장면이 늘어납니다. 현시점에서 이 용도를 위한 기능은 아직 없습니다. 방향이지 기능 일람이 아니다, 라고 써 둡니다.

덧붙여, 데이터나 서비스의 이용 약관에 따르는 것은, 그것을 넣는 개발자의 책무입니다. 기술적으로 조합할 수 있다는 것과, 그 조합이 허락되어 있다는 것은, 별개의 이야기입니다.

맞는 경우, 맞지 않는 경우

맞는 것은, 이런 때입니다.

  • 여러 플랫폼에서 같은 지도 경험을 내고 싶다
  • 장래에 프로바이더를 바꿀 가능성을 남겨 두고 싶다
  • 마커・도형・카메라 같은 표준적인 지도 표현이 중심
  • 수천〜수만의 마커를 다룬다
  • 거리나 면적의 표시에 일관성이 요구된다

반대로, 이런 때는 맞지 않습니다.

  • 특정 프로바이더 고유의 고도한 표현이 주역(독자 셰이더, 벤더 전용 레이어)
  • 턴바이턴 내비게이션 등, SDK의 전용 기능 그 자체가 목적
  • 1개 플랫폼・1개 프로바이더로 완결되고, 앞으로도 바꿀 예정이 없다

다만, 전부냐 아니냐는 아닙니다. 네이티브의 지도 인스턴스에는 항상 손이 닿으므로, 특수한 부분만 프로바이더 고유의 코드로 쓴다, 는 구성이 가능합니다.

시작하는 법

MapLibre라면 API 키 없이 동작하므로, 최초의 지도가 나오기까지는 5분 정도입니다.

개발의 진척이나 릴리스는 Discord에서 공개하고 있습니다. 설계에 대한 의견도, 불량의 보고도 환영입니다. 코드는 GitHub에 있습니다.