Documentación / Conceptos / Arquitectura

Resumen de la arquitectura

MapConductor actúa como puente entre la aplicación y varios SDK de mapas. La aplicación solo llama a la API de mapas unificada, y MapConductor envía el procesamiento al proveedor seleccionado. En Android (Kotlin + Compose), iOS (Swift + SwiftUI) y React (Web), la división de paquetes y la distribución interna de responsabilidades tienen el mismo diseño.

ANDROID
android-sdk-core
iOS
ios-sdk-core
REACT
js-sdk-core / js-sdk-react

01 · Imagen general

El flujo del proceso es el mismo en cualquier plataforma: Aplicación → API de mapas unificada → Core → Controladores de SDK de mapas → SDK de mapas. Solo las 2 capas superiores son el código escrito por la aplicación; las 2 capas inferiores se pueden reemplazar.

APP

IU y lógica de negocio

React · Compose · SwiftUI
UNIFIED API

API de mapas unificada

MapViewState · Marker · Camera
CORE

Funciones básicas (mapa, marcadores, formas, eventos)

Manager · Controller · Overlay
DRIVER

Controladores de proveedor

*-for-googlemaps / -maplibre / …
MAP SDK

SDK de mapas (nativos / JavaScript)

Google Maps · MapLibre · Mapbox · MapKit · ArcGIS · HERE …

Al cambiar de proveedor, solo se reemplazan los 2 niveles más bajos. Como el código de la interfaz está escrito para la API unificada, funciona tal cual.

Plataforma

02 · Configuración por plataforma

Core y los controladores están separados como paquetes. La aplicación solo añade Core y el controlador del proveedor que utiliza como dependencias.

android-sdk-core tiene el modelo común y la aplicación de diferencias, mientras que android-sdk-compose proporciona contenedores de estado para Compose. GeoJSON, agrupación y mapas de calor son independientes como módulos adicionales (android-geo-layer / android-marker-clustering / android-heatmap).

03 · Composición de capas

Para que se puedan reutilizar en diferentes plataformas, las responsabilidades se dividen en 6 capas. Las capas superiores no conocen las implementaciones de las capas inferiores.

#
Capa
Rol
1
Framework de UI
IU declarativa que usa la aplicación, como React / Vue / Jetpack Compose / SwiftUI, etc.
2
API de mapas unificada
La API de MapConductor que trata marcadores, formas, cámara y eventos con conceptos comunes. El código que realmente escribe la aplicación se escribe contra esta.
3
Puente
Puentea las operaciones de la API unificada hacia abajo según el entorno de ejecución. No es necesario cuando la UI y el renderizado se completan en el mismo entorno de ejecución; interviene solo cuando ambos están separados en diferentes entornos de ejecución.
4
Capa multiplataforma
El método de integración y declaración del SDK de mapas nativo varía según la plataforma solo en esta capa.
5
SDK nativo / controlador
La capa que realmente se encarga del renderizado de cámara, estilo y superposiciones (nativo para Android / iOS o el controlador JS en Web).
6
SDK de mapas
Las entidades reales como Google Maps / MapKit / MapLibre / Mapbox / ArcGIS / HERE, etc.

Gracias a esta separación, el código que se centra en “qué hacer con el mapa” en lugar de “qué plataforma” se puede desplegar tal cual en múltiples entornos. Las diferencias específicas de la plataforma se limitan, en principio, solo a los métodos de instalación / declaración de la capa multiplataforma.

En el caso de React Native

Web y React Native comparten el código que escribe la aplicación. Los objetos de estado y los componentes también son los mismos; solo debe cambiar el MapView que elija. La diferencia está debajo. En Web, el controlador invoca una biblioteca de mapas JavaScript en el mismo entorno de ejecución, mientras que en React Native pasa a través de un puente al SDK nativo de MapConductor y, finalmente, los SDK de mapas nativos realizan el renderizado.

Dónde diverge el mismo código
SHARED

Lo que escribe la app

js-sdk-core · js-sdk-react
WEB

React

DRIVER
Controlador de JavaScript
react-for-*
Sin puente: un solo entorno de ejecución
MAP SDK
SDK de mapas de JavaScript
Google Maps · MapLibre · Leaflet · Cesium …
REACT NATIVE

React Native

DRIVER
Controlador que delega en el código nativo
reactnative-for-*
BRIDGE
Módulo nativo de RN
Capa 3
NATIVE SDK
SDK nativo de MapConductor → SDK de mapas
Google Maps · MapLibre · ArcGIS · HERE

La capa 3 en la tabla de arriba es el puente. En Web no interviene, ya que la interfaz de usuario y el renderizado se completan en el mismo entorno de ejecución. En React Native, como ambos se separan en diferentes entornos de ejecución, se necesita esta capa. Solo esta capa varía según la plataforma; por encima, no hay cambios.

Los proveedores que se pueden usar con React Native son Google Maps, MapLibre, ArcGIS y HERE, en total 4. Como se limitan a aquellos que tienen un módulo correspondiente en el lado nativo, son menos que los 13 proveedores de Web.

04 · Estructura interna de Core

Core está estructurado de manera que repite los mismos 7 roles para cada elemento, como marcadores, polilíneas, polígonos, círculos, imágenes de suelo y capas ráster. Si entiende uno, puede seguir los demás elementos de la misma forma.

Rol
Responsabilidad
Lugar de implementación
State
Valores inmutables que pasa la aplicación. Coordenadas, color, zIndex, etc. Devuelve un hash del contenido con fingerPrint().
core
Entity
Un registro que agrupa State, el objeto realmente creado por el proveedor y el fingerPrint de ese momento.
core
Manager
Registro que mantiene Entity por id. También se encarga de las pruebas de impacto desde coordenadas (find).
core
Controller
Ventanilla de operaciones con add / update / clear / find / onCameraChanged / destroy. Realiza la determinación de diferencias.
core
Overlay
Unidad de dibujo que agrupa elementos del mismo tipo. Determina el orden de superposición mediante zIndex.
core
OverlayRenderer
Convierte onAdd / onChange / onRemove / onPostProcess en llamadas a los SDK de mapas respectivos. Simplemente herede las clases abstractas preparadas para cada elemento (como AbstractPolygonOverlayRenderer) e implemente los 3 métodos.
driver
Capable
Declara como tipo qué elementos puede manejar ese proveedor (compositionPolygons / updatePolygon / hasPolygon). Se prepara uno para cada elemento y se denomina, por ejemplo, PolygonCapableInterface en Kotlin y PolygonCapable en TypeScript. Swift no lo expresa como un protocolo, sino por si ese proveedor tiene un PolygonController.
driver

Lo importante es la posición del límite. El lado Core (State / Entity / Manager / Controller / Overlay) está escrito en un código casi idéntico en los 3 idiomas, y para cada proveedor solo hay que escribir el Renderer y la declaración de que puede manejar esos elementos.

ANDROID · Kotlin
iOS · Swift
REACT · TypeScript
core/polygon/PolygonManager.kt
PolygonCapableInterface.kt
AbstractPolygonOverlayRenderer.kt
polygon/PolygonManager.swift
polygon/PolygonOverlayRenderer.swift
polygon/PolygonHoleSplit.swift
polygon/PolygonManager.ts
polygon/PolygonCapable.ts
AbstractPolygonOverlayRenderer.ts

05 · Flujo de aplicación de diferencias

La aplicación solo pasa una "matriz del estado que debería existir ahora". Core calcula la diferencia con la vez anterior, la divide en agregados, cambiados y eliminados y la pasa al controlador. Como no se recrean los objetos del mapa, el renderizado es estable incluso con una gran cantidad de elementos.

controller/OverlayRendererInterface.ts · Contrato común para 3 plataformas
export interface OverlayRendererInterface<ActualType, StateType, EntityType> {
    onAdd(data: StateType[]): Promise<Array<ActualType | null>> | Array<ActualType | null>;
    onChange(data: Array<ChangeParamsInterface<EntityType>>): Promise<Array<ActualType | null>> | Array<ActualType | null>;
    onRemove(data: EntityType[]): Promise<void> | void;
    onPostProcess(): Promise<void> | void;
}

onChange recibe tanto la Entity anterior (prev) como el State actual (current). El controlador puede actualizar solo las propiedades cambiadas y la firma es la misma en Kotlin / Swift.

06 · Cosas que el controlador debe implementar

El trabajo para soportar un nuevo SDK de mapas se limita a heredar del renderizador abstracto para cada elemento y rellenar las 3 operaciones. No se toca el modelo de Core ni la lógica de diferencias.

android-for-googlemaps · Implementación del renderizador
// El driver hereda del renderizador abstracto y solo implementa tres operaciones
internal class GoogleMapPolygonOverlayRenderer(
    override val holder: GoogleMapViewHolder,
    override val coroutine: CoroutineScope,
) : AbstractPolygonOverlayRenderer<GoogleMapActualPolygon>() {

    override suspend fun createPolygon(state: PolygonState) = /* map.addPolygon(...) */
    override suspend fun updatePolygonProperties(polygon, current, prev) = /* Aplica solo la diferencia */
    override suspend fun removePolygon(entity: PolygonEntityInterface<GoogleMapActualPolygon>) =
        entity.polygon.remove()
}

Solo las 3 operaciones crear, actualizar y eliminar son específicas del proveedor. La determinación de diferencias, la gestión del registro y la prueba de impacto se llaman después de que Core ya las haya completado.

07 · Alcance de la abstracción y vías de escape

MapConductor no envuelve todas las funciones de cada SDK de mapas. Se enfoca en operaciones comúnmente utilizadas y, para requisitos que exceden esto, prepara dos vías de escape.

getMapViewHolder() · Llamar directamente a funciones nativas
// map de la interfaz común es unknown: acótalo al tipo del proveedor antes de usarlo
const holder = mapViewState.getMapViewHolder();
const map = holder?.map as maplibregl.Map | undefined;

map?.addLayer({ id: 'buildings', type: 'fill-extrusion', source: 'composite' });

Un diseño que mantiene la API común simple y, al mismo tiempo, no sacrifica las fortalezas específicas de cada proveedor. Para más detalles, consulte "Extensiones nativas".

Páginas relacionadas