ドキュメント / そのほか / ネイティブ拡張

ネイティブ拡張

MapConductor は各地図 SDK の全機能をラップしません。統一 API に無い表現が必要になったとき、抽象化を捨てずに下へ降りるための道が 2 つ用意されています。どちらを使っても、その画面の他の部分は共通 API のまま動きます。

1 · HOLDER
Android · iOS · React
2 · REGISTRY
Android · iOS · React

01 · 抽象化の終わり

統一 API が扱うのは、どのプロバイダにも共通してある概念だけです。3D 建物の押し出し、特定ベンダーの交通量レイヤー、独自のシェーダーといったものは、意図的に対象外にしています。全部を包もうとすると、共通 API が最小公倍数になって使いにくくなるためです。

1 · MapViewHolder
実体をそのまま借りる
ネイティブの地図インスタンスを取り出し、そのSDKのAPIを直接呼びます。3 プラットフォームすべてにあります。
2 · MapServiceRegistry
機能を差し込む
追加モジュールが、Core を改造せずに自分の機能を型付きキーで登録します。SDK を拡張する側の仕組みです。
プラットフォーム

02 · ネイティブの地図に触る

状態オブジェクトから getMapViewHolder() を呼ぶと、そのプロバイダの地図ビューと地図インスタンスを持つホルダーが返ります。型を絞り込めば、あとは素の SDK です。座標と画面ピクセルの相互変換も、このホルダーが持っています。

メンバー
説明
mapView
プロバイダのビュー(MKMapView・MapView・maplibregl.Map のコンテナなど)。
map
地図そのもののインスタンス。SDK のAPIはここから呼びます。
toScreenOffset(position)
座標を画面ピクセルへ。傾きや回転が反映されます。
fromScreenOffset(offset)
画面ピクセルを座標へ。非同期版と同期版があります。
Kotlin
// 型を絞り込めば、そこから先は素の Google Maps SDK
val holder = mapViewState.getMapViewHolder()
if (holder is GoogleMapViewHolder) {
    holder.map.isTrafficEnabled = true
}

ホルダーは地図の初期化が終わってから使えます。未初期化のあいだは null が返るため、onMapLoaded の中か、その後の操作で呼んでください。

03 · モジュールを差し込む

追加モジュールが、Core を改造せずに自分の機能を差し込むための口が MapServiceRegistry です。型付きのキーで登録し、必要な側が同じキーで取り出します。キーが型を持つため、取り出した値のキャストは要りません。現在これを使っているのはマーカークラスタリングで、プロバイダが登録した MarkerRenderingSupport を引き当てて描画します。

Android · React

MapServiceRegistry

MapServiceKey<T> をシングルトンとして定義し、MutableMapServiceRegistry に put、利用側は get で受け取ります。Android では CompositionLocal(LocalMapServiceRegistry)から地図スコープの登録簿を参照します。

iOS

MapServiceRegistryScope

キーは MapServiceKey に準拠した型として定義し、MutableMapServiceRegistry に put します。登録簿は状態オブジェクト(MapViewState.serviceRegistry)が持ち、プロバイダは content を組み立てるあいだだけ MapServiceRegistryScope.with(...) でそれを可視にします。SwiftUI の Environment ではないのは、地図の中身が MapViewContent という値であってビュー階層ではないためです。

map/MapServiceRegistry · 型付きキーの形
// Kotlin: キーはシングルトンの object として定義する
object MarkerRenderingSupportKey : MapServiceKey<MarkerRenderingSupport<*>>

registry.put(MarkerRenderingSupportKey, support)
val support = registry.get(MarkerRenderingSupportKey) // 型が付いたまま返る

// Swift: キーは MapServiceKey に準拠した型として定義する
enum MarkerRenderingSupportKey: MapServiceKey {
    typealias Value = any MarkerRenderingSupport
}

registry.put(MarkerRenderingSupportKey.self, support)
let support = registry.get(MarkerRenderingSupportKey.self)

// TypeScript: createMapServiceKey<T>() でキーを作る
const MarkerRenderingSupportKey = createMapServiceKey<MarkerRenderingSupport>();

ここで挙げた 3 つは、どれもプロバイダ固有のコードを画面に持ち込みます。プロバイダを差し替えたときに動かなくなる部分になるので、使った箇所は分岐の内側にまとめておくことをおすすめします。

関連ページ