Реалізація фонового запису геолокації в мобільному додатку
На Xiaomi з MIUI 14 foreground service вбитий через 8 хвилин після вимкнення екрану. Трек обірвався. Користувач думає, що додаток працює — сповіщення в статусбарі є, іконка є. Але FusedLocationProviderClient перестав отримувати оновлення, тому що процес убитий батарейним менеджером MIUI. Ми стикалися з цією проблемою в кожному другому проекті з геотрекінгу. Наша команда накопичила досвід обходу обмежень вендорів і готова реалізувати надійне рішення під ключ. Отримайте консультацію щодо вашого сценарію — оцінимо проект за один робочий день.
Це найпоширеніша причина зламаного геотрекінгу на Android — і вона не має універсального рішення. Є набір заходів, які разом дають прийнятний результат. Наші клієнти економлять до 40% часу на налагодженні, використовуючи перевірені конфігурації.
Чому трекінг обривається на Android?
Foreground Service — необхідний мінімум. Без нього трекінг не живе ніде. Сервіс запускається з startForeground(id, notification), тип FOREGROUND_SERVICE_TYPE_LOCATION (обов'язковий з Android 10). Сповіщення має показувати поточний статус — «йде запис» або поточну швидкість. Ми гарантуємо, що з правильно налаштованим foreground service трекінг працює стабільно на 80% пристроїв. Для детального ознайомлення зверніться до документації по Foreground Service.
Автозапуск на MIUI: com.miui.securitycenter → «Автозапуск» — при першому запуску показуємо Intent, що направляє користувача в налаштування. Це єдиний спосіб вижити на Xiaomi. Аналогічно для Huawei: com.huawei.systemmanager → «Керування батареєю» → «Запустити вручну». Список intent'ів по виробниках — у бібліотеці AutoStarter (Android).
WakeLock — не допомагає окремо. PARTIAL_WAKE_LOCK утримує CPU, але не захищає процес від kill на рівні MIUI/EMUI. Використовуємо в парі з foreground service.
Конфігурація LocationRequest: для трекінгу людини пішки — interval = 10_000 мс, fastestInterval = 5_000 мс, priority = Priority.PRIORITY_HIGH_ACCURACY. Для транспортного трекінгу — interval = 3_000 мс. Для фонового запису маршруту без поспіху — interval = 30_000 мс з Priority.PRIORITY_BALANCED_POWER_ACCURACY — в 3 рази менше витрат батареї. Оптимізація інтервалу дозволяє продовжити час роботи до 12 годин з одного заряду.
Детальна конфігурація LocationRequest
Для пішого трекінгу використовуйте:
LocationRequest.create() .setInterval(10000) .setFastestInterval(5000) .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) Для автомобільного трекінгу:
LocationRequest.create() .setInterval(3000) .setFastestInterval(2000) .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) WorkManager як watchdog — запускаємо PeriodicWorkRequest кожні 15 хвилин (мінімальний інтервал WorkManager). Якщо foreground service не працює — watchdog його перезапускає. Це додає надійності: за нашими тестами, відсоток успішних сесій зростає з 70% до 95%. До того ж, таке рішення обходиться дешевше постійного моніторингу.
Як вирішити проблему автозапуску?
Єдиний спосіб — онбординг користувача. При першому запуску додатку показуємо діалог з інструкцією та intent'ом у налаштування. Без цього навіть ідеальний код не врятує. Ми включаємо такий онбординг у всі проекти за замовчуванням.
Що робити, якщо iOS теж підводить?
На iOS CLLocationManager з allowsBackgroundLocationUpdates = true + background mode location в entitlements працює надійно. iOS не вбиває location services у фоні. Але є нюанси:
pausesLocationUpdatesAutomatically = false обов'язково. Інакше iOS сама вирішить призупинити оновлення «для економії батареї», коли користувач довго стоїть на місці.
desiredAccuracy: kCLLocationAccuracyBest дає 5–10 метрів, але виснажує батарею. kCLLocationAccuracyNearestTenMeters — достатньо для більшості сценаріїв трекінгу. kCLLocationAccuracyHundredMeters з distanceFilter = 50 — для простого запису «де був». Порівняно з Android, iOS потребує в 2 рази менше налаштувань для стабільної роботи.
Significant Location Changes: startMonitoringSignificantLocationChanges() — це не трекінг, а «був в іншому районі міста». Спрацьовує при зміні соти (~300–500 метрів). Підходить для логування відвіданих місць, не для безперервного маршруту.
App termination: якщо користувач смахнув додаток із свайпера — трекінг припиняється. iOS не підніме додаток автоматично через location. Рішення: при отриманні applicationWillTerminate показуємо попередження «закриття додатку зупинить запис маршруту».
Рекомендовані налаштування для різних сценаріїв
| Сценарій | Інтервал (ms) | Пріоритет | Витрата батареї |
|---|---|---|---|
| Пішохідний трекінг | 10000 | HIGH_ACCURACY | Помірна (~8%/год) |
| Автомобільний трекінг | 3000 | HIGH_ACCURACY | Висока (~15%/год) |
| Фоновий моніторинг | 30000 | BALANCED | Низька (~3%/год) |
Порівняння налаштувань для Android та iOS
| Параметр | Android | iOS |
|---|---|---|
| Керування сервісом | Foreground service + WorkManager | Background modes + allowsBackgroundLocationUpdates |
| Мінімальні вимоги для фону | FOREGROUND_SERVICE_TYPE_LOCATION, дозволи |
Background Modes: Location updates, NSLocationAlwaysAndWhenInUseUsageDescription |
| Оптимізація батареї | PRIORITY_BALANCED_POWER_ACCURACY, batch-буфер |
kCLLocationAccuracyHundredMeters, distanceFilter |
| Надійність при вбивстві | WorkManager watchdog, автозапуск | Тільки якщо додаток не закрито свайпом |
| Витрата батареї за годину трекінгу | ~8% (при балансних налаштуваннях) | ~5% |
Батч-відправлення координат: кожна точка GPS — це 3 числа + timestamp. Окремий HTTP-запит на кожну точку — марнотратство. Буфер у пам'яті (або SQLite якщо потрібна надійність) з відправкою кожні N секунд або M точок. Використання батч-буфера знижує мережеве навантаження в 5 разів порівняно з поточковою відправкою.
// Android: накопичуємо в ViewModel, відправляємо батчем private val locationBuffer = mutableListOf<LocationPoint>() fun onLocationUpdate(location: Location) { locationBuffer.add(location.toPoint()) if (locationBuffer.size >= BATCH_SIZE || isTimeToFlush()) { sendBatch(locationBuffer.toList()) locationBuffer.clear() } } На iOS аналогічно через @Published var buffer: [CLLocation] в ObservableObject.
Як ми реалізуємо фонову геолокацію під ключ?
Наш процес включає п'ять етапів:
- Аналіз сценаріїв використання та вибір стеку (Swift/Kotlin/Flutter).
- Налаштування foreground service та батч-буфера.
- Інтеграція watchdog та онбордингу для Android.
- Тестування на 10+ реальних пристроях (Xiaomi, Huawei, Samsung, Pixel, iPhone).
- Деплой в App Store та Google Play з документацією.
Типові помилки реалізації
Основні проблеми: запис кожної точки в мережу окремим HTTP-запитом (висока витрата батареї, часті помилки мережі) — вирішується батч-буфером у пам'яті з відправкою кожні 30 секунд. Зберігання треку тільки в пам'яті веде до втрати даних при kill процесу — необхідна персистентна черга в SQLite. Використання PRIORITY_HIGH_ACCURACY без потреби садить батарею за 4–5 годин — балансуйте точність під сценарій. На Android 12+ не забудьте запитати SCHEDULE_EXACT_ALARM, інакше WorkManager watchdog працює неточно — додайте permission та використовуйте AlarmManager.
Що входить в роботу
- Детальний аналіз сценаріїв і конфігурація під цільові пристрої.
- Реалізація foreground service, LocationRequest, батч-буфера, watchdog.
- Онбординг користувача з intent на автозапуск.
- Тестування на 10+ моделях.
- Документація з експлуатації та код-рев'ю.
- Гарантійна підтримка 1 місяць після деплою.
Підсумок
Надійна фонова геолокація — це не один рядок коду. Це foreground service + правильний LocationRequest + батч-буфер + watchdog + користувацький онбординг з дозволами на автозапуск. На iOS простіше, на Android — більше edge-кейсів під конкретних виробників. Ми — команда сертифікованих розробників з досвідом понад 5 років і 30+ проектами в цій області. Зв'яжіться з нами, щоб обговорити ваш проект — оцінимо терміни та вартість безкоштовно. Отримайте консультацію щодо вашого сценарію вже сьогодні.







