はじめに
Android で地図を扱うとき、Google Maps、MapLibre、Mapbox などの SDK はそれぞれ API が違います。あとからプロバイダを替えたくなると、地図まわりのコードをほぼ書き直すことになります。
MapConductor はこうした地図 SDK を 同じ Jetpack Compose の書き方 で扱えるようにするライブラリです。この記事では APIキーなしで使える MapLibre から始めて、次の順に試していきます。
- 地図を表示する
- マーカーをタップして吹き出しを出す
- 円・線・多角形を描く
- プロバイダを切り替える(地図に載せるコードはそのまま)
完成コード: https://github.com/saitojo1106/mapconductor-prc
リポジトリは Step ごとにコミットを分けているので、途中の状態も確認できます。
MapConductor とは
- Google Maps、Mapbox、MapLibre、HERE、ArcGIS、Open Mobile Maps などの地図 SDK を、共通の Compose API で扱えるライブラリです。
- マーカーや図形などの「地図に載せるもの」は共通の書き方で書き、プロバイダごとに替えるのは
MapViewと、その状態(State)だけです。 - ライセンスは Apache-2.0 で、Maven Central に
com.mapconductor:*として公開されています。 - 日本語のドキュメント もあります。
動作環境
| 項目 | バージョン |
|---|---|
| Android Studio | 2026.1 |
| AGP / Gradle | 9.4.1 / 9.6.0 |
| Kotlin | 2.4.10 |
| compileSdk / minSdk | 37 / 26 |
| MapConductor BOM | 1.3.1 |
| MapLibre Android SDK | 13.4.1 |
| Open Mobile Maps(mapscore) | 4.0.0 |
| UiAutomator(テスト) | 2.4.0 |
| 確認した端末 | エミュレータ(Pixel 8 / Android 17 / API 37、M4 Mac)、実機(Pixel 8a / Android 16) |
Step1: MapLibre で地図を表示する
Android Studio の「Empty Activity」(Compose)でプロジェクトを作り、依存関係を追加します。
[versions]
mapconductorBom = "1.3.1"
maplibreSdk = "13.4.1"
[libraries]
mapconductor-bom = { group = "com.mapconductor", name = "mapconductor-bom", version.ref = "mapconductorBom" }
mapconductor-core = { group = "com.mapconductor", name = "core" }
mapconductor-maplibre = { group = "com.mapconductor", name = "for-maplibre" }
maplibre-android-sdk = { group = "org.maplibre.gl", name = "android-sdk", version.ref = "maplibreSdk" }
dependencies {
implementation(libs.maplibre.android.sdk)
implementation(platform(libs.mapconductor.bom))
implementation(libs.mapconductor.core)
implementation(libs.mapconductor.maplibre)
}
バージョンカタログの名前に for を入れるとビルドが失敗します
モジュール名に合わせてエイリアスを mapconductor-for-maplibre にすると、アクセサが libs.mapconductor.for.maplibre になります。for は Kotlin の予約語なので、Expecting '(' to open a loop range というエラーでビルドが失敗します。この記事では mapconductor-maplibre にしています。
タイルを読み込むので、AndroidManifest.xml に INTERNET 権限を追加します。
<uses-permission android:name="android.permission.INTERNET" />
地図を表示する画面です。カメラの位置と地図のデザインを State にして、MapLibreMapView に渡します。
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.mapconductor.core.features.GeoPoint
import com.mapconductor.core.map.MapCameraPosition
import com.mapconductor.maplibre.MapLibreDesign
import com.mapconductor.maplibre.MapLibreMapView
import com.mapconductor.maplibre.rememberMapLibreMapViewState
private val TOKYO_STATION = GeoPoint(35.6812, 139.7671)
@Composable
fun HelloMapScreen(modifier: Modifier = Modifier) {
val mapState = rememberMapLibreMapViewState(
cameraPosition = MapCameraPosition(
position = TOKYO_STATION,
zoom = 14.0,
),
mapDesign = MapLibreDesign.OsmBrightJa,
)
MapLibreMapView(
modifier = modifier,
state = mapState,
)
}
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
MaterialTheme {
HelloMapScreen(modifier = Modifier.fillMaxSize())
}
}
}
}
実行すると、東京駅を中心に、日本語ラベルの地図が表示されます。
MapLibreDesign.OsmBrightJa は OpenStreetMap Japan のタイルサーバー(tile.openstreetmap.jp)にある osm-bright-ja スタイルを使います。左下の ⓘ をタップすると帰属表示が出ます。
このタイルは手軽に試すのには便利ですが、本番のアプリで使う前に配信元の利用条件を確認してください。スクショを記事などに載せるときは、「© OpenStreetMap contributors」の表記を残しましょう。
AGP 9 からは Kotlin が AGP に組み込まれたため、app モジュールに org.jetbrains.kotlin.android プラグインを書かなくても Kotlin が使えます。古い記事の手順と違うので、戸惑うかもしれません。
Step2: マーカーと吹き出し(InfoBubble)
東京駅にマーカーを置き、タップしたら「Hello, MapConductor」の吹き出しを出します。地図をタップすると閉じます。
@Composable
fun HelloMapScreen(modifier: Modifier = Modifier) {
+ var selectedMarker by remember { mutableStateOf<MarkerState?>(null) }
+
val mapState = rememberMapLibreMapViewState(
cameraPosition = MapCameraPosition(
position = TOKYO_STATION,
zoom = 14.0,
),
mapDesign = MapLibreDesign.OsmBrightJa,
)
+ val markerState = remember {
+ MarkerState(
+ position = TOKYO_STATION,
+ onClick = { selectedMarker = it },
+ )
+ }
+
MapLibreMapView(
modifier = modifier,
state = mapState,
- )
+ onMapClick = { selectedMarker = null },
+ ) {
+ Marker(markerState)
+
+ selectedMarker?.let {
+ InfoBubble(marker = it) {
+ Text("Hello, MapConductor")
+ }
+ }
+ }
}
-
MapLibreMapViewの最後のラムダに、地図に載せるものを書きます。ここが MapConductor の共通部分で、プロバイダを替えても同じコードがそのまま使えます(Step4 で試します)。 -
MarkerStateのonClickには、タップされたマーカーの State が渡ってきます。それを覚えておき、InfoBubble(marker = ...)に渡すと、そのマーカーの上に吹き出しが出ます。 - 吹き出しの中身は普通の Composable なので、
Text以外も自由に置けます。
Step3: Circle / Polyline / Polygon を描く
東京駅を中心にした半径 1km の円、東京 → 神田 → 秋葉原を結ぶ線、皇居をおおまかに囲む多角形を描きます。3つが画面に収まるよう、ズームは 13.5 に下げました。
private val KANDA_STATION = GeoPoint(35.6918, 139.7709)
private val AKIHABARA_STATION = GeoPoint(35.6984, 139.7731)
private val IMPERIAL_PALACE = listOf(
GeoPoint(35.6895, 139.7505),
GeoPoint(35.6890, 139.7570),
GeoPoint(35.6838, 139.7585),
GeoPoint(35.6790, 139.7555),
GeoPoint(35.6795, 139.7490),
GeoPoint(35.6850, 139.7470),
)
val circleState = remember {
CircleState(
center = TOKYO_STATION,
radiusMeters = 1000.0,
fillColor = Color.Blue.copy(alpha = 0.4f),
strokeColor = Color.Blue,
strokeWidth = 2.dp,
)
}
val polylineState = remember {
PolylineState(
points = listOf(TOKYO_STATION, KANDA_STATION, AKIHABARA_STATION),
strokeColor = Color.Red,
strokeWidth = 6.dp,
)
}
val polygonState = remember {
PolygonState(
points = IMPERIAL_PALACE,
fillColor = Color.Magenta.copy(alpha = 0.4f),
strokeColor = Color.Magenta,
strokeWidth = 2.dp,
)
}
MapLibreMapView(
modifier = modifier,
state = mapState,
onMapClick = { selectedMarker = null },
) {
Circle(circleState)
Polyline(polylineState)
Polygon(polygonState)
Marker(markerState)
selectedMarker?.let {
InfoBubble(marker = it) {
Text("Hello, MapConductor")
}
}
}
Step3 時点の import 一覧
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.mapconductor.compose.circle.Circle
import com.mapconductor.compose.info.InfoBubble
import com.mapconductor.compose.marker.Marker
import com.mapconductor.compose.polygon.Polygon
import com.mapconductor.compose.polyline.Polyline
import com.mapconductor.core.circle.CircleState
import com.mapconductor.core.features.GeoPoint
import com.mapconductor.core.map.MapCameraPosition
import com.mapconductor.core.marker.MarkerState
import com.mapconductor.core.polygon.PolygonState
import com.mapconductor.core.polyline.PolylineState
import com.mapconductor.maplibre.MapLibreDesign
import com.mapconductor.maplibre.MapLibreMapView
import com.mapconductor.maplibre.rememberMapLibreMapViewState
書いてみて分かった点です。
- 円の半径はメートルで指定します。ズームを変えても、地図上の実際の距離どおりの大きさで描かれます。
- 多角形は始点を最後にもう一度書かなくて大丈夫です。ライブラリ側で自動的に閉じてくれます。
- ズーム値は Google Maps 基準にそろえられています。MapConductor のズームは 256px タイルを基準にした値で、MapLibre には内部で「指定値 − 1」に変換して渡しています。そのため、プロバイダを替えても同じズーム値で同じ縮尺になります。
Step4: プロバイダを Open Mobile Maps に切り替える
ここまでのコードを別のプロバイダでも動かしてみます。MapConductor の Android 版は 8 つのプロバイダに対応していて、そのうち Open Mobile Maps は MapLibre と同じく APIキーなしで使えます。画面上のボタンで、MapLibre と Open Mobile Maps を実行時に切り替えられるようにします。
依存関係を追加します。公式のセットアップ手順に合わせて、compose モジュールも明示しました(Step3 までは for-maplibre 経由で入っていました)。
[versions]
openMobileMaps = "4.0.0"
[libraries]
mapconductor-compose = { group = "com.mapconductor", name = "compose" }
mapconductor-openmobilemaps = { group = "com.mapconductor", name = "for-openmobilemaps" }
openmobilemaps-mapscore = { group = "io.openmobilemaps", name = "mapscore", version.ref = "openMobileMaps" }
dependencies {
implementation(libs.maplibre.android.sdk)
implementation(platform(libs.mapconductor.bom))
implementation(libs.mapconductor.core)
implementation(libs.mapconductor.compose)
implementation(libs.mapconductor.maplibre)
implementation(libs.openmobilemaps.mapscore)
implementation(libs.mapconductor.openmobilemaps)
}
公式の手順には「minSdk 28 以上」とありますが、for-openmobilemaps 1.3.1 と mapscore 4.0.0 の AAR が宣言している minSdk は 26 で、minSdk 26 のままビルドできました。ただし、API 26〜27 の端末での動作は確かめていません。
画面のコードです。Step3 との違いは次の3つです。
- 地図に載せるもの(Step2〜3 で
MapLibreMapViewのラムダに書いていた部分)を、mapContentという変数に取り出す。 - プロバイダごとに State を用意し、ボタンで表示する
MapViewを切り替える。 - 切り替えた先の地図に、直前まで見ていたカメラ位置を引き継ぐ。
private val INITIAL_CAMERA = MapCameraPosition(
position = TOKYO_STATION,
zoom = 13.5,
)
@Composable
fun HelloMapScreen(modifier: Modifier = Modifier) {
var useOpenMobileMaps by remember { mutableStateOf(false) }
var selectedMarker by remember { mutableStateOf<MarkerState?>(null) }
val mapLibreState = rememberMapLibreMapViewState(
cameraPosition = INITIAL_CAMERA,
mapDesign = MapLibreDesign.OsmBrightJa,
)
val openMobileMapsState = rememberOpenMobileMapsMapViewState(
cameraPosition = INITIAL_CAMERA,
mapDesign = OpenMobileMapsDesign.OpenStreetMapJapan,
)
// markerState / circleState / polylineState / polygonState は Step3 と同じなので省略
// 地図に載せるものはプロバイダに関係なく一度だけ書き、どちらの MapView にも渡す
val mapContent: @Composable MapViewScope.() -> Unit = {
Circle(circleState)
Polyline(polylineState)
Polygon(polygonState)
Marker(markerState)
selectedMarker?.let {
InfoBubble(marker = it) {
Text("Hello, MapConductor")
}
}
}
// 切り替え先に、いま見ていたカメラ位置を引き継ぐ
LaunchedEffect(useOpenMobileMaps) {
if (useOpenMobileMaps) {
openMobileMapsState.moveCameraTo(mapLibreState.cameraPosition)
} else {
mapLibreState.moveCameraTo(openMobileMapsState.cameraPosition)
}
}
Box(modifier = modifier) {
if (useOpenMobileMaps) {
OpenMobileMapsMapView(
modifier = Modifier.fillMaxSize(),
state = openMobileMapsState,
onMapClick = { selectedMarker = null },
content = mapContent,
)
} else {
MapLibreMapView(
modifier = Modifier.fillMaxSize(),
state = mapLibreState,
onMapClick = { selectedMarker = null },
content = mapContent,
)
}
Button(
onClick = { useOpenMobileMaps = !useOpenMobileMaps },
modifier = Modifier
.align(Alignment.TopCenter)
.statusBarsPadding()
.padding(top = 8.dp),
) {
Text(if (useOpenMobileMaps) "MapLibre に切り替え" else "Open Mobile Maps に切り替え")
}
}
}
Step4 で増えた import
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material3.Button
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import com.mapconductor.compose.MapViewScope
import com.mapconductor.openmobilemaps.OpenMobileMapsDesign
import com.mapconductor.openmobilemaps.OpenMobileMapsMapView
import com.mapconductor.openmobilemaps.rememberOpenMobileMapsMapViewState
-
MarkerStateやCircleStateなどの「地図に載せるもの」の State は、プロバイダに依存しません。同じ State をどちらのMapViewにも渡せます。 - プロバイダごとに替わるのは、
MapViewの型と、その State(rememberXxxMapViewState)だけです。 - カメラ位置は State ごとに別々に持っているので、切り替えたときに
moveCameraTo()で合わせています。
実機(Pixel 8a)で切り替えた画面です。左が MapLibre、右が Open Mobile Maps で、円・線・多角形・マーカーが同じ位置に描かれています。Step3 で触れた「Google Maps 基準のズーム」のおかげで、縮尺もそろっています。
地図を動かしてから切り替えても、同じ範囲が表示されます(左: MapLibre で地図を動かした直後、右: Open Mobile Maps に切り替えた直後)。スクショから図形の中心位置を計算して比べると、切り替え前後のずれは数ピクセルでした。
ハマりどころ: Open Mobile Maps の OpenGL ES 3.2 要件
最初は Mac のエミュレータで試したのですが、Open Mobile Maps に切り替えると 地図も図形も真っ白 になりました。
Logcat には unsupported shader version というエラーが大量に出ます。一方、マーカーのタップと吹き出しは普通に動きます。当たり判定と吹き出しは、地図の描画とは別に動いているためです。「タップできるのに何も見えない」状態になるので、原因に気づきにくいです。
原因は、Open Mobile Maps の描画エンジンが OpenGL ES 3.2 を必須にしていることでした。シェーダーが #version 320 es で書かれていて、本家の README にも「Android 8.0+, OpenGl ES 3.2」と書かれています。MapConductor のセットアップページには、この要件は書かれていません(2026年11月時点)。「地図が真っ白」のトラブルシューティングも、ネットワーク側の原因だけを挙げています。
Mac(M4)のエミュレータで、GPU の設定を変えて OpenGL ES のバージョンを測った結果です。
| エミュレータの GPU 設定 | OpenGL ES |
|---|---|
| 自動(既定) | 3.1 |
-gpu host |
3.0 |
-gpu host -feature GuestAngle |
3.1 |
どの設定でも 3.2 にはなりません。Mac の GPU(Metal)には ES 3.2 が求める機能(ジオメトリシェーダーなど)の一部がないため、エミュレータの描画層(ANGLE)が「3.1 まで」と名乗るからです。Open Mobile Maps のバージョンを下げても解決しません。2.0.0 からずっと #version 320 es を使っていて、MapConductor 1.3.1 も 4.0.0 を前提にしているためです。
どうしてもエミュレータで動かしたい場合
エミュレータは起動時に、ANGLE の「規格を完全には満たせなくても新しいバージョンを名乗る」機能(exposeNonConformantExtensionsAndVersions)を無効にしています。これを有効に戻すと、Open Mobile Maps が描画されました。
emulator -avd Pixel_8 -gpu swiftshader_indirect -feature GuestAngle
起動したら、アプリを起動する前に次の2つを実行します(エミュレータを再起動すると元に戻ります)。
adb shell setprop debug.angle.feature_overrides_enabled exposeNonConformantExtensionsAndVersions
adb shell setprop debug.angle.feature_overrides_disabled 'supportsBlend*'
ただし、これは規格に準拠していない状態での描画なので、見た目が正しい保証はありません。しかもこの構成では、MapLibre の地図が崩れます。1回の起動で両方のプロバイダを正しく見ることはできないので、あくまで最終手段です。
結局、OpenGL ES 3.2 に対応した実機(Pixel 8a、Mali-G715)で確認しました。実機では上書きなしで、両方のプロバイダが問題なく描画されます。
実機はケーブルがなくても、Android 11 以降なら「ワイヤレスデバッグ」でつなげます。ただし、カフェなどのフリー Wi-Fi では端末どうしの通信が遮断されていることが多く、つながりません。自宅などのネットワークで試しましょう。
動作確認: 地図の UI テストの書き方
Step2 からは、先に UI テストを書いて失敗を確認してから実装しました。地図 SDK のテストには普通の Android アプリと違う難しさがありました。
Compose のテストと Espresso の問題
最初は Compose の UI テストで書きましたが、2つの問題で動きませんでした。
- Compose のテストが間接的に使う Espresso 3.5.0 が、Android 17 で削除された
InputManager.getInstanceを呼んで失敗します。Espresso を 3.7.0 に上げると直ります。 - 地図ライブラリがメインスレッドで処理を回し続けるため、Espresso が待つ「メインスレッドが暇になる瞬間」が来ず、
AppNotIdleExceptionで失敗します。
2つ目はテストの書き方では避けられないので、操作も検証も UiAutomator で行うことにしました。
@RunWith(AndroidJUnit4::class)
class HelloMapScreenTest {
@get:Rule
val activityRule = ActivityScenarioRule(MainActivity::class.java)
private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@Test
fun tappingMarkerShowsInfoBubble() {
assertFalse(device.hasObject(By.text("Hello, MapConductor")))
tapMarkerUntilBubbleShown()
assertTrue(device.hasObject(By.text("Hello, MapConductor")))
}
}
- 吹き出しの中身は Compose の
Textなので、UiAutomator のBy.text()で見つけられます。 - マーカーの当たり判定はアイコンの矩形で行われます。 デフォルトのアイコンは下端の中央が座標に合うので、座標ちょうどではなく少し上(今回は 12dp 上)をタップしないと当たりません。
- 地図のスタイルを読み込み終わるまではマーカーが出ないので、吹き出しが出るまで間隔を空けてタップし直しています。
図形はスクショの色で確かめる
円や線は地図の描画レイヤーに直接描かれるので、UiAutomator からは見えません。そこで、次の手順で確かめました。
- 図形の内側に来るはずの地点の緯度経度を、画面上の座標に変換する。
- スクショを撮り、その点の周りの画素が図形の色(青・赤・マゼンタ)になっているかを多数決で判定する。
多数決にしたのは、地名ラベルや道路が一部の画素に重なっても誤判定しないようにするためです。緯度経度から画面座標への変換は、Step3 で触れた「Google Maps 基準のズーム」を前提にしています。
// 地図は全画面なので、カメラの中心が画面の中央に来る
private fun toScreen(point: GeoPoint, width: Int, height: Int): Pair<Int, Int> {
val worldPx = 256 * 2.0.pow(CAMERA_ZOOM) * density
val x = width / 2.0 + (point.longitude - CAMERA_CENTER.longitude) / 360.0 * worldPx
val y = height / 2.0 - (mercatorY(point.latitude) - mercatorY(CAMERA_CENTER.latitude)) * worldPx / (2 * PI)
return x.roundToInt() to y.roundToInt()
}
private fun mercatorY(latitude: Double): Double = ln(tan(PI / 4 + Math.toRadians(latitude) / 2))
実装前は3本とも「色の一致率 0%」で失敗し、実装後にパスすることを確認しています。
同じテストをプロバイダごとに回す
Step4 では JUnit の Parameterized を使って、同じテストを MapLibre と Open Mobile Maps の両方で実行しました。テストの最初に、画面上のボタンで対象のプロバイダに切り替えます。
enum class MapProvider(private val label: String) {
MapLibre("MapLibre"),
OpenMobileMaps("Open Mobile Maps"),
;
override fun toString(): String = label
}
// 起動直後は MapLibre。Open Mobile Maps は画面上の切り替えボタンで移る
fun UiDevice.showMapWith(provider: MapProvider) {
if (provider == MapProvider.MapLibre) return
val button = wait(Until.findObject(By.text("Open Mobile Maps に切り替え")), 10_000L)
?: throw AssertionError("切り替えボタンが見つかりません")
button.click()
if (!wait(Until.hasObject(By.text("MapLibre に切り替え")), 10_000L)) {
throw AssertionError("$provider に切り替わりませんでした")
}
}
@RunWith(Parameterized::class)
class HelloMapScreenTest(private val provider: MapProvider) {
companion object {
@JvmStatic
@Parameterized.Parameters(name = "{0}")
fun providers(): List<MapProvider> = MapProvider.entries
}
@get:Rule
val activityRule = ActivityScenarioRule(MainActivity::class.java)
private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@Before
fun setUp() {
device.showMapWith(provider)
}
// テスト本体は Step2 と同じ
}
「マーカー・吹き出し」の2本と「円・線・多角形」の3本をプロバイダごとに回すので、テストは全部で10本です。結果は次のとおりでした。
| MapLibre | Open Mobile Maps | |
|---|---|---|
| エミュレータ(Mac) | 5/5 パス | 2/5 パス(図形の3本が失敗) |
| 実機(Pixel 8a) | 5/5 パス | 5/5 パス |
エミュレータで Open Mobile Maps の図形テストが落ちたことで、「タップはできるのに描画されていない」ことに気づけました。図形をスクショの色で確かめるテストを書いておいてよかった場面です。
ハマりどころまとめ
- バージョンカタログのエイリアスに
forを入れると、Kotlin の予約語とぶつかってビルドが失敗する。 - AGP 9 では
appに Kotlin Android プラグインを書かなくてよい。 - MapLibre SDK のバージョンが資料ごとに違う(MapConductor のドキュメントは 13.4.1、
for-maplibre1.3.1 が依存しているのは 13.3.1)。使ったバージョンを明記しておくと安心。 - 地図のテストは、Compose のテストや Espresso ではアイドル待ちが終わらない。UiAutomator を使う。
- マーカーをタップするときは、座標の少し上を狙う。
- ズーム値は Google Maps 基準で、プロバイダをまたいで同じ縮尺になる。
- Android 17(API 37)のエミュレータは、Mac ではソフトウェア描画になることがある。
- Open Mobile Maps は OpenGL ES 3.2 必須で、Mac のエミュレータでは地図も図形も真っ白になる。タップと吹き出しは動くので気づきにくい。
- Open Mobile Maps の公式手順は minSdk 28 以上だが、AAR の宣言は 26 で、minSdk 26 のままビルドできた。
- ワイヤレスデバッグはフリー Wi-Fi だとつながらないことが多い。
まとめ
- MapConductor を使うと、MapLibre の地図に、マーカー・吹き出し・円・線・多角形を Compose らしい書き方で載せられました。APIキーも要りません。
- 地図に載せるものは
MapViewのラムダに書くだけで、プロバイダに依存しないコードになります。 - Open Mobile Maps に切り替えても、地図に載せるコードを1行も変えずに、マーカーや図形が同じ位置・同じ縮尺で描画されました。替えたのは
MapViewと、その State だけです。 - ただし、プロバイダごとに動作環境の要件は違います。Open Mobile Maps の OpenGL ES 3.2 のように、MapConductor のドキュメントに書かれていない落とし穴もあるので、プロバイダを替えたら実機でも確かめるのがおすすめです。
次はヒートマップやクラスタリング、GeoJSON も試してみたいと思います。






