문서 / 지도 뷰 / 프로바이더를 전환하기

프로바이더 전환

프로바이더마다 다른 것은, 의존 모듈・지도 뷰의 타입・상태 객체의 타입 3가지뿐입니다. 마커나 도형, 카메라 조작, 이벤트의 작성법은 달라지지 않습니다. 같은 화면에 여러 프로바이더를 나란히 두고, 실행 시에 전환할 수도 있습니다.

ANDROID
8개 프로바이더
iOS
9개 프로바이더
REACT
13개 프로바이더

01 · 무엇이 바뀌고, 무엇이 바뀌지 않는가

바뀐다
  • 의존 모듈(for-maplibre → for-googlemaps 등)
  • 지도 뷰의 타입(MapLibreMapView → GoogleMapView)
  • 상태 객체의 타입과, 그 생성 함수
  • mapDesignType에 넘기는 디자인 상수
  • API 키의 취득 방법과 초기화의 작법
바뀌지 않는다
  • GeoPoint · GeoRectBounds · MapCameraPosition
  • MarkerState · PolylineState · PolygonState · CircleState …
  • moveCameraTo() · fitBounds() · 이벤트 핸들러
  • 지리 계산(거리・방위・면적)
  • 확장 레이어(클러스터링・히트맵・GeoJSON)

상태 객체의 타입은 프로바이더마다 나뉘어 있지만, 공통의 인터페이스(Android: MapViewStateInterface, iOS: MapViewStateProtocol, React: MapViewStateInterface)를 구현합니다. 카메라 조작이나 디자인 전환은, 이 공통 인터페이스 너머로 쓸 수 있습니다.

그림 · 각 프로바이더가 실제로 그리는 지도(샘플 앱에서)
GOOGLE MAPS
MAPLIBRE
MAPBOX
HERE
ARCGIS

02 · 프로바이더별 타입

각 프로바이더가 공개하는 지도 뷰와 상태 객체의 일람입니다. 역사적인 경위로 이름이 완전히는 맞춰져 있지 않은 곳이 있으므로, 실제로 export 되고 있는 이름을 그대로 싣고 있습니다.

Provider
Android
iOS
React
Google Maps
GoogleMapView
rememberGoogleMapViewState
GoogleMapViewState
GoogleMapView
GoogleMapViewState
GoogleMapView2D / GoogleMapView
useGoogleMapViewState
MapLibre
MapLibreMapView
rememberMapLibreMapViewState
MapLibreViewState
MapLibreMapView
MapLibreViewState
MapLibreMapView2D
useMapLibreViewState
Mapbox
MapboxMapView
rememberMapboxMapViewState
MapboxViewState
MapboxMapView
MapboxViewState
MapBoxMapView2D / MapBoxMapView
useMapboxViewState
HERE
HereMapView
rememberHereMapViewState
HereViewState
HereMapView
HereMapViewState
HereMapView2D
useHereViewState
ArcGIS
ArcGISMapView / 2D
rememberArcGISMapViewState
ArcGISMapViewState
ArcGISMapView / 2D
ArcGISMapViewState
ArcGISMapView2D / ArcGISMapView
useArcGISViewState
MapTiler
MapTilerMapView
rememberMapTilerMapViewState
MapTilerViewState
MapTilerMapView
MapTilerViewState
MapTilerMapView2D
useMapTilerViewState
TomTom
TomTomMapView
rememberTomTomMapViewState
TomTomMapViewState
TomTomMapView
TomTomMapViewState
TomTomMapView2D
useTomTomViewState
Longdo
LongdoMapView
rememberLongdoMapViewState
LongdoViewState
LongdoMapView
LongdoViewState
LongdoMapView2D
useLongdoViewState
Apple MapKit
MapKitMapView
MapKitViewState
MapKitMapView
useMapKitViewState
Leaflet
LeafletMapView
useLeafletMapViewState
OpenLayers
OpenLayersMapView
useOpenLayersMapViewState
Azure Maps
AzureMapsMapView
useAzureMapsViewState
Cesium
CesiumMapView
useCesiumMapViewState

「/ 2D」는 3D 표시와 2D 표시의 2가지 뷰가 있음을 나타냅니다. 어느 쪽도 같은 상태 객체를 공유하며, 2D에서는 tilt가 항상 0이 됩니다.

플랫폼

03 · 전환의 작성법

실행 시에 전환하고 싶을 때는, 상태 객체를 프로바이더마다 하나씩 가지고 있고, 표시할 뷰만을 분기합니다. 오버레이의 기술은 분기의 바깥에 둘 수 있습니다. 샘플 앱은 이 형태입니다.

MapViewContainer.kt · Jetpack Compose
@Composable
fun MapViewContainer(
    modifier: Modifier = Modifier,
    state: MapViewStateInterface<*>? = null,
    content: (@Composable MapViewScope.() -> Unit)? = null,
) {
    when (state) {
        is GoogleMapViewState -> GoogleMapView(modifier, state, content = content)
        is MapLibreViewState -> MapLibreMapView(modifier, state, content = content)
        is MapboxViewState -> MapboxMapView(modifier, state, content = content)
        is HereViewState -> HereMapView(modifier, state, content = content)
        else -> { /* not selected */ }
    }
}

// 호출하는 쪽은 오버레이만 쓴다
MapViewContainer(state = selectedState) {
    Markers(markerStates)
}

React에서는 훅의 호출 순서를 바꿀 수 없으므로, 프로바이더마다의 뷰를 별도 컴포넌트로 잘라내고, 그 컴포넌트 안에서 훅을 호출하는 형태가 안전합니다. 샘플 앱의 providers/ 디렉터리가 그 구성입니다.

영상으로 보여 주는 구현 · Android + MapLibreKotlin · Jetpack Compose
// One state per provider
val maplibre = rememberMapLibreMapViewState(
    mapDesign = MapLibreDesign.OsmBrightJa,
    cameraPosition = MapCameraPosition(
        position = GeoPoint.fromLatLong(35.6812, 139.7671),
        zoom = 12.0,
    ),
)
val googlemaps = rememberGoogleMapViewState(
    cameraPosition = MapCameraPosition(
        position = GeoPoint.fromLatLong(35.6812, 139.7671),
        zoom = 12.0,
    ),
)
var useMapLibre by remember { mutableStateOf(true) }

// The overlays are declared outside the branch, so swapping does not touch them
val overlays: @Composable MapViewScope.() -> Unit = {
    Marker(markerState)
    Polyline(routeState)
}

// Hand the camera you were just looking at to the side you are switching to
LaunchedEffect(useMapLibre) {
    if (useMapLibre) {
        maplibre.moveCameraTo(googlemaps.cameraPosition)
    } else {
        googlemaps.moveCameraTo(maplibre.cameraPosition)
    }
}

if (useMapLibre) {
    MapLibreMapView(state = maplibre, content = overlays)
} else {
    GoogleMapView(state = googlemaps, content = overlays)
}
샘플 영상 · 실행 중에 프로바이더를 전환하기
영상 미촬영샘플 앱에서, 오버레이를 둔 채로 지도 뷰만을 전환하는 모습. 마커나 폴리라인이 교체의 전후로 같은 위치에 남는 것이 보이면, 이 절의 주장이 전해집니다.

04 · 프로바이더 차이의 취급

모든 지도 SDK가 같은 기능을 가지는 것은 아닙니다. MapConductor는 차이를 메울 수 있는 곳은 메우고, 메울 수 없는 곳은 대체 표현을 마련합니다.

1 · 대체 렌더링

네이티브에 기능이 없으면, SDK 쪽에서 래스터 타일로 그립니다. 폴리곤의 구멍이나 마커의 대량 렌더링이 여기에 해당합니다. 호출하는 쪽의 코드는 달라지지 않습니다.

2 · 타입으로 나타낸다

그 프로바이더가 다룰 수 없는 요소는, 드라이버가 대응하는 렌더러를 가지지 않습니다. 쓸 수 있는지 여부는 컴파일 시나, 상태 객체의 타입으로 판단할 수 있습니다.

3 · 통로

아무래도 그 프로바이더 고유의 기능이 필요하다면, MapViewHolder에서 네이티브의 지도 인스턴스를 꺼내 직접 호출할 수 있습니다.

API KEYS

키와 초기화는 프로바이더마다

MapConductor는 API 키를 맡아 두지 않습니다. 각 지도 SDK가 요구하는 작법(Android의 매니페스트, iOS의 sdkInitialize, Web의 설정 객체)으로 그대로 넘깁니다. MapLibre・Leaflet・OpenLayers처럼 키가 필요 없는 프로바이더도 있고, 그 경우는 타일 배포처만 정합니다.

관련 페이지