Урок 03

Геолокация и карты

Expo Location

npx expo install expo-location

Текущая позиция

import * as Location from 'expo-location';

async function getCurrentLocation() {
    const { status } = await Location.requestForegroundPermissionsAsync();
    if (status !== 'granted') return;

    const location = await Location.getCurrentPositionAsync({
        accuracy: Location.Accuracy.High,
    });

    console.log(location.coords.latitude, location.coords.longitude);
}

Отслеживание

const subscription = await Location.watchPositionAsync(
    {
        accuracy: Location.Accuracy.High,
        timeInterval: 5000,
        distanceInterval: 10,
    },
    (location) => {
        setCoords(location.coords);
    }
);

return () => subscription.remove();

Фоновое отслеживание

Для фитнес-трекеров и доставки:

await Location.startLocationUpdatesAsync('task-name', {
    accuracy: Location.Accuracy.Balanced,
    timeInterval: 60000,
    distanceInterval: 100,
    foregroundService: {
        notificationTitle: 'Отслеживание активно',
        notificationBody: 'Приложение записывает ваш маршрут',
    },
});

Требует TaskManager.defineTask и разрешения Always.

Геокодирование

Адрес → координаты:

const results = await Location.geocodeAsync('Москва, Красная площадь');

Координаты → адрес:

const addresses = await Location.reverseGeocodeAsync({
    latitude: 55.7558,
    longitude: 37.6173,
});

Карты

npx expo install react-native-maps
import MapView, { Marker } from 'react-native-maps';

<MapView
    style={{ flex: 1 }}
    initialRegion={{
        latitude: 55.7558,
        longitude: 37.6173,
        latitudeDelta: 0.05,
        longitudeDelta: 0.05,
    }}
>
    <Marker
        coordinate={{ latitude: 55.7558, longitude: 37.6173 }}
        title="Москва"
        description="Столица России"
    />
</MapView>

Кластеризация

import { Marker } from 'react-native-maps';
import ClusteredMapView from 'react-native-map-clustering';

<ClusteredMapView
    style={{ flex: 1 }}
    initialRegion={region}
    clusterColor="#c1442e"
>
    {points.map((p) => (
        <Marker key={p.id} coordinate={p.coords} />
    ))}
</ClusteredMapView>

Пользовательская позиция

<MapView
    showsUserLocation
    followsUserLocation
    showsMyLocationButton
/>

Стили карты

const mapStyle = [
    { elementType: 'geometry', stylers: [{ color: '#242f3e' }] },
    { elementType: 'labels.text.fill', stylers: [{ color: '#746855' }] },
];

<MapView customMapStyle={mapStyle} />

Обратные вызовы

<MapView
    onRegionChangeComplete={(region) => console.log('регион изменился', region)}
    onPress={(e) => console.log('клик', e.nativeEvent.coordinate)}
    onMarkerPress={(e) => console.log('маркер', e.nativeEvent.id)}
/>

Разрешения

{
    "expo": {
        "ios": {
            "infoPlist": {
                "NSLocationWhenInUseUsageDescription": "Показываем ближайшие точки на карте"
            }
        },
        "android": {
            "permissions": ["ACCESS_FINE_LOCATION", "ACCESS_COARSE_LOCATION"]
        }
    }
}

Оптимизация батареи

  • Используй Accuracy.Balanced вместо High, если точность не критична
  • distanceInterval чтобы не получать обновления на каждом метре
  • Отключай отслеживание в фоне, когда не нужно

Итоги

  • expo-location для геолокации
  • watchPositionAsync для отслеживания
  • Фон — через TaskManager
  • Геокодирование для адресов
  • react-native-maps для карт
  • Кластеризация для множества точек