|
| 1 | +# MapConductor Android SDK |
| 2 | + |
| 3 | +- [English Doc](./README.md) |
| 4 | +- [Japanese Doc](./README.ja.md) |
| 5 | + |
| 6 | +**Una sola API de mapas para Android que funciona con múltiples proveedores de mapas.** |
| 7 | + |
| 8 | +MapConductor Android SDK es una librería de mapas de código abierto para Android que te permite trabajar con múltiples SDKs de mapas a través de una API única y consistente basada en Jetpack Compose. |
| 9 | + |
| 10 | +En lugar de escribir código de mapas distinto para Google Maps, Mapbox, HERE Maps, ArcGIS y MapLibre, MapConductor ofrece abstracciones compartidas para mapas, estado de cámara, marcadores, formas, superposiciones y funciones avanzadas de mapas. |
| 11 | + |
| 12 | +Escribe tu interfaz de mapa una sola vez. |
| 13 | +Elige el proveedor de mapas que mejor se adapte a tu producto. |
| 14 | + |
| 15 | +--- |
| 16 | + |
| 17 | +## ¿Por qué MapConductor? |
| 18 | + |
| 19 | +El desarrollo de mapas para móviles suele quedar fuertemente acoplado a un SDK de mapas específico. Cada proveedor tiene su propio diseño de API, modelo de ciclo de vida, comportamiento de renderizado y conjunto de funciones. Esto dificulta cambiar de proveedor, dar soporte a varios backends de mapas o mantener limpio el código relacionado con mapas en una aplicación moderna con Compose. |
| 20 | + |
| 21 | +MapConductor resuelve esto proporcionando una capa común sobre los principales SDKs de mapas para Android. |
| 22 | + |
| 23 | +Con MapConductor puedes: |
| 24 | + |
| 25 | +* Usar una API orientada a Jetpack Compose para la interfaz de mapas |
| 26 | +* Cambiar entre los proveedores de mapas compatibles con menos trabajo de reescritura |
| 27 | +* Compartir la misma lógica de marcadores, círculos, polilíneas, polígonos y superposiciones |
| 28 | +* Construir funciones de mapas independientes del proveedor, como mapas de calor y agrupamiento de marcadores |
| 29 | +* Mantener tu código de aplicación enfocado en el comportamiento del mapa, no en las diferencias específicas de cada SDK |
| 30 | + |
| 31 | + |
| 32 | + |
| 33 | +--- |
| 34 | + |
| 35 | +## Proveedores de mapas compatibles |
| 36 | + |
| 37 | +MapConductor actualmente es compatible con los siguientes proveedores de mapas para Android: |
| 38 | + |
| 39 | +| Proveedor | Módulo | |
| 40 | +| ---------------- | --------------------------------- | |
| 41 | +| Google Maps | `com.mapconductor:for-googlemaps` | |
| 42 | +| Mapbox | `com.mapconductor:for-mapbox` | |
| 43 | +| HERE Maps | `com.mapconductor:for-here` | |
| 44 | +| ArcGIS Maps SDK | `com.mapconductor:for-arcgis` | |
| 45 | +| MapLibre | `com.mapconductor:for-maplibre` | |
| 46 | + |
| 47 | +Puedes elegir un proveedor para tu app, o estructurar tu código de modo que el proveedor pueda cambiarse más adelante. |
| 48 | + |
| 49 | +--- |
| 50 | + |
| 51 | +## Funciones principales |
| 52 | + |
| 53 | +MapConductor ofrece una API unificada para las funciones comunes de interfaz de mapas y geoespaciales: |
| 54 | + |
| 55 | +* Componentes de vista de mapa para múltiples proveedores |
| 56 | +* Estado de cámara y posición de cámara |
| 57 | +* Marcadores |
| 58 | +* Iconos de marcador personalizados |
| 59 | +* Burbujas de información escritas con Jetpack Compose |
| 60 | +* Círculos con radio en metros |
| 61 | +* Polilíneas |
| 62 | +* Polígonos |
| 63 | +* Imágenes de superficie (ground images) |
| 64 | +* Capas de teselas ráster (raster tile layers) |
| 65 | +* Mapas de calor |
| 66 | +* Agrupamiento de marcadores |
| 67 | +* Capas GeoJSON |
| 68 | +* Tipos de geometría compartidos como `GeoPoint` |
| 69 | +* Gestión de estado reactiva para objetos de mapa |
| 70 | + |
| 71 | +El objetivo no es solo envolver el SDK de cada proveedor, sino también ofrecer un comportamiento consistente, en la medida de lo posible, entre los distintos motores de mapas. |
| 72 | + |
| 73 | +--- |
| 74 | + |
| 75 | +## Instalación |
| 76 | + |
| 77 | +Agrega los repositorios de Maven Central y Google a tu proyecto de Android si aún no están configurados. |
| 78 | + |
| 79 | +```kotlin |
| 80 | +dependencyResolutionManagement { |
| 81 | + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) |
| 82 | + repositories { |
| 83 | + google() |
| 84 | + mavenCentral() |
| 85 | + } |
| 86 | +} |
| 87 | +``` |
| 88 | + |
| 89 | +Luego agrega las dependencias de MapConductor. |
| 90 | + |
| 91 | +```kotlin |
| 92 | +dependencies { |
| 93 | + implementation(platform("com.mapconductor:mapconductor-bom:<latest-version>")) |
| 94 | + |
| 95 | + implementation("com.mapconductor:core") |
| 96 | + |
| 97 | + // Elige uno o más módulos de proveedor de mapas |
| 98 | + implementation("com.mapconductor:for-googlemaps") |
| 99 | + // implementation("com.mapconductor:for-mapbox") |
| 100 | + // implementation("com.mapconductor:for-here") |
| 101 | + // implementation("com.mapconductor:for-arcgis") |
| 102 | + // implementation("com.mapconductor:for-maplibre") |
| 103 | + |
| 104 | + // Módulos de funciones opcionales |
| 105 | + implementation("com.mapconductor:icons") |
| 106 | + implementation("com.mapconductor:heatmap") |
| 107 | + implementation("com.mapconductor:marker-clustering") |
| 108 | + implementation("com.mapconductor:geojson-layer") |
| 109 | +} |
| 110 | +``` |
| 111 | + |
| 112 | +Cada proveedor de mapas puede requerir su propia clave de API, token de acceso, configuración de Gradle o configuración en el manifiesto de Android. |
| 113 | + |
| 114 | +Por favor revisa la guía de configuración del proveedor que estés usando. |
| 115 | +- [Configuración de Google Maps Android API](https://docs-android.mapconductor.com/setup/google-maps/) |
| 116 | +- [Configuración de MapBox](https://docs-android.mapconductor.com/setup/mapbox/) |
| 117 | +- [Configuración de HERE](https://docs-android.mapconductor.com/setup/here-maps/) |
| 118 | +- [Configuración de ArcGIS](https://docs-android.mapconductor.com/setup/arcgis/) |
| 119 | +- [Configuración de MapLibre](https://docs-android.mapconductor.com/setup/maplibre/) |
| 120 | + |
| 121 | +--- |
| 122 | + |
| 123 | +## Ejemplo básico |
| 124 | + |
| 125 | +El siguiente ejemplo muestra un mapa simple con Compose que incluye un marcador y un círculo. |
| 126 | + |
| 127 | +```kotlin |
| 128 | +@Composable |
| 129 | +fun SimpleMapScreen(modifier: Modifier) { |
| 130 | + val mapState = rememberMapLibreMapViewState( |
| 131 | + cameraPosition = MapCameraPosition( |
| 132 | + position = GeoPoint(35.6762, 139.6503), |
| 133 | + zoom = 15.0, |
| 134 | + ), |
| 135 | + mapDesign = MapLibreDesign.OpenMapTiles, |
| 136 | + ) |
| 137 | + |
| 138 | + MapLibreMapView( |
| 139 | + modifier = modifier, |
| 140 | + state = mapState, |
| 141 | + ) { |
| 142 | + Marker( |
| 143 | + state = MarkerState( |
| 144 | + position = GeoPoint(35.6762, 139.6503), |
| 145 | + ) |
| 146 | + ) |
| 147 | + |
| 148 | + Circle( |
| 149 | + state = CircleState( |
| 150 | + center = GeoPoint(35.6762, 139.6503), |
| 151 | + radiusMeters = 500.0, |
| 152 | + fillColor = Color.Green.copy(alpha = 0.5f), |
| 153 | + strokeColor = Color.Blue, |
| 154 | + strokeWidth = 3.dp, |
| 155 | + ) |
| 156 | + ) |
| 157 | + } |
| 158 | +} |
| 159 | +``` |
| 160 | + |
| 161 | +Este ejemplo usa MapLibre Maps, pero los objetos del mapa están escritos usando conceptos de MapConductor. La misma lógica de superposiciones se puede adaptar a otros proveedores compatibles. |
| 162 | + |
| 163 | + |
| 164 | + |
| 165 | +--- |
| 166 | + |
| 167 | +## Cambiar de proveedor de mapas |
| 168 | + |
| 169 | +Una de las ideas principales detrás de MapConductor es que tus superposiciones de mapa no deberían tener que reescribirse cuando cambias de proveedor de mapas. |
| 170 | + |
| 171 | +Por ejemplo: |
| 172 | + |
| 173 | +- MapLibre |
| 174 | + |
| 175 | + ```kotlin |
| 176 | + val initCameraPosition = MapCameraPosition(...) |
| 177 | + |
| 178 | + val mapLibreMapState = rememberMapLibreMapViewState( |
| 179 | + cameraPosition = initCameraPosition, |
| 180 | + mapDesign = mapDesign = MapLibreDesign.OpenMapTiles, |
| 181 | + ) |
| 182 | + |
| 183 | + MapLibreMapView(state = mapLibreMapState) { |
| 184 | + MapContent() |
| 185 | + } |
| 186 | + ``` |
| 187 | + |
| 188 | +- <details> |
| 189 | + <summary>Google Maps (Toca para abrir)</summary> |
| 190 | + |
| 191 | + ```kotlin |
| 192 | + val initCameraPosition = MapCameraPosition(...) |
| 193 | + |
| 194 | + val googleMapState = rememberGoogleMapViewState( |
| 195 | + cameraPosition = initCameraPosition, |
| 196 | + mapDesign = GoogleMapDesign.Normal, |
| 197 | + ) |
| 198 | + |
| 199 | + GoogleMapView(state = googleMapState) { |
| 200 | + MapContent() |
| 201 | + } |
| 202 | + ``` |
| 203 | +</details> |
| 204 | + |
| 205 | +- <details> |
| 206 | + <summary>Mapbox (Toca para abrir)</summary> |
| 207 | + |
| 208 | + ```kotlin |
| 209 | + val initCameraPosition = MapCameraPosition(...) |
| 210 | + |
| 211 | + val mapboxMapState = rememberMapboxMapViewState( |
| 212 | + cameraPosition = initCameraPosition, |
| 213 | + mapDesign = MapboxMapDesign.Standard, |
| 214 | + ) |
| 215 | + |
| 216 | + MapboxMapView(state = mapboxMapState) { |
| 217 | + MapContent() |
| 218 | + } |
| 219 | + ``` |
| 220 | +</details> |
| 221 | + |
| 222 | +- <details> |
| 223 | + <summary>HERE (Toca para abrir)</summary> |
| 224 | + |
| 225 | + ```kotlin |
| 226 | + val initCameraPosition = MapCameraPosition(...) |
| 227 | + |
| 228 | + val hereMapState = rememberHereMapViewState( |
| 229 | + cameraPosition = initCameraPosition, |
| 230 | + mapDesign = HereMapDesign.NormalDay, |
| 231 | + ) |
| 232 | + |
| 233 | + HereMapView(state = hereMapState) { |
| 234 | + MapContent() |
| 235 | + } |
| 236 | + ``` |
| 237 | +</details> |
| 238 | + |
| 239 | +- <details> |
| 240 | + <summary>ArcGIS 2D (Toca para abrir)</summary> |
| 241 | + |
| 242 | + ```kotlin |
| 243 | + val initCameraPosition = MapCameraPosition(...) |
| 244 | + |
| 245 | + val arcgisMapState = rememberArcGISMapViewState( |
| 246 | + cameraPosition = initCameraPosition, |
| 247 | + mapDesign = ArcGISDesign.Streets, |
| 248 | + ) |
| 249 | + |
| 250 | + ArcGISMapView2D(state = arcgisMapState) { |
| 251 | + MapContent() |
| 252 | + } |
| 253 | + ``` |
| 254 | +</details> |
| 255 | + |
| 256 | +- <details> |
| 257 | + <summary>ArcGIS 3D (Toca para abrir)</summary> |
| 258 | + |
| 259 | + ```kotlin |
| 260 | + val initCameraPosition = MapCameraPosition(...) |
| 261 | + |
| 262 | + val arcgisMapState = rememberArcGISMapViewState( |
| 263 | + cameraPosition = initCameraPosition, |
| 264 | + mapDesign = ArcGISDesign.Streets, |
| 265 | + ) |
| 266 | + |
| 267 | + ArcGISMapView(state = arcgisMapState) { |
| 268 | + MapContent() |
| 269 | + } |
| 270 | + ``` |
| 271 | +</details> |
| 272 | + |
| 273 | +Tu contenido de mapa reutilizable puede incluir marcadores, círculos, polilíneas, polígonos, mapas de calor, agrupaciones u otros componentes de MapConductor. |
| 274 | + |
| 275 | +```kotlin |
| 276 | +@Composable |
| 277 | +fun MapContent() { |
| 278 | + Marker( |
| 279 | + state = rememberMarkerState( |
| 280 | + position = GeoPoint(35.6762, 139.6503), |
| 281 | + ) |
| 282 | + ) |
| 283 | + |
| 284 | + Polyline( |
| 285 | + state = rememberPolylineState( |
| 286 | + points = listOf( |
| 287 | + GeoPoint(35.6762, 139.6503), |
| 288 | + GeoPoint(35.6895, 139.6917), |
| 289 | + ) |
| 290 | + ) |
| 291 | + ) |
| 292 | +} |
| 293 | +``` |
| 294 | + |
| 295 | +Aún se requiere una configuración específica por proveedor, pero la interfaz de mapas a nivel de aplicación puede ser mucho más portable. |
| 296 | + |
| 297 | +--- |
| 298 | + |
| 299 | +## Resumen de módulos |
| 300 | + |
| 301 | +| Módulo | Artefacto | Descripción | |
| 302 | +| ----------------- | ------------------------------------ | --------------------------------------------------------------------- | |
| 303 | +| BOM | `com.mapconductor:mapconductor-bom` | Alinea las versiones de los módulos de MapConductor | |
| 304 | +| Core | `com.mapconductor:core` | Abstracciones principales, tipos de geometría, estado de cámara y de superposiciones | |
| 305 | +| Google Maps | `com.mapconductor:for-googlemaps` | Implementación del proveedor Google Maps | |
| 306 | +| Mapbox | `com.mapconductor:for-mapbox` | Implementación del proveedor Mapbox | |
| 307 | +| HERE Maps | `com.mapconductor:for-here` | Implementación del proveedor HERE Maps | |
| 308 | +| ArcGIS | `com.mapconductor:for-arcgis` | Implementación del proveedor ArcGIS | |
| 309 | +| MapLibre | `com.mapconductor:for-maplibre` | Implementación del proveedor MapLibre | |
| 310 | +| Icons | `com.mapconductor:icons` | Iconos de marcador basados en Compose y utilidades de burbujas de información | |
| 311 | +| Heatmap | `com.mapconductor:heatmap` | Superposición de mapa de calor independiente del proveedor | |
| 312 | +| Marker Clustering | `com.mapconductor:marker-clustering` | Soporte de agrupamiento de marcadores | |
| 313 | +| GeoJSON Layer | `com.mapconductor:geojson-layer` | Soporte de capas GeoJSON | |
| 314 | + |
| 315 | +--- |
| 316 | + |
| 317 | +## Estado de las funciones |
| 318 | + |
| 319 | +| Función | Google Maps | Mapbox | HERE Maps | ArcGIS | MapLibre | |
| 320 | +| ------------------ | ----------: | ------: | --------: | ------: | -------: | |
| 321 | +| Map | ✅ | ✅ | ✅ | ✅ | ✅ | |
| 322 | +| Marker | ✅ | ✅ | ✅ | ✅ | ✅ | |
| 323 | +| Circle | ✅ | ✅ | ✅ | ✅ | ✅ | |
| 324 | +| Polyline | ✅ | ✅ | ✅ | ✅ | ✅ | |
| 325 | +| Polygon | ✅ | ✅ | ✅ | ✅ | ✅ | |
| 326 | +| Ground Image | ✅ | ✅ | ✅ | ✅ | ✅ | |
| 327 | +| Heatmap | ✅ | ✅ | ✅ | ✅ | ✅ | |
| 328 | +| Marker Clustering | ✅ | ✅ | ✅ | ✅ | ✅ | |
| 329 | +| Raster Tile Layer | ✅ | ✅ | ✅ | ✅ | ✅ | |
| 330 | +| Vector Tile Layer | Planned | Planned | Planned | Planned | Planned | |
| 331 | + |
| 332 | +MapConductor está en desarrollo activo. Consulta la documentación y las notas de la versión para conocer el comportamiento y las limitaciones más recientes de cada proveedor. |
| 333 | + |
| 334 | +--- |
| 335 | + |
| 336 | +## ¿Para quién es esto? |
| 337 | + |
| 338 | +MapConductor te resulta útil si estás: |
| 339 | + |
| 340 | +* Construyendo una app de Android con Jetpack Compose y mapas |
| 341 | +* Evaluando múltiples proveedores de mapas |
| 342 | +* Planeando una posible migración de un SDK de mapas a otro |
| 343 | +* Manteniendo funciones de mapas para distintos requisitos de clientes o regiones |
| 344 | +* Construyendo componentes de interfaz de mapas reutilizables |
| 345 | +* Buscando una capa de abstracción de código abierto para mapas móviles |
| 346 | + |
| 347 | +Es especialmente útil cuando quieres que tu código de aplicación describa qué debe aparecer en el mapa, en lugar de cómo espera cada SDK de proveedor que se implemente esa función. |
| 348 | + |
| 349 | +--- |
| 350 | + |
| 351 | +## Documentación |
| 352 | + |
| 353 | +La documentación está disponible en: |
| 354 | + |
| 355 | +```text |
| 356 | +https://docs-android.mapconductor.com/ |
| 357 | +``` |
| 358 | + |
| 359 | +La documentación incluye: |
| 360 | + |
| 361 | +* Guías de introducción |
| 362 | +* Configuración específica por proveedor |
| 363 | +* Componentes de vista de mapa |
| 364 | +* Gestión de estado |
| 365 | +* Manejo de eventos |
| 366 | +* Clases principales de geometría |
| 367 | +* Iconos de marcador |
| 368 | +* Mapas de calor |
| 369 | +* Agrupamiento de marcadores |
| 370 | +* Capas GeoJSON |
| 371 | + |
| 372 | +--- |
| 373 | + |
| 374 | +## Estado del proyecto |
| 375 | + |
| 376 | +MapConductor Android SDK ya está publicado y se encuentra en desarrollo activo. |
| 377 | + |
| 378 | +El proyecto busca hacer que el desarrollo de mapas sea más flexible, portable y amigable con Compose en los principales proveedores de mapas para Android. Algunas funciones avanzadas pueden seguir siendo experimentales o presentar diferencias específicas por proveedor. |
| 379 | + |
| 380 | +Los comentarios, reportes de errores y contribuciones son bienvenidos. |
| 381 | + |
| 382 | +--- |
| 383 | + |
| 384 | +## Licencia |
| 385 | + |
| 386 | +MapConductor Android SDK se publica bajo la Licencia Apache 2.0. |
0 commit comments