Мобильная связь кажется вездесущей, пока не окажешься в подвале склада, в лифте, в метро между станциями, на трассе за городом или в цеху с толстыми бетонными стенами. Для многих приложений отсутствие интернета — это досадная мелочь. Но для части продуктов это критическая проблема: курьер не может закрыть доставку, механик не может внести данные о ремонте, торговый представитель теряет заказ клиента.
Офлайн-режим — это способность приложения продолжать работу без подключения к сети и корректно синхронизировать данные, когда связь появится. В этой статье разберём, кому он нужен, какие бывают уровни офлайн-поддержки и как подойти к реализации, чтобы не создать больше проблем, чем решить.
Кому нужен офлайн-режим
Офлайн-режим особенно важен в следующих сценариях:
- Полевые сотрудники. Курьеры, водители, выездные мастера, инспекторы, торговые представители. Они работают там, где связь нестабильна, и не могут ждать, пока появится сигнал.
- Склады и производство. Инвентаризация, приёмка товара, учёт операций в помещениях с плохим покрытием.
- Транспорт и автопарки. Водители и механики заполняют чек-листы осмотра, путевые листы, фиксируют пробег и неисправности в любых условиях.
- Медицина и выездные службы. Врачи на вызовах, социальные работники, аварийные бригады.
- Путешествия и навигация. Карты, билеты, бронирования должны быть доступны в самолёте и за границей.
- Контент. Книги, музыка, курсы, статьи — пользователи хотят иметь доступ к ним в дороге.
Для клиентских приложений офлайн-режим чаще всего ограничен просмотром ранее загруженных данных. Для рабочих инструментов — это полноценная возможность создавать и изменять данные без сети.
Если от приложения зависит рабочий процесс и сотрудник не может «подождать сеть», офлайн-режим — не дополнительная функция, а базовое требование.
Уровни офлайн-поддержки
Офлайн-режим — не бинарная характеристика. Есть несколько уровней, и важно заранее определить, какой нужен вашему продукту.
Уровень 1. Корректная обработка отсутствия сети
Приложение не падает, не показывает бесконечную загрузку, а честно сообщает: «Нет подключения к интернету» — и предлагает повторить попытку. Это минимум, который должен быть в любом приложении.
Уровень 2. Кэширование для чтения
Приложение сохраняет ранее загруженные данные и показывает их без сети: каталог, история заказов, профиль, расписание. Пользователь видит пометку, что данные могут быть устаревшими. Изменять что-либо без сети нельзя.
Уровень 3. Очередь действий
Пользователь может выполнять действия без сети — например, отметить доставку, отправить комментарий, сделать фото. Действия сохраняются в очередь и отправляются на сервер, когда связь восстановится. Подходит для простых операций, которые не конфликтуют друг с другом.
Уровень 4. Полноценная офлайн-работа
Приложение работает с локальной базой данных как с основным источником информации. Пользователь создаёт, редактирует и удаляет записи, а синхронизация с сервером идёт в фоне в обе стороны. Это так называемый подход offline-first. Он самый сложный, но даёт лучший пользовательский опыт для рабочих инструментов.
Локальное хранение данных
Для офлайн-режима приложению нужно хранить данные на устройстве. Основные варианты:
- Реляционные базы данных — SQLite и обёртки над ней (Room на Android, Core Data или SwiftData на iOS, Drift во Flutter). Подходят для структурированных данных со связями: заказы, позиции, клиенты.
- Объектные и NoSQL-хранилища — Realm, Hive, ObjectBox. Удобны для простых моделей и быстрой разработки.
- Хранилища «ключ — значение» — для настроек, токенов, небольших объёмов данных.
- Файловая система — для фотографий, документов, медиафайлов.
При выборе важно учесть:
- Объём данных. Сколько записей нужно хранить на устройстве? Весь справочник товаров на десятки тысяч позиций или только задания на сегодня?
- Безопасность. Если хранятся персональные или коммерческие данные, локальная база должна быть зашифрована.
- Миграции. При обновлении приложения структура базы меняется. Нужно аккуратно переносить данные, чтобы пользователь не потерял несинхронизированную работу.
Синхронизация: самая сложная часть
Сохранить данные локально — относительно просто. Сложность начинается, когда нужно согласовать их с сервером.
Отправка изменений на сервер
Каждое действие пользователя в офлайне записывается в очередь с отметкой времени и уникальным идентификатором. При появлении сети приложение отправляет изменения по порядку. Важные моменты:
- Идемпотентность. Если запрос отправлен, но ответ не пришёл из-за обрыва связи, приложение отправит его повторно. Сервер должен распознать повтор и не создать дубликат. Для этого каждой операции присваивается уникальный идентификатор, созданный на устройстве.
- Порядок. Если пользователь создал заказ, а потом добавил в него позицию, операции должны выполняться именно в этой последовательности.
- Повторные попытки. При ошибках сети отправка повторяется с увеличивающимися интервалами, чтобы не разряжать батарею.
- Фоновая отправка. Синхронизация должна работать, даже если пользователь свернул приложение, — с учётом ограничений, которые накладывают iOS и Android на фоновые задачи.
Получение изменений с сервера
Чтобы не загружать все данные каждый раз, используется инкрементальная синхронизация: приложение запрашивает только изменения с момента последней синхронизации. Для этого сервер должен уметь отдавать изменённые и удалённые записи по отметке времени или версии.
Конфликты
Конфликт возникает, когда одну и ту же запись изменили в двух местах: например, диспетчер изменил адрес доставки, пока курьер был без сети и отметил заказ как выполненный по старому адресу.
Стратегии разрешения конфликтов:
- Последняя запись побеждает. Простейший вариант: сохраняется изменение с более поздней отметкой времени. Подходит для некритичных данных, но может приводить к потере информации.
- Сервер всегда прав. Изменения с устройства отклоняются, если запись изменилась на сервере. Пользователь получает уведомление.
- Слияние по полям. Если изменены разные поля записи, оба изменения сохраняются. Конфликт возникает, только если изменено одно и то же поле.
- Ручное разрешение. Пользователю показываются обе версии, и он выбирает правильную. Подходит для важных данных, но усложняет интерфейс.
- Бизнес-правила. Например, статус «выполнено» имеет приоритет над любыми изменениями диспетчера. Такие правила определяются вместе с заказчиком.
Стратегию разрешения конфликтов нужно выбирать на этапе проектирования, вместе с бизнесом. Это не технический, а процессный вопрос.
Интерфейс офлайн-режима
Пользователь должен понимать, что происходит с его данными. Хороший офлайн-интерфейс:
- показывает статус сети — ненавязчиво, например полоской вверху экрана;
- отмечает несинхронизированные записи — значком или цветом, чтобы было видно, что ещё не отправлено;
- показывает время последней синхронизации — особенно важно для справочников и заданий;
- позволяет запустить синхронизацию вручную — сотрудники часто хотят убедиться, что всё отправлено, перед концом смены;
- сообщает об ошибках синхронизации понятным языком и предлагает решение;
- не блокирует работу — пользователь продолжает работать, пока данные отправляются в фоне.
Что учесть на этапе проектирования
Офлайн-режим сложно добавить в готовое приложение — он затрагивает архитектуру клиента и сервера. Поэтому решения нужно принять заранее:
- Определите сценарии. Какие действия пользователь должен выполнять без сети? Какие данные ему нужны?
- Определите объём данных на устройстве. Что загружается заранее, а что — по запросу.
- Спроектируйте API под синхронизацию. Инкрементальные выгрузки, уникальные идентификаторы с устройства, обработка повторов.
- Согласуйте правила конфликтов с владельцами процессов.
- Продумайте работу с файлами. Фотографии и документы занимают много места и долго загружаются — их нужно сжимать и отправлять отдельной очередью.
- Заложите время на тестирование. Офлайн-сценарии требуют проверки в условиях обрыва связи, медленной сети, переключения между Wi-Fi и мобильным интернетом.
Пример из практики
Сервисная компания, обслуживающая промышленное оборудование, использовала приложение для выездных инженеров, которое работало только онлайн. На объектах — в цехах, подвалах, котельных — связи часто не было, и инженеры записывали данные на бумагу, а потом переносили в приложение. Терялось время, возникали ошибки.
Мы перестроили приложение по принципу offline-first: задания на день загружаются утром, все чек-листы, фотографии и подписи клиентов сохраняются локально и отправляются автоматически при появлении сети. Для конфликтов определили бизнес-правило: данные инженера с объекта имеют приоритет над изменениями в офисе, а при конфликте диспетчер получает уведомление. Бумажный учёт исчез, а время закрытия заявок заметно сократилось.
Вывод
Офлайн-режим — это не одна функция, а архитектурное решение, которое влияет на хранение данных, серверное API, интерфейс и тестирование. Для клиентских приложений часто достаточно кэширования, для рабочих инструментов полевых сотрудников — нужна полноценная офлайн-работа с продуманной синхронизацией.
Определите нужный уровень офлайн-поддержки до начала разработки, а правила разрешения конфликтов — вместе с бизнесом.
Мы проектируем и разрабатываем приложения для работы в сложных условиях связи, включая серверную часть синхронизации. Подробнее — на странице мобильной разработки, а если приложению нужно обмениваться данными с учётной системой — в разделе интеграция по API.