Разработка мобильного приложения для полевых сотрудников (Field Service)
Полевой техник приезжает к клиенту, открывает приложение — а там белый экран, потому что сотовой сети нет. Заявка на ремонт, история оборудования, чек-лист инспекции — всё зависло. Именно здесь ломается большинство Field Service-приложений: они строятся как обычный CRUD поверх REST API и не закладывают офлайн-режим как первоклассный сценарий.
Ключевые технические проблемы
Offline-first синхронизация. Полевые сотрудники работают на складах, в подвалах, в промышленных зонах — покрытие нестабильное. Нужна двусторонняя sync-очередь: действия пользователя сохраняются локально (SQLite через Room или CoreData), потом синхронизируются при появлении сети. Конфликт версий — самая болезненная точка. Если два техника одновременно закрыли одну заявку офлайн, нужна merge-стратегия. Обычно применяем "last-write-wins" с логом операций или CRDTs для некоторых типов данных (например, комментарии — append-only).
Фотографии и медиа. Акт выполненных работ требует фото «до» и «после». На Android WorkManager с Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED) — стандартный способ отложенной загрузки. Но нюанс: WorkManager не гарантирует порядок выполнения задач при batch upload. Если порядок фото критичен — нумеруем в имени файла и принимаем это на сервере.
Подпись на экране. Canvas API (Android View.onDraw с Path, iOS UIBezierPath через CAShapeLayer) для захвата подписи клиента — задача простая, пока не понадобится высококачественный экспорт в PDF. Используем iText (Android) или PDFKit (iOS) для генерации акта прямо на устройстве.
Карты и маршрутизация
Диспетчер видит всех полевых сотрудников на карте в реальном времени — это WebSocket или MQTT от брокера (mosquitto / EMQX) до мобильного клиента. Координаты отправляем батчами каждые 30 секунд через FusedLocationProviderClient (Android) или CLLocationManager с desiredAccuracy: kCLLocationAccuracyNearestTenMeters (iOS) — не каждую секунду, чтобы не убивать батарею.
Оптимальный маршрут между 10–15 заявками за день — задача Travelling Salesman, которую в мобильном клиенте не решают. Оптимизацию считает сервер (Google OR-Tools, Vroom), мобильное приложение только отображает готовый маршрут через Google Maps SDK или MapKit с пошаговой навигацией через deep link в Maps/Google Maps.
Стек и архитектура
Для Field Service-приложений с одним кодом под iOS и Android выбираем Flutter или React Native с Expo. Flutter предпочтительнее, когда есть требования к кастомным виджетам (кастомная форма осмотра оборудования, drag-and-drop для позиций в заявке). React Native — если команда клиента будет поддерживать код самостоятельно и у них JavaScript-бэкграунд.
Архитектура: MVVM + Repository pattern. Локальная БД — SQLite (sqflite для Flutter, Room для Android-нативки). Sync-слой — отдельный сервис, который не смешивается с бизнес-логикой.
Из практики
Приложение для обслуживания торговых автоматов: ~200 техников, каждый с 8–15 точками в день. Главная ошибка в первой версии — синхронизация запускалась при каждом действии пользователя через прямой HTTP-запрос. При плохой сети это приводило к тому, что техник ждал 30 секунд после каждого закрытия позиции. Переписали на очередь операций (SQLite-таблица pending_operations + WorkManager) — техник работает мгновенно, синхронизация идёт фоном. Количество жалоб на «приложение тормозит» упало до нуля.
Этапы
- Аудит существующей системы (ERP, CRM, диспетчерский модуль) — разбираемся, с чем будем синхронизироваться
- Проектирование офлайн-модели данных и стратегии разрешения конфликтов
- Дизайн интерфейса с учётом использования в перчатках и на ярком солнце (контрастность, крупные кнопки)
- Разработка и поэтапная интеграция с backend
- Пилот с группой техников (10–20 человек) до полного rollout
- Публикация в App Store и Google Play с MDM-профилем для корпоративных устройств
Сроки от 6 недель (простое приложение с заявками и чек-листами) до 4–6 месяцев для полноценной платформы с диспетчерским модулем, маршрутизацией и интеграцией с ERP. Стоимость рассчитывается индивидуально после анализа требований.







