Разработка мобильного приложения для курьерской службы
Курьер принял заказ, выехал — и приложение упало в background-killed на Android Xiaomi с MIUI. FusedLocationProvider перестал отдавать координаты, трек оборвался, диспетчер не видит машину. Это не гипотетический сценарий — это стандартная проблема курьерских приложений на агрессивных лаунчерах MIUI, OneUI, EMUI, где foreground service убивается сборщиком мусора батареи.
Проблема: геотрекинг на Android
На Android для непрерывной геолокации нужен Foreground Service с явным уведомлением в строке статуса. Без него на Xiaomi/Huawei/OPPO приложение умрёт через 5–10 минут в фоне независимо от WakeLock. Но и foreground service не панацея: MIUI добавляет батарейные ограничения даже на запущенные сервисы, если пользователь не разрешил автозапуск вручную.
Правильный подход: при первом запуске показываем Intent на системный экран «Автозапуск» (для MIUI — com.miui.securitycenter, для Huawei — com.huawei.systemmanager). Это не всегда красиво, но это единственный способ гарантировать трекинг. Плюс — батч-отправка координат: накапливаем точки в памяти, отправляем каждые 10–15 секунд одним запросом вместо 15 отдельных.
На iOS проблем меньше: CLLocationManager с allowsBackgroundLocationUpdates = true и pausesLocationUpdatesAutomatically = false работает надёжно. Но significant-change location updates не подходят для курьеров — они срабатывают только при смене соты (~500 м точность), что не годится для отображения на карте в реальном времени.
Архитектура двух приложений
Курьерский сервис — это почти всегда два отдельных приложения: для курьера и для клиента. Иногда добавляется третье — диспетчерский web-интерфейс. Но мобильная часть может быть в одном проекте с разными flavor/scheme:
-
Android Flavors:
courierApp/clientApp— разныеapplicationId, иконки, разрешения - iOS Targets: два target'а в одном Xcode-проекте, shared код через SPM-пакет
Это позволяет переиспользовать бизнес-логику (сетевой слой, модели данных, геолокационный модуль) между двумя приложениями без дублирования кода.
Алгоритм назначения и маршрутизация
Логика распределения заказов живёт на сервере. Мобильный клиент только получает назначение через push (FCM/APNs с priority: high) и подтверждает принятие. Важно: FCM high priority на Android гарантирует доставку даже в Doze mode, но только если у приложения есть RECEIVE_BOOT_COMPLETED и правильно настроен FirebaseMessagingService.
Маршрут до получателя строим через Google Maps Directions API или OSRM (если нужен self-hosted без платы за API-вызовы). Пошаговую навигацию не реализуем в приложении — открываем Google Maps / Яндекс.Навигатор через deep link, передавая координаты точки доставки.
ETA и трекинг для клиента
Клиент видит курьера на карте — это WebSocket или Server-Sent Events от сервера до клиентского приложения. Координаты обновляются каждые 5–10 секунд. На карте используем Marker с анимацией animateCamera чтобы точка не прыгала, а плавно двигалась — ValueAnimator (Android) или CABasicAnimation (iOS).
ETA считается на стороне сервера через Google Maps Distance Matrix API или HERE Routing API и передаётся клиенту. Не вычисляем ETA на устройстве — там нет актуальных данных о пробках.
Подтверждение доставки
Три варианта подтверждения, которые встречаются чаще всего:
- Фото посылки/двери —
CameraX(Android) илиAVFoundation(iOS) + загрузка в S3/GCS - PIN-код, который знает получатель — простой TOTP или статический код из заказа
- Подпись на экране —
Canvas/UIBezierPath, сохраняем как SVG или PNG
Код подписи делаем с strokeWidth зависящим от скорости движения пальца — выглядит значительно естественнее, чем линия постоянной толщины.
Этапы и сроки
Минимальный жизнеспособный продукт — два приложения (курьер + клиент) с геотрекингом, назначением заказов и подтверждением доставки: 6–10 недель при команде 2 разработчика + дизайнер. Полная платформа с диспетчерским модулем, аналитикой и интеграцией с внешними OMS/WMS-системами — 4–6 месяцев. Стоимость рассчитывается индивидуально после анализа требований.







