Услуги Портфолио Контакты БлогНовости +7 (800) 511‑32‑27 Обсудить проект
Мобильная разработка

Offline-first в мобильных приложениях: как это работает

22 октября 2026·18 мин чтения
Автор материалаЕкатеринаспециалист по процессам YuSMP Group
Добавить YuSMP как предпочитаемый источник в Google
Сотрудник склада работает в мобильном приложении без подключения к интернету

Коротко. Offline-first в мобильных приложениях — подход, при котором приложение сначала читает и пишет данные в локальную базу на устройстве, а синхронизация с сервером идёт в фоне. Пользователь не ждёт сеть, введённые данные не теряются. Подход нужен там, где связь нестабильна, а потерянное действие стоит денег: на складе, у курьеров, в выездном сервисе и медицине.

Google в официальном руководстве по архитектуре Android прямо формулирует главный принцип: в offline-first приложении локальный источник данных — канонический источник истины, и верхние слои приложения читают данные только из него. Offline-first приложением там называют такое, которое выполняет всю или хотя бы критичную часть основной функциональности без доступа к интернету. Ту же идею, только шире, развивает эссе исследователей Ink & Switch о local-first software, а для веба стратегии работы без сети давно описаны в The Offline Cookbook на web.dev.

Звучит академично, но проблема очень приземлённая. Курьер заходит в подъезд, кладовщик уходит вглубь склада с металлическими стеллажами, агроном едет по полю, менеджер садится в самолёт или оказывается в роуминге. В обычном приложении в этот момент крутится бесконечный спиннер, а заполненная форма пропадает. В offline-first приложении человек продолжает работать, а данные догоняют сервер, когда связь вернётся. Поэтому офлайн-режим мы обсуждаем с заказчиком ещё на этапе разработки мобильных приложений: добавить его позже заметно сложнее.

В статье разберём, что такое offline-first и чем он отличается от «кэша на всякий случай», когда офлайн-режим окупается, а когда хватит частичного, как устроены локальная база, очередь изменений и синхронизация, что делать с конфликтами, как тестировать и что влияет на сроки и бюджет.

Что такое offline-first простыми словами

Offline-first — это архитектурный подход, при котором мобильное приложение проектируется так, будто сети нет, а сервер — лишь место, с которым данные периодически сверяются. Любое действие пользователя сначала записывается в локальную базу на устройстве, экран сразу показывает результат, а отправка на сервер происходит отдельно и незаметно для человека.

Ключевая идея — локальная база как единственный источник истины (single source of truth). Экран никогда не ходит в сеть напрямую: он подписан на данные в локальной базе и перерисовывается, когда они меняются. Синхронизация обновляет базу, база обновляет экран. Поэтому для интерфейса нет разницы, пришли данные минуту назад с сервера или были созданы пользователем в авиарежиме.

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

Offline-first, online-first и offline-tolerant: в чём разница

На практике встречаются три подхода к работе без сети. Они отличаются тем, где живут данные и что происходит при обрыве связи.

ПараметрOnline-firstOffline-tolerantOffline-first
Источник данных для экранаСерверСервер, при ошибке — кэшЛокальная база
Что видит пользователь без сетиОшибку или пустой экранПоследние загруженные данные только для чтенияПолноценный интерфейс: чтение и запись
Что происходит с действиями без сетиНе выполняютсяБлокируются или теряютсяВстают в очередь и отправляются позже
Сложность разработкиНизкаяСредняяВысокая: синхронизация, конфликты, миграции
Типичные примерыОнлайн-банкинг, биржевые терминалы, видеосвязьНовостные ленты, каталоги, справочникиЗаметки и задачи, складские и курьерские приложения, выездной сервис

Многие приложения находятся между этими полюсами: например, каталог работает как offline-tolerant, а оформление заявки — как offline-first. Это нормально — подход выбирают для сценария, а не для всего продукта.

Offline-first и local-first

Local-first — более радикальная версия той же идеи, которую сформулировали исследователи Ink & Switch во главе с Мартином Клеппманом. В local-first данные принадлежат пользователю и полноценно живут на его устройствах, а сервер нужен лишь для обмена и резервного копирования. Чтобы правки с разных устройств сливались без потерь, там используют CRDT (conflict-free replicated data types) — структуры данных, которые математически гарантируют одинаковый результат слияния в любом порядке. Для большинства бизнес-приложений достаточно классического offline-first с сервером как главным арбитром, но идеи local-first полезны там, где несколько людей одновременно редактируют один документ.

Когда офлайн-режим нужен бизнесу

Офлайн-режим нужен бизнесу, когда сотрудник или клиент обязан выполнить действие в месте без надёжной связи, а несделанное или потерянное действие ведёт к прямым убыткам: сорванной доставке, ошибке в остатках, повторному выезду. Чем дороже минута простоя и чем хуже связь на объекте, тем быстрее окупается offline-first.

Типичные сценарии выглядят так:

СценарийЧто делает пользователь без сетиЧто происходит после синхронизации
Склад и инвентаризацияСканирует штрихкоды, вводит фактические остатки, отмечает расхожденияОстатки уходят в учётную систему, расхождения попадают в отчёт
Курьер и доставкаВидит маршрут и заказы на смену, отмечает вручение, фотографирует подтверждениеСтатусы заказов обновляются у диспетчера и клиента, фото загружаются на сервер
Выездной сервис и мерчандайзингЗаполняет чек-листы, акты работ, фотоотчёты по выкладкеАкты и фото попадают в CRM, руководитель видит выполнение
Полевые работы и агроЗаписывает наблюдения по участкам, отмечает точки на офлайн-картеДанные объединяются с данными других бригад, строится сводка
Медицина и обходыОткрывает карточку пациента, вносит назначения и показателиЗаписи попадают в медицинскую систему с исходным временем ввода
Торговые представителиСмотрит каталог и цены, оформляет заказ у клиентаЗаказ уходит в учётную систему, проверяются актуальные цены и остатки
Туризм и путешествияОткрывает билеты, бронирования, офлайн-карты и маршрутыПодгружаются изменения расписания и новые бронирования
Заметки и задачиСоздаёт и редактирует записи, отмечает выполненноеИзменения появляются на остальных устройствах пользователя

Признаки, что офлайн-режим окупится именно у вас:

  • сотрудники работают на объектах, где связь объективно плохая: подвалы, склады, промзоны, трассы, сельская местность;
  • один потерянный ввод данных стоит дорого: повторный выезд, недоставленный заказ, ошибка в учёте;
  • пользователи жалуются на «зависания» и потерянные формы, а в аналитике видны таймауты сетевых запросов;
  • работа идёт сменами, и задания на смену можно загрузить заранее;
  • приложение — рабочий инструмент, а не витрина: им пользуются по много раз в день.

Когда офлайн-режим не нужен — и чем можно обойтись

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

Примеры таких сценариев:

  • платежи и переводы — списание средств нельзя «поставить в очередь» без явного согласия пользователя и проверки баланса;
  • биржевые торги и аукционы — цена через пять минут уже другая;
  • бронирование в реальном времени — место в зале или слот у врача может занять другой человек;
  • живые чаты и видеосвязь — без сети пропадает сам смысл общения в моменте.

Но даже здесь часто полезен частичный офлайн — компромисс между полной синхронизацией и её отсутствием:

  • только чтение — история операций, каталог, расписание доступны без сети, а изменения требуют связи;
  • только черновики — пользователь заполняет заявку офлайн, а отправляет её сам, когда сеть появится;
  • кэш каталога — товары, цены и изображения хранятся локально и обновляются по расписанию, корзина и оплата работают онлайн.

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

Как устроено offline-first приложение изнутри

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

Путь данных выглядит так:

  1. UI — экраны и компоненты. Подписаны на данные и показывают то, что лежит в локальной базе.
  2. Репозиторий — единая точка доступа к данным. Принимает действия пользователя и превращает их в записи.
  3. Локальная база данных — хранит все рабочие данные и является источником истины.
  4. Очередь исходящих изменений (outbox) — журнал действий, которые ещё не дошли до сервера.
  5. Модуль синхронизации — фоновый процесс: отправляет очередь, забирает изменения с сервера, решает конфликты.
  6. Серверный API — принимает пакеты изменений и отдаёт дельты.
Синхронизация данных между смартфоном и сервером после восстановления сети

Локальная база как источник истины

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

Очередь несинхронизированных изменений

Outbox — это таблица, где каждое изменение хранится как отдельная задача со статусом: pending (ждёт отправки), synced (подтверждено сервером) или failed (сервер отклонил). Модуль синхронизации отправляет задачи по порядку и при сетевой ошибке повторяет попытку с экспоненциальной задержкой: через несколько секунд, затем дольше, чтобы не сажать батарею и не перегружать сервер. Схематично цикл выглядит так:

for task in outbox.where(status = pending).orderBy(createdAt):
    response = api.send(task, idempotencyKey = task.id)
    if response.ok:         task.status = synced
    elif response.rejected: task.status = failed   // показать пользователю
    else:                   retryLater(backoff)    // сеть, таймаут

Порядок важен: если пользователь сначала создал клиента, а потом заказ для него, заказ не должен уйти на сервер раньше клиента.

Идентификаторы объектов: локальный и серверный ID

Классическая проблема офлайна — идентификаторы. Если ID записи выдаёт сервер, то созданный без сети объект какое-то время живёт без ID, а связанные с ним записи не на что ссылать. Решений два. Первое — двойные ключи: локальный ID на устройстве и серверный ID, который проставляется после синхронизации и подменяется во всех связях. Второе, более простое, — генерировать UUID прямо на клиенте и использовать его как основной идентификатор и на устройстве, и на сервере. Мы обычно выбираем второй вариант: он убирает целый класс ошибок с подменой ссылок.

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

На устройстве хранят данные, без которых пользователь не может выполнить свои задачи офлайн, а на сервере оставляют всё, что быстро устаревает, опасно при утечке или слишком объёмно для телефона. Граница проводится по сценариям: для каждого действия без сети спрашиваем, какие данные ему нужны.

Хранить локально:

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

Оставить только на сервере:

  • платёжные данные и реквизиты карт;
  • остатки и цены, которые меняются в реальном времени и не должны браться из устаревшей копии;
  • персональные данные других людей, которые сотруднику не нужны для текущей задачи;
  • тяжёлые архивы: история за годы, отчёты, видео.

Отдельно стоит задать лимиты: сколько дней истории хранить, какой объём медиа держать до загрузки, когда очищать устаревшие записи (TTL кэша). Без этих правил через полгода работы приложение занимает гигабайты и тормозит на бюджетных смартфонах.

Чем хранить данные локально: SQLite, Room, Core Data и другие

Для локального хранения в offline-first приложениях чаще всего используют встраиваемую реляционную базу SQLite и надстройки над ней, а также объектные базы вроде Realm, Isar и Hive. Выбор зависит от платформы, сложности связей между данными и требований к реактивности интерфейса. Про общие принципы выбора между реляционной и документной моделью мы писали в статье «SQL или NoSQL».

РешениеПлатформаТипКогда брать
SQLiteВсе платформыВстраиваемая реляционная базаОснова большинства решений; сложные связи, выборки и транзакции
RoomAndroidORM-слой над SQLiteСтандарт для нативного Android: проверка запросов на этапе сборки, реактивные потоки, миграции
Core Data / SwiftDataiOSФреймворк объектного графа (по умолчанию поверх SQLite)Нативный iOS; SwiftData — для проектов на SwiftUI
RealmiOS, Android, кроссплатформаОбъектная базаОбъектная модель без ручного маппинга, живые объекты в интерфейсе
Drift, Isar, HiveFlutterDrift — над SQLite; Isar и Hive — NoSQLDrift — для реляционных данных; Isar и Hive — для простых объектов и быстрого старта
WatermelonDBReact NativeРеактивная база поверх SQLiteБольшие объёмы данных и встроенный протокол синхронизации
DataStore / UserDefaultsAndroid / iOSХранилище «ключ — значение»Только настройки и флаги, не рабочие данные

Если приложение выходит сразу на iOS и Android, логику офлайна выгодно писать один раз. Разработка на Flutter позволяет держать локальную базу, очередь изменений и алгоритм синхронизации в общем коде, а с нативными механизмами платформ — фоновыми задачами, шифрованием ключей, сетью — работать через плагины. В React Native похожую роль играет WatermelonDB со встроенной поддержкой синхронизации. Главное — не выбирать хранилище «по моде»: смотрите на модель данных, объём и то, насколько удобно в выбранной базе делать миграции схемы.

Как работает синхронизация после восстановления сети

Синхронизация в offline-first приложении — это фоновый процесс, который отправляет на сервер накопленные локальные изменения и забирает изменения, сделанные другими пользователями или системами, приводя локальную базу и сервер к согласованному состоянию. В руководстве Android выделяют два базовых подхода: pull и push.

ПодходКак работаетПлюсыМинусы
Pull-синхронизацияПриложение запрашивает данные у сервера по требованию — например, при открытии экранаПростота реализацииМного трафика, плохо подходит для связанных реляционных данных, офлайн доступно только загруженное
Push-синхронизацияПриложение один раз загружает базовый набор данных, затем сервер уведомляет, что данные устарели, и клиент забирает измененияПриложение может работать офлайн сколь угодно долго, минимум трафикаСложное версионирование данных и логика на сервере

Синхронизацию запускают фоновые механизмы платформ: на Android — WorkManager, который умеет ставить задачи в очередь, повторять их при сбое и ждать появления сети, на iOS — Background Tasks. Чтобы синхронизация была быстрой и надёжной, используют несколько приёмов:

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

Один цикл синхронизации обычно состоит из шагов:

  1. Модуль синхронизации получает сигнал: появилась сеть, сработал таймер или пришло push-уведомление.
  2. Изменения из outbox отправляются на сервер пакетами по порядку.
  3. Сервер подтверждает принятые изменения, задачи в outbox получают статус synced.
  4. Клиент запрашивает изменения с сервера начиная со своей последней метки синхронизации.
  5. Полученные данные записываются в локальную базу, при совпадении записей запускается разрешение конфликтов.
  6. Метка последней синхронизации обновляется, экраны перерисовываются из базы автоматически.

Синхронизация опирается на серверную сторону не меньше, чем на клиент: API должен уметь отдавать дельты и принимать пакеты. Подробнее о проектировании серверной части — в статье «API для мобильного приложения».

Что делать с конфликтами данных

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

СтратегияКак работаетКогда подходит
Last Write WinsПобеждает изменение с более поздней меткой времени (стратегия, которую приводит руководство Android)Настройки, статусы, данные, где потеря чужой правки некритична
«Сервер прав»При расхождении сохраняется серверная версия, локальная отбрасывается или уходит в журналЦены, остатки, справочники, которые ведёт учётная система
Слияние по полямЕсли изменены разные поля записи, объединяются обе правки; конфликт только при правке одного поляКарточки клиентов, заявки, анкеты
Ручное разрешениеПользователь видит обе версии и выбирает нужнуюРедкие, но дорогие конфликты: медицинские записи, юридически значимые данные
CRDTСтруктуры данных, которые сливают изменения без конфликтов по математическим правиламСовместное редактирование текстов, списков, досок

Пример: два кладовщика офлайн пересчитали одну и ту же ячейку и внесли разные остатки. Last Write Wins тут опасен — победит тот, кто позже нажал кнопку, а не тот, кто посчитал верно. Правильнее хранить не итоговое число, а операции («+5», «−2») и складывать их на сервере, а явное расхождение пересчёта отправлять на проверку. Метки времени, кстати, лучше брать с сервера или учитывать сдвиг часов устройства: часы телефона могут быть переведены вручную.

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

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

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

Подсказка. Покажите время последней синхронизации: «Данные обновлены 12 минут назад». Эта строка снимает большую часть вопросов «а у меня актуальные цены?» и почти ничего не стоит в разработке.

Безопасность данных на устройстве

Безопасность данных в offline-first приложении — это защита локальной базы на случай кражи, потери телефона или увольнения сотрудника, потому что рабочие данные физически лежат на устройстве, а не только на сервере. Чем больше данных приложение хранит офлайн, тем внимательнее нужно относиться к этому слою.

  • Шифрование базы. Локальную базу шифруют, например, с помощью SQLCipher для SQLite. Ключ шифрования хранят не в коде, а в Android Keystore или iOS Keychain.
  • Удалённая очистка. При потере устройства или увольнении сотрудника администратор отзывает доступ, и при следующем подключении приложение стирает локальные данные.
  • Срок жизни офлайн-сессии. Приложение не должно работать без повторного входа бесконечно: задайте лимит — например, одну смену или несколько дней — после которого нужна авторизация.
  • Минимизация персональных данных. Храните на устройстве только то, что нужно для текущей задачи. Это снижает риски и упрощает соответствие требованиям 152-ФЗ о персональных данных.

Как внедрить offline-first: пошаговый план

Внедрение offline-first — это проектная работа, которая начинается не с выбора библиотеки, а с описания сценариев: что именно пользователь должен сделать без сети. Мы обычно идём по семи шагам.

  1. Выпишите критичные сценарии без сети. Какие действия обязаны работать офлайн, а какие могут подождать связь. Это определяет границы и объём работ.
  2. Определите данные и срок их хранения. Какие справочники, задания и черновики лежат на устройстве, за сколько дней и какого объёма, что никогда не попадает в локальную базу.
  3. Выберите локальную базу данных под платформу и модель данных — по таблице выше.
  4. Спроектируйте API под синхронизацию. Выдача изменений с метки или версии, клиентские UUID, пакетная отправка, идемпотентность запросов, мягкое удаление.
  5. Выберите стратегию конфликтов для каждого типа данных и согласуйте её с бизнесом: кто прав, если два человека изменили одно и то же.
  6. Продумайте UX-статусы: индикатор сети, статусы записей, счётчик очереди, сообщения об ошибках.
  7. Протестируйте в плохой сети — подробнее в следующем разделе.

Почему офлайн сложно добавить в готовое приложение

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

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

Тестирование офлайн-режима — это проверка поведения приложения не только при полном отсутствии сети, но и при медленной, нестабильной и обрывающейся связи, а также при долгом офлайне и одновременной работе нескольких устройств. Большинство ошибок офлайна проявляется не в авиарежиме, а на «плохой» сети, когда запросы уходят, но ответы теряются.

Чек-лист, по которому мы проверяем офлайн-сценарии:

  • авиарежим: все критичные сценарии выполняются, данные сохраняются и отображаются;
  • эмуляция плохой сети: Network Link Conditioner на iOS, профили скорости и задержки сети в Android Emulator;
  • обрыв посреди отправки: запрос ушёл, ответ не пришёл — повторная отправка не создаёт дубль;
  • долгий офлайн: несколько дней без сети, сотни изменений в очереди, корректная отправка после подключения;
  • конфликт с двух устройств: одна запись изменена офлайн на двух телефонах — срабатывает выбранная стратегия;
  • смена пользователя на устройстве: данные одного сотрудника не видны другому;
  • переустановка и обновление приложения: миграция локальной базы не теряет неотправленные изменения;
  • нехватка места и разряд батареи: приложение не падает и не теряет данные.

Часть этих сценариев стоит автоматизировать: тесты синхронизации и конфликтов на уровне репозитория дешёвые и ловят регрессии до релиза.

Сколько стоит и сколько времени добавляет offline-first

Offline-first увеличивает трудоёмкость проекта, потому что к обычной разработке добавляются локальная база, синхронизация, разрешение конфликтов, доработка серверного API и заметно больший объём тестирования. Насколько дороже — зависит от глубины офлайна, а не от самого факта его наличия, поэтому универсальной цифры нет.

Что увеличивает объём работ:

  • двусторонняя синхронизация вместо односторонней загрузки;
  • сложные связи между данными и много типов сущностей;
  • нетривиальные конфликты, требующие ручного разрешения или CRDT;
  • интеграции с учётными системами, которые сами не поддерживают дельты;
  • офлайн-медиа: фото, подписи, документы большого объёма.

Что снижает объём работ:

  • частичный офлайн — только чтение или только черновики;
  • простые стратегии конфликтов вроде «сервер прав» для большинства данных;
  • готовые решения синхронизации, встроенные в выбранную базу;
  • офлайн, заложенный с первого спринта, а не добавленный после релиза.

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

Частые вопросы

Что значит offline-first в мобильном приложении?

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

Чем offline-first отличается от обычного кэширования?

Кэш — это копия ответов сервера, которую приложение показывает, пока ждёт свежие данные; писать в него обычно нельзя. В offline-first локальная база — главный источник истины: пользователь создаёт и меняет записи без сети, изменения встают в очередь и уходят на сервер позже, а приложение решает конфликты.

Можно ли добавить офлайн-режим в уже готовое приложение?

Можно, но это дороже, чем заложить его сразу. Придётся переписать слой данных так, чтобы экраны читали из локальной базы, доработать серверный API под синхронизацию, добавить очередь изменений, миграции и тесты. Часто разумный компромисс — частичный офлайн для самых важных сценариев.

Какую базу данных выбрать для офлайн-режима?

Для большинства задач подходит реляционная SQLite и обёртки над ней: Room на Android, Core Data или SwiftData на iOS, Drift во Flutter, WatermelonDB в React Native. Realm, Isar и Hive удобны для объектной модели. Простые настройки хранят в DataStore или UserDefaults, а не в базе.

Как решаются конфликты, если данные изменили на двух устройствах?

Стратегию выбирают под тип данных. Last Write Wins оставляет изменение с более поздней меткой времени, стратегия «сервер прав» отдаёт приоритет серверу, слияние по полям объединяет правки разных полей, а критичные конфликты показывают пользователю. Для совместного редактирования применяют CRDT, которые сливают изменения без конфликтов.

Работает ли offline-first во Flutter и React Native?

Да. Во Flutter для локального хранения используют Drift поверх SQLite, Isar или Hive, в React Native — WatermelonDB или SQLite. Логика очереди и синхронизации пишется один раз для обеих платформ, а фоновые задачи запускаются через нативные механизмы Android и iOS.

Безопасно ли хранить данные на телефоне?

Безопасно, если хранить только необходимое и защищать его. Локальную базу шифруют, например через SQLCipher, ключи держат в Android Keystore или iOS Keychain, ограничивают срок работы без повторного входа и предусматривают удалённую очистку данных при потере устройства или увольнении сотрудника.

Нужно приложение, которое работает без интернета?

Спроектируем офлайн-режим под ваши сценарии: локальное хранилище, очередь изменений и надёжную синхронизацию — в рамках разработки мобильного приложения под ключ.

Обсудить разработку приложения