Внедрение отслеживания местоположения пользователя с помощью карт React Native и геолокации

Перейти за пределы основ: почему местоположение в реальном времени имеет значение

Расположение пользователя является одним из самых мощных потоков данных, которые может захватить мобильное приложение. Когда все сделано правильно, оно превращает статическое приложение в инструмент, учитывающий контекст, который предвосхищает то, что нужно пользователям. React Native Maps в сочетании с API геолокации является стандартным подходом для этого, и они естественным образом интегрируются с безголовой CMS, такой как Directus. Храня и обслуживая данные о местоположении через Directus, вы можете создавать функции, начиная от отслеживания водителя и маршрутизации доставки до социальных проверок и рекомендаций на основе близости. Эта статья проходит через полную реализацию, от настройки среды до закаленных передового опыта, чтобы вы могли отправить надежный опыт, зная местоположение.

Архитектура: где находится Directus

Перед написанием любого кода, он помогает понять, как части соединяются. React Native обрабатывает мобильный интерфейс, включая визуализацию карт и необработанные данные о местоположении. Directus действует как серверная и безголовая CMS. Он хранит истории местоположений пользователей, определения геозоны и любые метаданные, которые вам нужны. Приложение React Native извлекает и отправляет данные о местоположении Directus через его REST или GraphQL API. Это разделение сохраняет ваш интерфейс наклонным и ваши данные централизованными, доступными для поиска и аудита.

Для более глубокого изучения возможностей моделирования данных Directus см. Руководство по моделированию данных Directus .

Предпосылки и настройка пакета

Вам понадобится рабочий проект React Native (CLI или Expo) и экземпляр Directus. Для локальной разработки вы можете раскрутить Directus через Docker. Вот основные пакеты, которые вам нужны в вашем проекте React Native:

  • react-native-maps – Обеспечивает наложение компонента карты и маркера.
  • @react-native-community/geolocation – Доступ к устройству GPS и сетевому местоположению.
  • @react-native-community/geolocation – Доступ к устройству GPS и сетевому местоположению.

Установите их из корня вашего проекта:

npm install react-native-maps @react-native-community/geolocation

Для iOS запустите , чтобы связать нативные модули. Если вы используете Expo, вам нужно будет выбросить в голый рабочий процесс или использовать , потому что эти библиотеки требуют нативного связывания модулей. После установки проверьте все компилируется, запустив приложение на симуляторе или устройстве, прежде чем двигаться дальше.

Платформы: The Gatekeeper

И Android, и iOS требуют явного согласия пользователя на доступ к местоположению. Неспособность изящно обрабатывать разрешения является причиной номер один сбоев во времени выполнения и негативных отзывов. Начните с необходимой конфигурации платформы.

Конфигурация Android

Откройте и добавьте эти разрешения внутри блока, перед элементом:

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

обеспечивает точность GPS, в то время как обеспечивает запасной вариант с использованием Wi-Fi и вышек сотовой связи.В том числе оба позволяют вашему приложению изящно ухудшаться в средах, где GPS слаб, например, в помещении.

Конфигурация iOS

Откройте и добавьте один или оба из этих ключей:

<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs your location to show nearby services and track your route.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs background location access to provide continuous route tracking.</string>

Apple требует убедительного объяснения для каждого ключа. Избегайте общих строк, таких как “Ваше приложение нуждается в доступе к вашему местоположению, ” так как рецензенты могут отклонить его. Будьте конкретны: “Чтобы показать близлежащие кофейни и обеспечить пошаговую навигацию, ” например.Начните с , если вам нужно только отслеживание переднего плана. Обновление до всегда ключа только в том случае, если ваше приложение действительно требует обновления фона.

Обработка разрешения Runtime в React Native

Настройка значений манифеста — это только половина работы. Также нужно запросить разрешение во время выполнения, особенно на Android 6.0+ и iOS 8.0+. Используйте модуль для Android и полагайтесь на родную библиотеку геолокации для iOS, которая запускает системную подсказку автоматически при вызове или .

Вот крюк с разрешением многоразового использования:

import { PermissionsAndroid, Platform } from 'react-native';

const requestLocationPermission = async () => {
 if (Platform.OS === 'android') {
 const apiLevel = Platform.Version;
 if (apiLevel < 23) {
 // permissions granted automatically at install time
 return true;
 }
 const granted = await PermissionsAndroid.request(
 PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
 {
 title: 'Location Permission',
 message: 'This app needs access to your location.',
 buttonPositive: 'Grant',
 buttonNegative: 'Deny',
 }
 );
 return granted === PermissionsAndroid.RESULTS.GRANTED;
 }
 // iOS handles runtime permission via the Geolocation call itself
 return true;
};

Позвоните этой функции перед любым геолокационным вызовом. Если пользователь откажется, отобразите дружественное сообщение, объясняющее воздействие и предложите кнопку для открытия настроек системы. Никогда не просто сбой или покажите пустую карту.

Основная реализация: отображение пользователя на карте

При наличии подключенных разрешений можно создать основной компонент отслеживания. Следующий код запрашивает текущее положение пользователя, устанавливает область карты и сбрасывает маркер. Он также обновляет маркер в режиме реального времени с помощью .

import React, { useState, useEffect, useRef } from 'react';
import { View, StyleSheet } from 'react-native';
import MapView, { Marker, PROVIDER_GOOGLE } from 'react-native-maps';
import Geolocation from '@react-native-community/geolocation';
import { requestLocationPermission } from './permission';

const LocationTracker = () => {
 const [region, setRegion] = useState(null);
 const [currentLocation, setCurrentLocation] = useState(null);
 const watchId = useRef(null);
 const mapRef = useRef(null);

 useEffect(() => {
 const initTracking = async () => {
 const hasPermission = await requestLocationPermission();
 if (!hasPermission) return;

 // Get the initial position immediately
 Geolocation.getCurrentPosition(
 (position) => {
 const { latitude, longitude } = position.coords;
 const initialRegion = {
 latitude,
 longitude,
 latitudeDelta: 0.01,
 longitudeDelta: 0.01,
 };
 setRegion(initialRegion);
 setCurrentLocation({ latitude, longitude });
 },
 (error) => {
 console.warn('Initial position error:', error.message);
 },
 { enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 }
 );

 // Subscribe to continuous updates
 watchId.current = Geolocation.watchPosition(
 (position) => {
 const { latitude, longitude } = position.coords;
 setCurrentLocation({ latitude, longitude });
 // Optionally animate the map to follow the user
 mapRef.current?.animateToRegion({
 latitude,
 longitude,
 latitudeDelta: 0.01,
 longitudeDelta: 0.01,
 }, 500);
 },
 (error) => {
 console.warn('Watch position error:', error.message);
 },
 { enableHighAccuracy: true, distanceFilter: 10, interval: 5000 }
 );
 };

 initTracking();

 return () => {
 if (watchId.current !== null) {
 Geolocation.clearWatch(watchId.current);
 }
 };
 }, []);

 if (!region) {
 return ;
 }

 return (
 
 
 {currentLocation && (
 
 )}
 
 
 );
};

const styles = StyleSheet.create({
 container: { flex: 1 },
 map: { flex: 1 },
});

export default LocationTracker;

Ключевые детали в этой реализации:

  • Дистанционный фильтр: 10 – Запускает обновление местоположения только при движении устройства не менее 10 метров. Это экономит батарею и уменьшает сетевые вызовы.
  • Интервал: 5000 – Сокращает частоту обновления до одного раза каждые 5 секунд на Android. iOS игнорирует это, но использует собственное дросселирование.
  • показывает UserLocation – встроенная функция React Native Maps, которая отображает нативную точку системы для местоположения пользователя, даже без явного маркера.

Данные о местоположении Directus

Отображение местоположения на карте полезно, но реальная ценность исходит от хранения и запроса этих данных.В Directus создайте коллекцию, называемую локации с этими полями:

  • id (автоприрост, первичный ключ)
  • user id (струна или отношение к Directus users)
  • широта (плавать)
  • долгота (плавание)
  • точность (плавание, метры)
  • метка времени (дата, автогенерируемая)

После этого, вернувшись к своему , отправьте каждое обновление в Directus:

import axios from 'axios';

const DIRECTUS_URL = 'https://your-directus-instance.com';
const DIRECTUS_TOKEN = 'your-static-token-or-dynamic-jwt';

const saveLocationToDirectus = async (coords) => {
 try {
 await axios.post(
 `${DIRECTUS_URL}/items/locations`,
 {
 latitude: coords.latitude,
 longitude: coords.longitude,
 accuracy: coords.accuracy,
 // user_id is typically pulled from auth context
 },
 {
 headers: {
 Authorization: `Bearer ${DIRECTUS_TOKEN}`,
 },
 }
 );
 } catch (error) {
 console.error('Failed to save location:', error.response?.data || error.message);
 }
};

Пакет обновлений, если вы ожидаете высокочастотных записей. Directus поддерживает создание нескольких элементов одновременно, передавая массив в одну и ту же конечную точку. Это снижает накладные расходы сети и избегает ограничений скорости.

Геофенсирование с помощью React Native и Directus

Geofencing - это возможность обнаруживать, когда пользователь входит или выходит из заранее определенной географической границы. Directus может хранить эти определения границы, а ваше приложение React Native может проверять их на текущую позицию. Этот шаблон дает уведомления, такие как “Добро пожаловать в магазин!” или “Вы покинули свою офисную зону.”

Хранение геофенсов в Directus

Создайте коллекцию под названием геофагены со следующими полями:

  • id (первичный ключ)
  • Имя (струна)
  • широта (плавать)
  • долгота (плавание)
  • radius (плавание, метры)
  • trigger on entry (булеан)
  • trigger on exit (булеан)
  • Сообщение (текст)

Клиентский интерфейс Geofence Check

На каждом обновлении местоположения выберите активные геозоны от Directus и проверьте расстояние между текущим положением и каждым центром забора. Можно использовать формулу Haversine или более простое приближение:

const getDistanceFromLatLonInMeters = (lat1, lon1, lat2, lon2) => {
 const R = 6371000; // Earth's radius in meters
 const dLat = (lat2 - lat1) * Math.PI / 180;
 const dLon = (lon2 - lon1) * Math.PI / 180;
 const a =
 Math.sin(dLat / 2) * Math.sin(dLat / 2) +
 Math.cos(lat1 * Math.PI / 180) *
 Math.cos(lat2 * Math.PI / 180) *
 Math.sin(dLon / 2) *
 Math.sin(dLon / 2);
 const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
 return R * c;
};

const checkGeofences = async (currentCoords, geofences) => {
 for (const fence of geofences) {
 const distance = getDistanceFromLatLonInMeters(
 currentCoords.latitude,
 currentCoords.longitude,
 fence.latitude,
 fence.longitude
 );
 if (distance <= fence.radius) {
 return fence; // user is inside this geofence
 }
 }
 return null;
};

Нажмите список геозон локально и периодически обновляйте его, а не извлекайте каждое обновление позиции. Это сохраняет адаптивность приложения и снижает нагрузку на сервер.

Производительность и оптимизация батареи

Отслеживание местоположения является одной из самых интенсивных функций на мобильных устройствах. Пользователи будут удалять приложение, которое истощает их телефон, поэтому оптимизация не является дополнительной. Следуйте этим рекомендациям:

  • Использовать дистанционный фильтр – Установить его достаточно высоко, чтобы избежать нервозных обновлений. Для приложений для ходьбы 10 метров — хорошая базовая линия. Для приложений для вождения лучше работает 20-50 метров.
  • Уменьшите точность определения местоположения, когда это возможно – Для таких функций, как “текущий город, ” грубое местоположение (на основе сети) достаточно. Используйте тонкое (GPS) только тогда, когда точность ниже 50 метров имеет значение.
  • Тромбоевая сеть вызывает – Буферные точки расположения в памяти и смывайте их в Directus каждые 30 секунд или каждые 100 точек, в зависимости от того, что наступит раньше.
  • Прекратите смотреть, когда приложение переходит в фоновый режим – Если ваше приложение не имеет законного случая использования фона (навигация, отслеживание фитнеса), очистите watchId в AppState, измените слушателя. iOS в любом случае прекратит ваше приложение, если оно использует слишком много фоновой энергии.
  • Использовать – Принять кэшированное местоположение, если оно достаточно недавнее. Это позволяет избежать ненужного пробуждения аппаратного обеспечения GPS.

Apple и Google предоставляют подробные инструменты профилирования энергии. Используйте журнал энергии Xcode и историю батареи Android, чтобы проверить поведение вашего приложения перед отправкой.

Обработка ошибок и Edge Cases

Услуги определения местоположения, как известно, ненадежны. Пользователи могут отказать в разрешениях, может быть включен режим полета, GPS может быть заблокирован в помещении, а старые устройства могут возвращать устаревшие или дико неточные данные. Ваше приложение должно предвидеть каждый из этих сценариев.

  • Разрешение отказано – Показать неблокирующий баннер с кнопкой “Открыть настройки” Никогда не заставляйте приложение работать.
  • Место недоступно – Отобразить сообщение, как “ Расположение временно недоступно. Проверьте настройки вашего устройства.” Продолжайте смотреть, чтобы приложение автоматически восстанавливалось, когда сигнал возвращается.
  • Timeout – Повторите до трех раз с экспоненциальным обратным выключением. Если он все еще не срабатывает, вернитесь в грубое местоположение или в последнюю известную позицию.
  • Хранимые или кэшированные данные – Сравните временную метку возвращенной позиции с . Если она старше 60 секунд, отбросьте ее и ждите следующего обновления.

Интегрируйте облегченный сервис регистрации (или просто отправьте ошибки в коллекцию Directus под названием location errors), чтобы вы могли отслеживать реальные показатели отказов и итеративно улучшать свою логику.

Тестирование устройств и сценариев

Симуляторы полезны для быстрой итерации пользовательского интерфейса, но они не могут имитировать реальное поведение GPS. Всегда тестируйте на физических устройствах в различных условиях: ходьба, вождение, внутри здания, в туннеле и с устройством в энергосберегающем режиме. эмуляторы Android могут вводить макеты местоположения через расширенные элементы управления, но симуляторы iOS не могут эмулировать GPS вообще для библиотеки геолокации. Используйте службу, такую как Locationary, чтобы воспроизводить реалистичные GPS-треки во время разработки.

Создайте план тестирования, который охватывает эти случаи:

Конфиденциальность, соблюдение и доверие пользователей

Данные о местоположении чувствительны. Неправильное обращение с ними может привести к штрафам и потере доверия пользователей. Относитесь к ним с той же осторожностью, что и к паролям или финансовой информации.

Для получения дополнительных указаний по обработке персональных данных в Directus, просмотрите опции конфигурации безопасности Directus .

Продолжение: Расширенные варианты использования

Как только основы прочны, вы можете наложить более сложные функции, используя тот же фундамент.

Обмен местоположением в реальном времени

Используйте поддержку Directus WebSocket или SSE для трансляции обновлений местоположения другим пользователям. Например, приложение доставки может показывать движущийся маркер курьера на карте клиента. Бэкэнд получает местоположение через REST и выталкивает его подписавшимся клиентам без опроса.

Аналитика на основе местоположения

Совокупные данные о местоположении в Directus для генерации тепловых карт, отчетов о времени ожидания или популярных шаблонов маршрутов. В руководстве по аналитике Directus показано, как создавать панели приборов поверх ваших данных.

Оффлайн-очередь

Когда сеть недоступна, точки расположения очереди на устройстве используют AsyncStorage или локальную базу данных, такую как WatermelonDB. Как только соединение возобновляется, промывают очередь на Directus. Это обеспечивает целостность данных даже в областях с пятнистым покрытием.

Заключение

Внедрение отслеживания местоположения пользователя с помощью React Native Maps и Geolocation API - это хорошо понятная схема, но дьявол в деталях. Путем сопряжения надежной реализации интерфейса с безголовой CMS, такой как Directus, вы получаете гибкий бэкэнд для хранения, запроса и действия на данных о местоположении без создания пользовательского уровня API. Сосредоточьтесь на обработке разрешений, оптимизации батареи и конфиденциальности данных с самого начала, и вы предоставите функцию, которую пользователи находят действительно полезной, а не навязчивой. Примеры кода и стратегии в этом руководстве дают вам готовый к производству фундамент, который вы можете адаптировать к таким доменам, как логистика, социальные сети, полевые службы или любое приложение, которое выигрывает от знания, где находятся его пользователи.