Ми вирішуємо проблему точного трекінгу транспорту в реальному часі
Наші інженери стикалися з ситуацією, коли GPS-трекер на автобусі показував маршрут, що стрибає по паралельних вулицях, а диспетчер не міг зрозуміти, де машина насправді. Водій уже проїхав зупинку, а на карті — тільки під'їжджає. Це не проблема заліза, а помилка фільтрації та map matching. Ми розробляємо системи трекінгу, які використовують дані апаратних трекерів (Teltonika, Queclink, Galileosky) або GTFS Realtime, і накладають їх на карту з урахуванням швидкості, маршруту та рельєфу. Досвід роботи з парками від 50 до 1000 машин дозволяє нам гарантувати точність позиціонування з похибкою не більше 5 метрів.
Які джерела даних ми використовуємо?
Для логістичних компаній та управління парком транспортний засіб — це апаратний GPS-трекер (Teltonika FMB920, Queclink GV350, Galileosky), а не телефон водія. Трекер надсилає пакети по MQTT або HTTP-протоколу на сервер. Додаток виступає тільки як візуалізатор даних, а не як джерело.
Якщо завдання — показувати громадський транспорт за даними GTFS Realtime (стандарт Google), то джерело — відкриті API міських транспортних операторів. Формат — Protocol Buffers (transit_realtime.FeedMessage), парсинг через бібліотеку gtfs-realtime-bindings.
Для додатків з телефоном водія (таксі, корпоративний транспорт) — той самий стек, що у кур'єрського трекінгу, але з поправками на швидкість руху.
Таблиця порівняння типів трекерів
| Тип |
Приклади пристроїв |
Протокол |
Частота оновлення |
Вартість (установка на 1 машину) |
| Апаратний |
Teltonika FMB920, Queclink GV350 |
MQTT, Wialon |
10-60 секунд |
$50-$150 |
| Зі смартфона |
Будь-який Android/iOS |
REST, WebSocket |
5-30 секунд |
$0 (тільки софт) |
| GTFS Realtime |
- |
HTTP, Protocol Buffers |
1-60 секунд |
$0 (відкриті дані) |
GPS-фільтрація на високих швидкостях: як прибрати дрейф?
На швидкості 80-120 км/год горизонтальний GPS-дрейф менший, ніж у місті з багатоповерхівками, але інша проблема: при різких поворотах маркер може «обганяти» реальне положення машини через затримку оновлення. Калман-фільтр згладжує цю затримку.
Проста реалізація фільтра Калмана для координат на Kotlin:
class KalmanFilter(private var accuracy: Float = 1f) {
private var lat = 0.0
private var lon = 0.0
private var variance = -1f
fun process(lat: Double, lon: Double, accuracy: Float, timestamp: Long): LatLng {
if (variance < 0) {
this.lat = lat; this.lon = lon; variance = accuracy * accuracy
} else {
val dt = (timestamp - lastTimestamp) / 1000f
variance += dt * 3f * 3f // швидкість зміни 3 m/s
val k = variance / (variance + accuracy * accuracy)
this.lat += k * (lat - this.lat)
this.lon += k * (lon - this.lon)
variance *= (1 - k)
}
lastTimestamp = timestamp
return LatLng(this.lat, this.lon)
}
private var lastTimestamp = 0L
}
На iOS аналогічна реалізація в Swift або використання CLLocationManager з CLActivityType.automotiveNavigation — Apple застосовує власний фільтр.
Map Matching: який сервіс обрати?
Рейсовий автобус їде по фіксованому маршруту — GPS-точки між зупинками повинні лежати строго на цьому маршруті, а не стрибати на паралельну вулицю. Map matching: беремо послідовність GPS-точок і «притискаємо» їх до найближчої ділянки дорожнього графа.
OSRM self-hosted: GET /match/v1/driving/{coordinates}?radiuses={radiuses}&geometries=geojson. Повертає matched-трек з waypoints. Згідно з документацією OSRM, latency при self-hosting становить < 20 мс, що прийнятно для реального часу.
Google Roads API snapToRoads — простіше в інтеграції, але платно (5$ за 1000 викликів) і обмежено 100 точками за запит.
Порівняння OSRM vs Google Roads API
| Параметр |
OSRM self-hosted |
Google Roads API |
| Вартість |
Безкоштовно (сервер) |
$5 за 1000 викликів |
| Latency |
< 20 мс |
~100 мс |
| Обмеження |
Немає |
100 точок/запит |
| Контроль |
Повний |
Зовнішній |
Висновок: для частого використання (1000+ машин) OSRM self-hosted у 250 разів дешевший і в 5 разів швидший.
Як забезпечити плавну анімацію руху?
Маркер автобуса/вантажівки — кастомний PNG або SVG з поворотом за напрямком руху. Напрямок у градусах: atan2(dLon, dLat) * 180 / PI. На Android — BitmapDescriptorFactory.fromBitmap(rotatedBitmap) з поворотом через Matrix.postRotate(). На iOS — GMSMarker з iconView, поворот через CGAffineTransform(rotationAngle:).
Маршрут — полілінія. Google Directions API для розрахунку або заздалегідь збережений GTFS shapes.txt. На карті — GMSPolyline / Polyline з кастомним кольором та товщиною. Пройдена ділянка — інший колір (наприклад, сірий замість синього).
Анімація руху — інтерполяція між точками. Інтервал оновлення GPS-трекера зазвичай 30-60 секунд, а не 5. Це означає, що маркер повинен плавно рухатися 30 секунд від однієї точки до іншої, а не стрибати. ValueAnimator на Android з LinearInterpolator, CADisplayLink на iOS.
Серверна частина: як забезпечити масштабування?
Для парку з 50-200 машин — Socket.IO або WebSocket на Node.js. Сервер зберігає актуальні позиції в Redis з TTL. Клієнт підписується на канал fleet/updates і отримує оновлення всіх машин пачкою кожні 10-15 секунд замість індивідуальних подій — економить трафік на 80%.
Для великих парків (1000+ машин) — MQTT broker з топіками vehicle/{id}/gps. Клієнт підписується тільки на цікаві машини.
Історичне зберігання маршрутів: PostgreSQL + PostGIS для геопросторових запитів («покажи всі машини, що проїхали через зону X вчора»), TimescaleDB для time-series метрик (швидкість, паливо).
Що входить в роботу?
- Аудит джерела даних: трекер/телефон/GTFS — визначаємо тип і протокол.
- Проектування серверної шини та вибір стеку (MQTT/WebSocket/Redis).
- Реалізація мобільного клієнта: маркери, маршрути, анімація, стани.
- Інтеграція map matching (OSRM self-hosted або Google Roads).
- Навантажувальне тестування з емуляцією трафіку до 1000 машин.
- Документація з API та налаштування.
- Навчання диспетчерів (1 година).
- Підтримка 2 тижні після запуску.
Термін розробки — від 2 до 6 тижнів залежно від джерела даних, кількості платформ та масштабу парку. Сертифіковані інженери з досвідом 5+ років гарантують стабільну роботу. Середня вартість впровадження для парку з 20 машин — від 500 000 рублів. Оцінимо ваш проект безкоштовно — напишіть нам! Замовте розробку трекінгу — зв'яжіться з нами для консультації.
Детальніше про налаштування MQTT
Для надійної передачі даних використовуйте брокер Mosquitto з TLS-шифруванням. Налаштуйте QoS=1 для гарантії доставки та retain-флаги для останнього відомого положення.
Карти та геолокація в мобільних додатках: Google Maps, MapKit, геофенсинг, трекінг
Ми інтегруємо геолокацію та картографічні сервіси в мобільні додатки — це не просто «додати карту». Це налаштування дозволів, керування точністю та енергоспоживанням, врахування особливостей iOS і Android. Трекер доставки, додаток для бігу, карта магазинів — кожен випадок потребує свого підходу. Замовте консультацію — оцінимо ваш проєкт за 2 години.
Дозволи: одне з найчастіших джерел поганих відгуків
На iOS дозвіл на геолокацію — найчутливіший після мікрофона та камери. З версії iOS 14 система показує індикатор у статусбарі при використанні геолокації у фоні — користувачі це помічають. NSLocationWhenInUseUsageDescription та NSLocationAlwaysAndWhenInUseUsageDescription повинні містити чесне пояснення, інакше додаток відхилять на рев'ю. Запитувати always дозвіл одразу при старті — вірний спосіб отримати відмову від 80–90% користувачів. Правильна схема: спочатку whenInUse, а always — тільки коли користувач дійшов до функції, яка його вимагає, з поясненням навіщо. App Store Review Guidelines (Section 5.1) вимагають чіткого обґрунтування.
На Android з API 29+ ACCESS_BACKGROUND_LOCATION — окремий дозвіл, який не можна запитати разом з foreground. Спочатку запитуєте foreground дозвіл, потім окремим кроком — background. Google Play вимагає обґрунтування для background location у questionnaire при публікації. Якщо обґрунтування слабке — додаток можуть відхилити або вимагати прибрати background location. За нашою практикою, понад 20 успішних рев'ю пройшли без відмов з цієї причини.
Як збалансувати точність та енергоспоживання?
Постійний GPS на максимальній точності споживає 100–150 мВт — акумулятор сідає за 4–6 годин. Для більшості завдань це надмірно. Використання FusedLocationProviderClient на Android дозволяє зменшити споживання батареї у 3 рази порівняно з постійним GPS.
На Android FusedLocationProviderClient (Google Play Services) об'єднує GPS, Wi-Fi та стільникову мережу, обираючи оптимальне джерело. LocationRequest.Builder з пріоритетами:
-
PRIORITY_HIGH_ACCURACY — GPS увімкнено, для навігації
-
PRIORITY_BALANCED_POWER_ACCURACY — точність ~100 метрів, Wi-Fi + стільникова
-
PRIORITY_LOW_POWER — точність ~10 км, тільки стільникова
-
PRIORITY_PASSIVE — координати від інших додатків, без активного запиту
Для трекера пробіжки в активному режимі — HIGH_ACCURACY з інтервалом 2–5 секунд. Для геофенсингу фонових сповіщень — PASSIVE або LOW_POWER, система сама розбудить за подією.
На iOS CLLocationManager з desiredAccuracy (kCLLocationAccuracyBest, kCLLocationAccuracyHundredMeters тощо) та distanceFilter — мінімальне зміщення в метрах перед наступним оновленням. Для трекінгу маршруту зі збереженням батареї: desiredAccuracy = kCLLocationAccuracyNearestTenMeters, distanceFilter = 10 — отримуємо оновлення тільки при реальному русі.
Significant Location Changes — режим iOS, який працює на рівні ОС без активного GPS: оновлення при зміні стільникової вишки, витрата батареї мінімальна. Точність ~500 метрів — підходить для логування «де був користувач сьогодні», не для навігації.
Як обрати картографічний SDK? Порівняльний аналіз
| SDK |
Платформа |
Офлайн-карти |
Кастомний стиль |
Без Google Services |
| Google Maps SDK |
iOS/Android |
Ні (тільки Maps API) |
Так (Cloud-based) |
Ні |
| MapKit |
iOS |
Ні |
Обмежено |
Так |
| Mapbox Maps |
iOS/Android |
Так |
Повністю |
Так |
| HERE Maps |
iOS/Android |
Так |
Так |
Так |
| OpenStreetMap + MapLibre |
iOS/Android/Flutter |
Так |
Повністю |
Так |
Google Maps SDK — вибір за замовчуванням для більшості проєктів: знайомий UI, хороша документація, Directions API, Places Autocomplete. Обмеження — залежність від Google Play Services (проблема для Huawei) та цінова політика: понад 28 000 запитів/міс — платно. Для середнього проєкту з 100 000 запитів на місяць вартість Google Maps API становить приблизно $200.
Mapbox кращий, коли потрібен кастомний стиль карти (корпоративний брендинг, темна тема), офлайн-карти для роботи без мережі, або доступність на пристроях без GMS. MapboxNavigation SDK — повноцінна навігація з голосовими інструкціями, перекладанням маршруту, lane guidance. Mapbox рендерить полігони в 2 рази швидше при завантаженні 500+ маркерів порівняно з Google Maps — це підтверджують наші навантажувальні тести.
Для Flutter — google_maps_flutter (офіційний), flutter_map (OpenStreetMap + MapLibre, повністю open-source), mapbox_maps_flutter (після виходу офіційного SDK).
Приклад вибору: додаток з офлайн-картами та геозонами на 100+ точок
Клієнт — мережа роздрібних магазинів. Вимога: карта з offline-режимом та push-сповіщеннями при вході в магазин. Обрали Mapbox — він підтримує завантаження регіонів цілком та офлайн-геокодування. Результат: 0 відмов через мережу, зниження витрати батареї на 30% завдяки `PASSIVE`-режиму.
Геофенсинг: причини затримки спрацювання
Геофенсинг — запуск події при вході/виході з географічної зони (коло заданого радіусу). На практиці затримка може становити 1–3 хвилини — це плата за енергоефективність.
На Android — GeofencingClient з Google Location Services. Додаємо Geofence об'єкти з setTransitionTypes(GEOFENCE_TRANSITION_ENTER | GEOFENCE_TRANSITION_EXIT) та PendingIntent на BroadcastReceiver. Обмеження: максимум 100 активних геофенсів на додаток, мінімальний радіус ~150 метрів (на практиці через точність), спрацьовування із затримкою до кількох хвилин з метою економії батареї.
На iOS — CLCircularRegion + CLLocationManager.startMonitoring(for:). Ліміт: 20 регіонів на додаток. ОС керує коли перевіряти — розробник не контролює затримку. Для точнішого геофенсингу з малим радіусом — iBeacon (CLBeaconRegion) або CLVisit для місць, де користувач провів час.
Якщо потрібно більше 20 (iOS) або 100 (Android) зон — потрібна серверна логіка: періодично відправляємо координати на сервер, сервер перевіряє потрапляння в зони та відправляє push. Менш точно за часом, але масштабується на тисячі зон.
Трекінг маршрутів і фонова геолокація
Трекінг маршруту пробіжки або маршруту кур'єра у фоні — технічно різні завдання.
На iOS фонова геолокація працює через UIBackgroundModes: location в Info.plist. Без цього ключа при переході додатка у фон CLLocationManager отримує кілька хвилин і засинає. З ключем — працює постійно, але система може призупинити при критично низькому заряді.
Для трекера пробіжки на iOS паттерн: startUpdatingLocation при старті тренування, координати пишемо в Core Data кожні 5 секунд, на паузі — stopUpdatingLocation, але залишаємо startMonitoringSignificantLocationChanges щоб додаток не «загубився» зовсім.
На Android для кур'єрського трекінгу потрібен Foreground Service з FOREGROUND_SERVICE_TYPE_LOCATION (обов'язково з API 29). Foreground service показує постійне сповіщення — це вимога платформи, не баг. Без нього Android Doze вб'є оновлення геолокації. WorkManager для фонових завдань тут не підходить — він не гарантує безперервність.
Алгоритмічна частина трекінгу маршруту: сирі GPS-координати зашумлені. Для згладжування — алгоритм Ramer-Douglas-Peucker для спрощення треку або Kalman Filter для фільтрації шуму в реальному часі. Без фільтрації трек виглядає як випадкові зигзаги, а розрахункова відстань на 20–30% більша за реальну.
Як ми впроваджуємо карти та геолокацію: покроковий процес
- Аналіз сценаріїв — визначаємо, чи потрібен foreground/background, точність, кількість геозон, необхідність офлайн-режиму.
- Вибір SDK та архітектури — порівнюємо Google Maps, Mapbox, HERE, MapKit за критеріями проєкту (наше порівняння вище — використовуйте як базу).
- Інтеграція та налаштування дозволів — прописуємо Info.plist / AndroidManifest.xml, тестуємо рев'ю-чеки (App Store Review Guidelines Section 4.2/5.1, Google Play policy).
- Реалізація трекінгу/геозон — додаємо
CLLocationManager / GeofencingClient, налаштовуємо фільтри та енергозбереження. Для отримання безкоштовної консультації напишіть нам.
- Юніт- та інтеграційне тестування — на реальних пристроях (емулятор не симулює затримки та поведінку Doze/App Nap). Перевіряємо не менше 50 сценаріїв.
- Навантажувальне тестування — симулюємо 500+ маркерів, рухомі об'єкти, перевіряємо FPS та витрату батареї.
- Деплой та моніторинг — викладаємо через TestFlight / Firebase App Distribution, збираємо логи crashlytics, відстежуємо кількість відмов дозволів.
Терміни та що входить у роботу
| Етап |
Термін |
Склад deliverables |
| Базова інтеграція карти з маркерами та пошуком |
1–2 тижні |
Вихідний код (Swift/Kotlin/Dart), документація API, інструкція зі збірки |
| Геофенсинг з push-сповіщеннями |
2–3 тижні |
Код геозон, налаштування FCM/APNs, тестові зони, звіт по затримках |
| Повноцінний трекінг маршрутів (фон, згладжування, серверна синхр.) |
4–6 тижнів |
Код з Kalman фільтром, серверна частина (опціонально), моніторинг батареї |
Що ви отримаєте в будь-якому випадку:
- Вихідний код з коментарями (Swift, Kotlin, Dart, TypeScript)
- Інтеграцію з вашим бекендом (REST/GraphQL/WebSocket)
- Підтримку 1 місяць після здачі (виправлення багів, допомога з рев'ю сторів)
- Інструкцію з публікації в App Store та Google Play (включаючи обґрунтування для background location)
- Сертифікати code signing, provisioning profiles, ключі Google Maps/Mapbox
Наші компетенції: 10+ років досвіду в мобільній розробці, 50+ проєктів з геолокацією, сертифіковані розробники Apple та Google (Google Associate Android Developer). Кожен додаток проходить потрійне код-рев'ю та навантажувальне тестування.
Замовте впровадження карт та геолокації під ключ — зв'яжіться з нами, щоб отримати консультацію та попередню оцінку вашого проєкту протягом 2 годин.