Blog

Tutorial completo: implementar Google Maps en React Native con mapas interactivos

Tabla de Contenidos

En la actualidad, añadir mapas a aplicaciones móviles es un requisito esencial debido a funcionalidades como tracking, navegación o mostrar ubicaciones de usuarios. En Juice Studio, desarrollamos aplicaciones con React Native que están diseñadas para ayudarte a construir productos capaces de obtener la ubicación de manera eficiente.

En este post, te mostraremos cómo implementar Google Maps en React Native utilizando react-native-maps en un proyecto React Native. Te guiaremos a través del setup necesario, configuraciones y permisos, y mostraremos una vista de mapa. Al completar este tutorial, estarás preparado para cualquier aplicación que desees construir, ya sea una simple pantalla de mapa o funcionalidades más complejas.

Tutorial completo: implementar Google Maps en React Native con mapas interactivos | 5

Prerrequisitos para implementar Google Maps en React Native

Verifica que tengas todas las herramientas de React Native configuradas en tu sistema. Si aún no está configurada, puedes completar la guía oficial de configuración de React Native.

Qué aprenderás en este tutorial para implementar Google Maps en React Native

En esta guía, recorreremos los aspectos clave de trabajar con mapas en un proyecto React Native CLI, incluyendo:

  1. Introducción a React Native Maps con la librería react-native-maps
  2. Instalación y configuración completa paso a paso
  3. Solicitar y manejar permisos de ubicación
  4. Crear una pantalla de ejemplo con vista de mapa
  5. Mostrar la ubicación actual del usuario en el mapa
  6. Dibujar una polilínea entre dos coordenadas
  7. Usar Google Maps Directions API para características avanzadas

Introducción a React Native Maps para implementar Google Maps en React Native

React-native-maps es una librería popular para integrar mapas en aplicaciones Android e iOS desarrolladas usando React Native. Tiene componentes principales como MapView y Marker. Estos te ayudan a mostrar mapas, dar pins y manejar interacciones de usuario como toques y gestos.

Características clave al implementar Google Maps en React Native:

  • Utiliza servicios de mapas nativos para rendimiento óptimo
  • Funciona con Google Maps en Android e iOS
  • Compatibilidad con Apple Maps en iOS como alternativa
  • Amplia personalización: tipos de mapas, controles de zoom, overlays y marcadores
  • Funcionalidades avanzadas: clustering, mapas offline, estilos personalizados

Para empezar a implementar Google Maps en React Native, instala los siguientes paquetes:

npm install react-native-maps
npm install react-native-geolocation-service
npm install react-native-permissions

Qué hace cada paquete para implementar Google Maps en React Native:

  • react-native-maps: Se usa para mostrar y controlar la vista del mapa
  • react-native-geolocation-service: Ofrece la ubicación del dispositivo con mayor precisión
  • react-native-permissions: Se usa para solicitar y verificar permisos de ubicación para Android e iOS
Tutorial completo: implementar Google Maps en React Native con mapas interactivos | 6

Configuración de React Native Maps para iOS

Paso 1: Configurar Podfile

Añade la siguiente dependencia a tu Podfile ubicado en el directorio ios:

pod 'react-native-maps', :path => '../node_modules/react-native-maps', :subspecs => ['Google']

Paso 2: Actualizar script de permisos

Actualiza tu Podfile con el siguiente script para manejar la configuración de permisos correctamente:

def node_require(script)
  # Resolve script with node to allow for hoisting
  require Pod::Executable.execute_command('node', ['-p',
    "require.resolve(
      '#{script}',
      {paths: [process.argv[1]]},
    )", __dir__]).strip
end

node_require('react-native/scripts/react_native_pods.rb')
node_require('react-native-permissions/scripts/setup.rb')

setup_permissions([
  'LocationAccuracy',
  'LocationAlways',
  'LocationWhenInUse',
])

Paso 3: Instalar pods

Ejecuta el comando pod install para instalar los pods:

cd ios && pod install

Configuración de React Native Maps para Android

Paso 1: Configurar build.gradle de la app

Añade la siguiente dependencia a tu archivo android/app/build.gradle dentro del bloque dependencies:

implementation ("com.google.android.gms:play-services-location:21.1.0")

Paso 2: Configurar build.gradle del proyecto

Añade la siguiente configuración a tu archivo android/build.gradle fuera del bloque buildscript (a nivel raíz):

allprojects {
  configurations.all {
    resolutionStrategy {
      force 'com.google.android.gms:play-services-location:21.1.0'
    }
  }
}

Esto asegura que se use consistentemente la misma versión de play-services-location en todas las librerías, evitando crashes en tiempo de ejecución causados por desajustes de versión.

Solicitar y manejar permisos de ubicación al implementar Google Maps en React Native

iOS – Añade las siguientes descripciones de permisos en Info.plist:

<key>NSLocationWhenInUseUsageDescription</key>
<string>Esta app requiere acceso a tu ubicación para mostrar tu posición actual en el mapa</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Esta app requiere acceso a tu ubicación para mostrar tu posición actual en el mapa</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Esta app requiere acceso a tu ubicación para mostrar tu posición actual en el mapa</string>

Android – Añade los siguientes permisos en AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Crear utility para manejar permisos

Vamos a crear un archivo utility PermissionHandler.ts para manejar toda la lógica relacionada con permisos:

import { PermissionsAndroid, Platform } from "react-native";
import { PERMISSIONS, request, RESULTS } from "react-native-permissions";

export const requestLocationPermission = async (): Promise<boolean> => {
  try {
    if (Platform.OS === "android") {
      const granted = await PermissionsAndroid.request(
        PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION
      );
      return granted == PermissionsAndroid.RESULTS.GRANTED;
    } else {
      const result = await request(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE);
      console.log(result);
      return (result == RESULTS.GRANTED || result == RESULTS.LIMITED);
    }
  } catch (error) {
    console.warn("Permission error:", error);
    return false;
  }
};

Crear pantalla de ejemplo con vista de mapa

Vamos a crear una pantalla llamada HomeScreen. Para mantener todas las pantallas organizadas, comienza creando una carpeta src. Dentro de la carpeta src, crea una carpeta llamada screens, y dentro de esa, un archivo llamado HomeScreen.tsx.

Código básico para implementar Google Maps en React Native:

import React from 'react';
import { View } from 'react-native';
import MapView from 'react-native-maps';

const HomeScreen = () => {
  return (
    <View style={{ flex: 1 }}>
      <MapView 
        style={{ flex: 1 }} 
        provider="google" 
        initialRegion={{
          latitude: 40.4168,
          longitude: -3.7038,
          latitudeDelta: 0.001,
          longitudeDelta: 0.001,
        }}
      />
    </View>
  );
};

export default HomeScreen;

Explicación del código para implementar Google Maps en React Native:

  • style={{ flex: 1 }}: Se aplica tanto al View como al MapView para que el mapa cubra todo el espacio de pantalla disponible
  • provider=»google»: Especifica que Google Maps debe usarse como proveedor del mapa
  • initialRegion: Establece la posición inicial del mapa y nivel de zoom con valores de latitud, longitud y delta

Configurar API Key de Google Maps

iOS (en AppDelegate.swift):

import GoogleMaps
GMSServices.provideAPIKey("YOUR_GOOGLE_MAPS_API_KEY")

Android (en AndroidManifest.xml):

<meta-data 
  android:name="com.google.android.geo.API_KEY"
  android:value="YOUR_GOOGLE_MAPS_API_KEY"/>

Mostrar la ubicación actual del usuario al implementar Google Maps en React Native

Para mostrar la ubicación actual del usuario en el mapa, primero necesitamos obtenerla. Esto involucra solicitar permiso del usuario para acceder a su ubicación.

Implementación completa con geolocalización:

import { useEffect, useRef, useState } from "react";
import { View, Alert } from "react-native";
import MapView, { Marker, Region } from 'react-native-maps';
import Geolocation from 'react-native-geolocation-service';
import type MapViewType from 'react-native-maps';
import { requestLocationPermission } from "../../utils/PermissionHandler";

type Location = {
  latitude: number;
  longitude: number;
};

const HomeScreen = () => {
  const [location, setLocation] = useState<Location | null>(null);
  const [region, setRegion] = useState<Region>({
    latitude: 0,
    longitude: 0,
    latitudeDelta: 0.01,
    longitudeDelta: 0.01,
  });
  const mapRef = useRef<MapViewType | null>(null);

  useEffect(() => {
    const getLocation = async () => {
      const hasPermission = await requestLocationPermission();
      if (!hasPermission) {
        Alert.alert('Permiso Denegado', 'Se requiere acceso a la ubicación.');
        return null;
      }

      Geolocation.getCurrentPosition(position => {
        const { latitude, longitude } = position.coords;
        const userLocation = { latitude, longitude };
        setLocation(userLocation);
        
        const newRegion = {
          ...userLocation,
          latitudeDelta: 0.01,
          longitudeDelta: 0.01,
        };
        setRegion(newRegion);

        if (mapRef.current) {
          mapRef.current.animateToRegion(newRegion, 1000);
        }
      }, error => {
        Alert.alert('Error', error.message);
      }, {
        enableHighAccuracy: true,
        timeout: 15000,
        maximumAge: 10000,
      });
    };

    getLocation();
  }, []);

  return (
    <View style={{ flex: 1 }}>
      <MapView 
        ref={mapRef} 
        style={{ flex: 1 }} 
        provider="google"
        region={region}
      >
        {location && (
          <Marker
            coordinate={location}
            title="Estás aquí"
            description="Ubicación actual"
          />
        )}
      </MapView>
    </View>
  );
};

export default HomeScreen;

Dibujar polilínea entre dos coordenadas

Para conectar la ubicación del usuario con un destino, vamos a implementar Google Maps en React Native con Polyline:

import { Polyline } from 'react-native-maps';

// Añadir destino
const destination = {
  latitude: 40.4178,
  longitude: -3.7040,
};

// Reemplazar el código animateToRegion existente:
if (mapRef.current) {
  mapRef.current.fitToCoordinates(
    [userLocation, destination],
    {
      edgePadding: { top: 80, right: 80, bottom: 80, left: 80 },
      animated: true,
    }
  );
}

// Dentro del MapView, añadir:
<Marker coordinate={destination} title="Destino" />
<Polyline 
  coordinates={[location, destination]} 
  strokeColor="#1E90FF" 
  strokeWidth={4} 
/>

Implementar Google Maps Directions API para características avanzadas

Para mostrar rutas reales utilizando Google Directions API al implementar Google Maps en React Native:

type LatLng = {
  latitude: number;
  longitude: number;
};

const fetchRouteCoordinates = async (
  source: LatLng,
  destination: LatLng
) => {
  try {
    const API_KEY = 'YOUR_GOOGLE_MAPS_API_KEY';
    const url = `https://maps.googleapis.com/maps/api/directions/json?origin=${source.latitude},${source.longitude}&destination=${destination.latitude},${destination.longitude}&key=${API_KEY}`;
    
    const response = await fetch(url);
    const json = await response.json();
    
    if (json.routes.length) {
      const points = decodePolyline(json.routes[0].overview_polyline.points);
      return points;
    } else {
      Alert.alert('Ruta no encontrada');
      return [];
    }
  } catch (error) {
    Alert.alert('Error obteniendo ruta', String(error));
    return [];
  }
};

// Decodificador de polilínea personalizado
const decodePolyline = (t: string, e = 5) => {
  let points = [];
  let index = 0, lat = 0, lng = 0;
  
  while (index < t.length) {
    let b, shift = 0, result = 0;
    do {
      b = t.charCodeAt(index++) - 63;
      result |= (b & 0x1f) << shift;
      shift += 5;
    } while (b >= 0x20);
    
    let dlat = (result & 1) ? ~(result >> 1) : result >> 1;
    lat += dlat;
    shift = 0;
    result = 0;
    
    do {
      b = t.charCodeAt(index++) - 63;
      result |= (b & 0x1f) << shift;
      shift += 5;
    } while (b >= 0x20);
    
    let dlng = (result & 1) ? ~(result >> 1) : result >> 1;
    lng += dlng;
    
    points.push({
      latitude: lat / 1e5,
      longitude: lng / 1e5,
    });
  }
  return points;
};
Tutorial completo: implementar Google Maps en React Native con mapas interactivos | 7

Características avanzadas para implementar Google Maps en React Native

1. Clustering de marcadores

Para manejar múltiples marcadores eficientemente:

import { Marker } from 'react-native-maps';
import SuperCluster from 'supercluster';

const MarkerCluster = ({ markers, region, onRegionChange }) => {
  const [clusters, setClusters] = useState([]);
  
  useEffect(() => {
    const cluster = new SuperCluster({
      radius: 40,
      maxZoom: 16,
    });
    
    cluster.load(markers.map(marker => ({
      type: 'Feature',
      properties: { cluster: false, marker },
      geometry: {
        type: 'Point',
        coordinates: [marker.longitude, marker.latitude],
      },
    })));
    
    const bbox = [
      region.longitude - region.longitudeDelta,
      region.latitude - region.latitudeDelta,
      region.longitude + region.longitudeDelta,
      region.latitude + region.latitudeDelta,
    ];
    
    const clusters = cluster.getClusters(bbox, Math.round(Math.log(360 / region.longitudeDelta) / Math.LN2));
    setClusters(clusters);
  }, [markers, region]);
  
  return (
    <>
      {clusters.map((cluster, index) => (
        <Marker
          key={index}
          coordinate={{
            longitude: cluster.geometry.coordinates[0],
            latitude: cluster.geometry.coordinates[1],
          }}
          title={cluster.properties.cluster ? `${cluster.properties.point_count} ubicaciones` : cluster.properties.marker.title}
        />
      ))}
    </>
  );
};

2. Estilos de mapa personalizados

Para personalizar la apariencia al implementar Google Maps en React Native:

const customMapStyle = [
  {
    "elementType": "geometry",
    "stylers": [{ "color": "#242f3e" }]
  },
  {
    "elementType": "labels.text.stroke",
    "stylers": [{ "color": "#242f3e" }]
  },
  {
    "elementType": "labels.text.fill",
    "stylers": [{ "color": "#746855" }]
  },
  // Más estilos...
];

<MapView
  style={{ flex: 1 }}
  provider="google"
  customMapStyle={customMapStyle}
  region={region}
>

3. Geocodificación inversa

Para obtener direcciones a partir de coordenadas:

const reverseGeocode = async (latitude: number, longitude: number) => {
  try {
    const API_KEY = 'YOUR_GOOGLE_MAPS_API_KEY';
    const url = `https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}&key=${API_KEY}`;
    
    const response = await fetch(url);
    const json = await response.json();
    
    if (json.results.length > 0) {
      return json.results[0].formatted_address;
    }
    return 'Dirección no encontrada';
  } catch (error) {
    console.error('Error en geocodificación inversa:', error);
    return 'Error obteniendo dirección';
  }
};

4. Mapas offline

Para funcionalidad offline al implementar Google Maps en React Native:

import { OfflineMap } from 'react-native-maps';

const OfflineMapScreen = () => {
  const downloadOfflineMap = async (region: Region) => {
    try {
      await OfflineMap.downloadMap({
        region,
        name: 'offline_map_madrid',
      });
      Alert.alert('Éxito', 'Mapa descargado para uso offline');
    } catch (error) {
      Alert.alert('Error', 'No se pudo descargar el mapa offline');
    }
  };

  return (
    <View style={{ flex: 1 }}>
      <MapView
        style={{ flex: 1 }}
        provider="google"
        offlineMapName="offline_map_madrid"
        region={region}
      />
    </View>
  );
};

Optimización de performance al implementar Google Maps en React Native

1. Lazy loading de marcadores

const LazyMarkers = ({ markers, region }) => {
  const visibleMarkers = useMemo(() => {
    return markers.filter(marker => {
      return (
        marker.latitude >= region.latitude - region.latitudeDelta &&
        marker.latitude <= region.latitude + region.latitudeDelta &&
        marker.longitude >= region.longitude - region.longitudeDelta &&
        marker.longitude <= region.longitude + region.longitudeDelta
      );
    });
  }, [markers, region]);

  return (
    <>
      {visibleMarkers.map(marker => (
        <Marker key={marker.id} coordinate={marker} />
      ))}
    </>
  );
};

2. Debounce para actualizaciones de región

import { debounce } from 'lodash';

const MapScreen = () => {
  const debouncedRegionChange = useMemo(
    () => debounce((region: Region) => {
      // Actualizar marcadores visibles
      updateVisibleMarkers(region);
    }, 300),
    []
  );

  return (
    <MapView
      onRegionChangeComplete={debouncedRegionChange}
      // otras props...
    />
  );
};

Testing y debugging al implementar Google Maps en React Native

1. Testing de componentes de mapa

import { render } from '@testing-library/react-native';
import MapScreen from '../MapScreen';

jest.mock('react-native-maps', () => ({
  MapView: 'MapView',
  Marker: 'Marker',
  Polyline: 'Polyline',
}));

describe('MapScreen', () => {
  test('renders map with correct props', () => {
    const { getByTestId } = render(<MapScreen />);
    const mapView = getByTestId('map-view');
    expect(mapView).toBeTruthy();
  });
});

2. Debugging de permisos

const debugPermissions = async () => {
  if (Platform.OS === 'android') {
    const permissions = await PermissionsAndroid.requestMultiple([
      PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
      PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION,
    ]);
    
    console.log('Android permissions:', permissions);
  } else {
    const result = await check(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE);
    console.log('iOS location permission:', result);
  }
};
Tutorial completo: implementar Google Maps en React Native con mapas interactivos | 8

Mejores prácticas al implementar Google Maps en React Native

1. Gestión de memoria

const MapScreen = () => {
  useEffect(() => {
    return () => {
      // Limpiar listeners y timers
      if (watchId) {
        Geolocation.clearWatch(watchId);
      }
    };
  }, []);
};

2. Manejo de errores robusto

const ErrorBoundary = ({ children }) => {
  const [hasError, setHasError] = useState(false);

  useEffect(() => {
    const errorHandler = (error) => {
      console.error('Map error:', error);
      setHasError(true);
    };

    // Configurar manejo de errores globales
    return () => {
      // Limpiar
    };
  }, []);

  if (hasError) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Text>Error cargando el mapa. Intenta de nuevo.</Text>
      </View>
    );
  }

  return children;
};

3. Configuración de producción

const isProduction = __DEV__ === false;

const MapScreen = () => {
  const mapConfig = {
    provider: 'google',
    showsUserLocation: !isProduction, // Solo en desarrollo
    showsMyLocationButton: !isProduction,
    loadingEnabled: true,
    loadingIndicatorColor: '#1E90FF',
    pitchEnabled: true,
    rotateEnabled: true,
    scrollEnabled: true,
    zoomEnabled: true,
  };

  return (
    <MapView
      {...mapConfig}
      style={{ flex: 1 }}
      region={region}
    />
  );
};

Conclusión: dominar cómo implementar Google Maps en React Native

Ahora tenemos una aplicación React Native CLI completamente configurada que utiliza Google Maps para mostrar rutas usando la Directions API. Esta configuración incluye permisos de ubicación, recuperación de direcciones y renderizado de polylines.

Esta base robusta es ideal para implementar casos de uso avanzados como:

  • Seguimiento de entregas con actualizaciones en tiempo real
  • Reserva de taxis con rutas dinámicas
  • Asistencia de navegación paso a paso
  • Aplicaciones de turismo con puntos de interés
  • Fitness tracking con rutas grabadas
  • Marketplace de servicios con proveedores cercanos

Extensiones adicionales al implementar Google Maps en React Native:

  • React-native-maps con geolocalización para tracking continuo
  • Controles de mapa personalizados para UX específica
  • Soporte de mapas offline para funcionalidad sin conexión
  • Integración con notificaciones push para actualizaciones de ubicación
  • Analytics de uso para optimizar rutas frecuentes

En Juice Studio, siempre elegimos las herramientas adecuadas para cada proyecto. Nuestra experiencia en implementar Google Maps en React Native nos permite crear soluciones robustas que van desde mapas básicos hasta sistemas complejos de navegación y tracking.

Ya sea que estés construyendo una aplicación de delivery, una plataforma de movilidad o cualquier solución que requiera mapas interactivos, podemos ayudarte a implementar Google Maps en React Native de manera eficiente y escalable.

¿Listo para construir la próxima gran aplicación con mapas? En Juice Studio te ayudamos a implementar Google Maps en React Native con las mejores prácticas y tecnologías más avanzadas.

Construyamos algo excepcional juntos aplicando todo el potencial de implementar Google Maps en React Native en tu próximo proyecto móvil.

Compartir en:

From offline to online.

Comparte tus ideas con nosotros