Блог

Офлайн режим в мобильном приложении: как реализовать

Пользователь заходит в приложение в метро, в самолёте или в зоне с плохим сигналом — и видит белый экран или ошибку. Он закрывает приложение и не возвращается. Офлайн режим в мобильном приложении решает именно эту проблему: данные доступны, действия сохраняются, а синхронизация происходит в фоне при восстановлении связи. Для маркетплейса это напрямую влияет на конверсию и удержание. В этой статье — конкретная механика реализации без лишней теории.

Что именно должен уметь офлайн-режим

Перед тем как писать код, нужно чётко определить границы. Офлайн-режим — не значит «всё работает без интернета». Это значит «пользователь может выполнить ключевые сценарии, даже если связи нет прямо сейчас».

Для маркетплейса типичный набор офлайн-функций выглядит так:

  • Просмотр ранее загруженных каталогов, карточек товаров, цен.
  • Добавление товаров в корзину и избранное.
  • Просмотр истории заказов и статусов.
  • Заполнение форм (адрес доставки, комментарий к заказу) с отложенной отправкой.
  • Поиск по закэшированным данным.

Что не стоит пытаться делать офлайн: оформление оплаты, запросы к сторонним сервисам (геокодинг, проверка промокодов в реальном времени), чат с поддержкой. Это снизит сложность системы без потери ценности для пользователя.

Архитектура: локальная база данных как источник истины

Ключевой принцип — приложение всегда читает данные из локального хранилища, а не напрямую из сети. Сеть только обновляет это хранилище. Такой подход называется offline-first.

Выбор локальной БД

На практике используют несколько решений:

Решение Платформа Когда подходит
SQLite / Room Android Сложные реляционные данные, запросы с фильтрами
Core Data / SQLite iOS То же самое для iOS
Realm Cross-platform Быстрый старт, реактивные подписки на изменения
SQLite + Drift Flutter Кроссплатформенные приложения на Flutter
WatermelonDB React Native Большие объёмы данных в RN-проектах

Для маркетплейса с каталогом от 10 000 позиций рекомендуем SQLite-based решения: они дают полноценный SQL для сложных фильтров и сортировок.

Стратегии кэширования данных

Не все данные одинаково важно кэшировать. Разделите их на три уровня:

  1. Критичные (кэшировать всегда): каталог категорий, последние просмотренные товары, корзина, профиль пользователя, история заказов за последние 30 дней.
  2. Важные (кэшировать при наличии Wi-Fi или при первом просмотре): карточки товаров с изображениями, описания, отзывы.
  3. Некритичные (не кэшировать): рекламные баннеры, персонализированные рекомендации в реальном времени, актуальные остатки на складе.

Для изображений используйте отдельный кэш с политикой вытеснения LRU (Least Recently Used). На Android это Glide или Coil, на iOS — Kingfisher, в Flutter — cached_network_image. Ограничьте размер кэша изображений: 150–300 МБ достаточно для большинства маркетплейсов.

Синхронизация и разрешение конфликтов

Это самая сложная часть. Пользователь добавил товар в корзину офлайн, а к моменту синхронизации этот товар закончился на складе. Что делать?

Базовые стратегии синхронизации:

  • Last Write Wins (LWW): побеждает последнее изменение по временной метке. Просто в реализации, но теряет данные при параллельных правках.
  • Server Wins: при конфликте всегда берём данные сервера. Подходит для цен, остатков, статусов заказов.
  • Client Wins: данные пользователя имеют приоритет. Подходит для корзины и избранного.
  • Merge: объединяем изменения по правилам бизнес-логики. Самый правильный, но требует проектирования.

Для маркетплейса рабочая схема такая: корзина и избранное — Client Wins с уведомлением («Товар X закончился, он удалён из корзины»). Цены и остатки — Server Wins без исключений. Профиль пользователя — Merge по полям.

Для реализации очереди отложенных действий используйте паттерн Outbox: все действия пользователя офлайн записываются в локальную таблицу-очередь. При восстановлении соединения воркер последовательно отправляет их на сервер и помечает как выполненные.

UX офлайн-режима: как не запутать пользователя

Техническая реализация — половина дела. Пользователь должен понимать, что происходит.

  • Индикатор офлайн-режима: ненавязчивая плашка вверху экрана «Нет соединения — показываем сохранённые данные». Не блокируйте интерфейс модальным окном.
  • Актуальность данных: показывайте время последнего обновления («Каталог обновлён 2 часа назад»). Пользователь сам решит, доверять ли ценам.
  • Недоступные действия: кнопку «Оформить заказ» можно показывать, но при нажатии — объяснить, что действие выполнится после восстановления связи, и предложить сохранить.
  • Автоматическая синхронизация: как только соединение восстановилось — тихо синхронизируйте в фоне. Не требуйте от пользователя нажимать «Обновить».

Технические нюансы реализации

Несколько практических моментов, которые часто упускают на старте:

  • Версионирование схемы БД: при обновлении приложения схема локальной базы может измениться. Реализуйте миграции с первой версии — иначе получите краши у пользователей со старыми данными.
  • Шифрование локальных данных: если приложение хранит персональные данные (адреса, история заказов), локальная БД должна быть зашифрована. SQLCipher — стандартное решение для SQLite.
  • Background Sync на iOS: iOS ограничивает фоновые задачи. Используйте BGTaskScheduler для периодической синхронизации и Silent Push Notifications для триггерной.
  • Размер хранилища: следите за объёмом данных на устройстве. Реализуйте автоочистку устаревших записей — например, удаляйте карточки товаров, которые не просматривались более 60 дней.

Если вы планируете разработку мобильного приложения с нуля, закладывайте офлайн-архитектуру на этапе проектирования: добавить её в готовое приложение значительно дороже и сложнее.

Часто задаваемые вопросы

Сколько стоит добавить офлайн режим в мобильное приложение?

Стоимость зависит от объёма данных, сложности синхронизации и количества офлайн-сценариев. Простой офлайн-просмотр каталога с кэшем — 40–80 часов работы. Полноценный offline-first с очередью действий, разрешением конфликтов и шифрованием — от 150 часов. Для маркетплейса с каталогом от 50 000 позиций закладывайте отдельный спринт на проектирование архитектуры синхронизации.

Какие данные опасно хранить локально на устройстве?

Платёжные данные (номера карт, CVV) хранить локально нельзя ни при каких условиях — это нарушение стандарта PCI DSS. Токены авторизации хранятся только в защищённом хранилище (Keychain на iOS, EncryptedSharedPreferences на Android). Персональные данные пользователей (адреса, история заказов) — только в зашифрованной базе. Всё остальное (каталог, цены, изображения) можно хранить без шифрования.

Как тестировать офлайн-режим в мобильном приложении?

Используйте несколько подходов: отключение сети в настройках эмулятора, режим «В самолёте» на реальном устройстве, Network Link Conditioner на iOS для симуляции нестабильного соединения. Обязательно тестируйте сценарии: приложение запущено офлайн с первого открытия; соединение пропало в середине сессии; соединение восстановилось после длительного офлайна (более 24 часов). Автоматизируйте эти сценарии в UI-тестах с мок-сервером.

Офлайн-режим — это инвестиция в удержание пользователей, а не техническая прихоть. Маркетплейсы, которые работают в метро и в зонах слабого сигнала, получают на 15–25% больше сессий от активной аудитории. Правильная архитектура закладывается один раз и окупается годами.

Если вы хотите обсудить реализацию офлайн-режима для вашего проекта — команда Aris.Web готова разобрать задачу и предложить решение. Свяжитесь с нами по телефону +7 (977) 326-69-09 или оставьте заявку на странице контактов. Также вы можете подробнее узнать об услуге разработка мобильного приложения на нашем сайте.

ARISWEB · ПОД КЛЮЧ ЗА 2 НЕДЕЛИ
Нужно такое решение? Сделаем и опубликуем за 2 недели
Фиксированная цена, оплата онлайн, гарантия публикации в срок.
author-avatar

О Роман Воронов

Роман Воронов — менеджер продаж Aris.Web. Более 15 лет в IT: запуск цифровых платформ, мобильных приложений и маркетплейсов для e-commerce, логистики, промышленности, образования и бизнес-автоматизации. Помогает заказчикам подобрать решение и рассчитать проект.