Реализация отслеживания геолокации в реальном времени
Показать точку пользователя на карте — пять строк кода. Передавать её на сервер каждые 5 секунд с минимальным разрядом батареи, пока приложение в фоне, корректно обрабатывать потерю сигнала и переподключение — совсем другая история.
Где обычно возникают проблемы
Самая частая ошибка — не разделять foreground и background режим отслеживания. В foreground можно запускать CLLocationManager с desiredAccuracy: .bestForNavigation и distanceFilter: 5 — пользователь активно смотрит на карту, батарея не в приоритете. В background тот же режим убьёт заряд за два часа и вызовет жалобы.
На Android проблема острее: с версии 8.0 система агрессивно убивает фоновые процессы. LocationManager.requestLocationUpdates() из Service без startForeground() перестаёт получать обновления через несколько минут на большинстве прошивок. MIUI и One UI с настройками «Оптимизация батареи» делают это ещё быстрее — независимо от настроек разработчика.
Стек и архитектура
iOS
Для foreground — CLLocationManager с CLLocationAccuracy.best, callback в didUpdateLocations. Для background — allowsBackgroundLocationUpdates = true + capability «Background Modes → Location updates» в entitlements. Без этого флага фоновые обновления просто не приходят, и ни одна ошибка в консоль не выводится.
Координаты буферизуем локально (массив в памяти или Core Data) и отправляем пачками через URLSession.shared.uploadTask каждые N секунд или при накоплении K точек. Одиночные HTTP-запросы на каждое обновление — антипаттерн: при плохом интернете очередь растёт быстрее, чем разгребается.
Для экономии батареи переключаем режим в зависимости от контекста:
- Приложение активно:
desiredAccuracy = kCLLocationAccuracyBest,distanceFilter = 10 - Экран выключен:
desiredAccuracy = kCLLocationAccuracyHundredMeters,distanceFilter = 50 - Режим «долгий трекинг»: Significant Location Changes API вместо постоянного мониторинга
Android
FusedLocationProviderClient из play-services-location — единственный правильный выбор для большинства проектов. Платформенный LocationManager даёт меньше контроля над слиянием источников.
val request = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 5_000L)
.setMinUpdateDistanceMeters(10f)
.setWaitForAccurateLocation(false)
.build()
fusedLocationClient.requestLocationUpdates(
request,
locationCallback,
Looper.getMainLooper()
)
Фоновый трекинг — только через Foreground Service с уведомлением. Уведомление нельзя скрыть по требованиям Android 9+. Сервис регистрируем через startForeground() с FOREGROUND_SERVICE_TYPE_LOCATION (Android 10+).
При потере соединения — Room как локальный буфер. WorkManager с Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED) отправляет накопленные точки при восстановлении связи.
Flutter
geolocator пакет для получения позиций, background_locator_2 или flutter_background_geolocation (платный, но надёжный) для фонового режима. Координаты через Isolate или FlutterEngine-background service передаём в Dart-слой, сохраняем в Isar или sqflite, синхронизируем через Dio с retry-логикой.
Передача на сервер в реальном времени
Если нужно показывать позицию другим пользователям в реальном времени — HTTP-поллинг не подходит. WebSocket (socket.io или нативный URLSessionWebSocketTask / OkHttp WebSocket) или MQTT (легче по трафику, лучше для нестабильного соединения). Для Flutter — mqtt_client пакет.
Топик MQTT вида tracking/{userId}/location, QoS 1 для гарантии доставки без подтверждения прочтения. Сервер (Node.js + mosquitto broker или AWS IoT Core) рассылает обновления подписчикам.
Процесс работы
Проектирование: режимы трекинга, интервалы, буферизация, протокол передачи. Реализация iOS и/или Android с правильным управлением жизненным циклом сервиса. Реализация серверной части приёма координат (если нужно). Тестирование на реальных поездках, проверка поведения при переключении сеть/без сети.
Срок: три-восемь дней в зависимости от платформ, наличия серверной части и требований к real-time отображению.







