ドキュメント / 地図ビュー / プロバイダを切り替える

プロバイダを切り替える

プロバイダごとに違うのは、依存モジュール・地図ビューの型・状態オブジェクトの型の 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 · 切り替えの書き方

実行時に切り替えたいときは、状態オブジェクトをプロバイダごとに 1 つずつ持っておき、表示するビューだけを分岐します。オーバーレイの記述は分岐の外に置けます。サンプルアプリはこの形です。

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
// プロバイダごとに状態を 1 つずつ持つ
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) }

// オーバーレイの宣言は分岐の外に置く。差し替えても書き直さない
val overlays: @Composable MapViewScope.() -> Unit = {
    Marker(markerState)
    Polyline(routeState)
}

// 切り替えた側へ、直前まで見えていたカメラを引き継ぐ
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 のようにキーが不要なプロバイダもあり、その場合はタイル配信元だけを決めます。

関連ページ