Cambiar proveedor
Lo único que varía entre los proveedores son tres cosas: los módulos dependientes, el tipo de vista de mapa y el tipo de objeto de estado. La forma de escribir marcadores, figuras, operaciones de cámara y eventos no cambia. También puede colocar varios proveedores en la misma pantalla y cambiarlos en tiempo de ejecución.
01 · Qué cambia y qué permanece igual
- Módulos de dependencia (for-maplibre → for-googlemaps, etc.)
- Tipo de vista de mapa (MapLibreMapView → GoogleMapView)
- Tipo del objeto de estado y su función de generación
- Constantes de diseño que se pasan a mapDesignType
- Cómo obtener una clave de API y las prácticas de inicialización
- GeoPoint · GeoRectBounds · MapCameraPosition
- MarkerState · PolylineState · PolygonState · CircleState …
- moveCameraTo() · fitBounds() · controladores de eventos
- Cálculos geográficos (distancia, rumbo, área)
- Capas extendidas (agrupación, mapa de calor, GeoJSON)
Si bien el tipo de objeto de estado está separado para cada proveedor, implementa una interfaz común (Android: MapViewStateInterface, iOS: MapViewStateProtocol, React: MapViewStateInterface). Las operaciones de cámara y el cambio de diseño se pueden escribir a través de esta interfaz común.





02 · Tipos por proveedor
Una lista de las vistas de mapa y objetos de estado que expone cada proveedor. Debido a razones históricas, hay lugares donde los nombres no coinciden completamente, por lo que se muestran los nombres tal como se exportan realmente.
rememberGoogleMapViewState
GoogleMapViewState
GoogleMapViewState
useGoogleMapViewState
rememberMapLibreMapViewState
MapLibreViewState
MapLibreViewState
useMapLibreViewState
rememberMapboxMapViewState
MapboxViewState
MapboxViewState
useMapboxViewState
rememberHereMapViewState
HereViewState
HereMapViewState
useHereViewState
rememberArcGISMapViewState
ArcGISMapViewState
ArcGISMapViewState
useArcGISViewState
rememberMapTilerMapViewState
MapTilerViewState
MapTilerViewState
useMapTilerViewState
rememberTomTomMapViewState
TomTomMapViewState
TomTomMapViewState
useTomTomViewState
rememberLongdoMapViewState
LongdoViewState
LongdoViewState
useLongdoViewState
MapKitViewState
useMapKitViewState
useLeafletMapViewState
useOpenLayersMapViewState
useAzureMapsViewState
useCesiumMapViewState
"/ 2D" indica que hay dos vistas: una vista 3D y una vista 2D. Ambas comparten el mismo objeto de estado y, en 2D, tilt siempre es 0.
03 · Cómo escribir el cambio
Cuando desee cambiar en tiempo de ejecución, mantenga un objeto de estado para cada proveedor y bifurque solo la vista que se muestra. La descripción de las superposiciones se puede colocar fuera de la bifurcación. La aplicación de ejemplo tiene esta forma.
@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 */ }
}
}
// Quien llama escribe solo las capas
MapViewContainer(state = selectedState) {
Markers(markerStates)
}@StateObject private var googleState = GoogleMapViewState(cameraPosition: initial)
@StateObject private var mapLibreState = MapLibreViewState(cameraPosition: initial)
// A través de la interfaz común, el trabajo de cámara no necesita ramificaciones
private var activeState: any MapViewStateProtocol {
provider == .googleMaps ? googleState : mapLibreState
}
@ViewBuilder
private var mapView: some View {
switch provider {
case .googleMaps:
GoogleMapView(state: googleState, sdkInitialize: {
GMSServices.provideAPIKey(apiKey)
}) { Marker(state: markerState) }
case .mapLibre:
MapLibreMapView(state: mapLibreState) { Marker(state: markerState) }
}
}// Llama a los hooks de forma fija por componente y cambia solo la vista
const maplibre = useMapLibreViewState({ id: 'maplibre', cameraPosition: INIT });
const google = useGoogleMapViewState({ id: 'google', cameraPosition: INIT });
switch (provider) {
case 'maplibre':
return <MapLibreMapView2D state={maplibre}>{children}</MapLibreMapView2D>;
case 'google-maps':
return <GoogleMapView2D state={google}>{children}</GoogleMapView2D>;
}En React, no se puede cambiar el orden de las llamadas a los hooks, por lo que es seguro extraer las vistas de cada proveedor en componentes separados y llamar a los hooks dentro de ese componente. El directorio providers/ de la aplicación de ejemplo tiene esa configuración.
// 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 · Manejo de las diferencias entre proveedores
No todos los SDK de mapas tienen las mismas funciones. MapConductor cubre las diferencias donde puede y proporciona representaciones alternativas donde no puede.
Si la funcionalidad no está disponible de forma nativa, el SDK la renderiza como teselas de trama. Esto incluye huecos en polígonos y el renderizado masivo de marcadores. El código de llamada no cambia.
Para los elementos que ese proveedor no puede manejar, el controlador no tiene un renderizador compatible. Se puede saber si se puede usar en tiempo de compilación o por el tipo del objeto de estado.
Si de verdad necesita la funcionalidad específica de ese proveedor, puede obtener la instancia del mapa nativo desde `MapViewHolder` y llamarla directamente.
Las claves y la inicialización son por proveedor
`MapConductor` no recibe claves de API. Las pasa tal cual en la forma que cada SDK de mapas requiere (manifiesto de Android, `sdkInitialize` en iOS, objeto de configuración en Web). También hay proveedores como `MapLibre`, `Leaflet` y `OpenLayers` que no necesitan claves; en ese caso solo se determina la fuente de las teselas.