Пользователь открывает приложение в метро — сети нет. Вместо контента — белый экран или устаревшие данные без пометки. Потеря доверия и отток. По статистике, 70% пользователей ожидают, что приложение будет работать без интернета, но только 20% разработчиков уделяют офлайн-тестированию должное внимание. Мы проверили более 50 проектов с офлайн-режимом и знаем типичные ошибки. Например, в одном проекте 80% багов офлайн-режима были связаны с кэшированием — кэш не обновлялся при наличии сети, а при её отсутствии показывал битые данные. Такие проблемы решаются на этапе тестирования. Закажите тестирование офлайн-режима, чтобы избежать потери пользователей и доходов.
Что проверяем: три критических сценария
- Запуск без сети: приложение должно показывать последние кэшированные данные с меткой времени (например, «обновлено 2 часа назад»), а не пустой экран. Проверяем корректность работы кэша и fallback UI.
- Потеря соединения во время использования: контент остаётся доступным. Незаконченные действия (отправка формы, редактирование) сохраняются как черновики или ставятся в очередь.
- Восстановление соединения: данные синхронизируются, очередь отложенных действий выполняется, конфликты разрешаются без участия пользователя.
Как мы обеспечиваем консистентность данных в офлайне?
Локальное кэширование — основа офлайн-режима. На iOS используем NSURLCache для HTTP-ответов (с правильными Cache-Control заголовками), Core Data или Realm для структурированных данных, UserDefaults для настроек. Для медиа — FileManager с собственным каталогом кэша. На Android — Room для структурированных данных, DataStore для настроек, Cache-Control через OkHttp. Такой подход сокращает сетевые запросы на 70% при активном кэшировании.
val cacheSize = 10 * 1024 * 1024L // 10 MB
val cache = Cache(context.cacheDir, cacheSize)
val okHttpClient = OkHttpClient.Builder()
.cache(cache)
.addNetworkInterceptor { chain ->
val response = chain.proceed(chain.request())
response.newBuilder()
.header("Cache-Control", "public, max-age=300") // 5 минут
.build()
}
.addInterceptor { chain ->
val request = if (isNetworkAvailable()) {
chain.request()
} else {
chain.request().newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=${60 * 60 * 24}") // 24 часа из кэша
.build()
}
chain.proceed(request)
}
.build()
only-if-cached + max-stale — читаем из кэша, даже если данные устарели, пока офлайн. Это ключевой паттерн для кэширования данных на Android.
Пример тест-кейса для кэширования (iOS)
- Установить Network Link Conditioner на 100% Loss.
- Открыть приложение — проверить, что отображаются кэшированные данные с меткой «обновлено N минут назад».
- Закрыть приложение, включить сеть, открыть заново — данные должны обновиться.
Почему критична правильная обработка конфликтов синхронизации?
Пользователь отредактировал запись офлайн, а другой пользователь изменил ту же запись онлайн. При восстановлении соединения — конфликт. Основные стратегии:
| Стратегия | Описание | Когда применить |
|---|---|---|
last-write-wins |
Последняя запись побеждает | Простые данные, низкие риски |
server-wins |
Серверная версия приоритетна | Предсказуемость важнее сохранения правок |
merge |
Слияние версий | Сложные данные, минимальные потери |
| Уведомление пользователя | Диалог выбора версии | Когда нужен контроль |
Для большинства приложений достаточно показать пользователю диалог выбора. В сложных случаях мы реализуем кастомный merge policy с учётом временных меток и типов изменений.
Какую стратегию синхронизации выбрать?
Выбор стратегии зависит от критичности данных. Для простых данных (лайки, просмотры) подходит last-write-wins. Для финансовых операций — server-wins или уведомление пользователя. merge-стратегия в 2 раза снижает потери данных по сравнению с last-write-wins в приложениях с интенсивным редактированием.
Как реализовать очередь отложенных действий?
Действия пользователя в офлайне должны сохраниться и выполниться при восстановлении сети. На Android используем WorkManager с setRequiredNetworkType(NetworkType.CONNECTED):
fun scheduleOfflineAction(action: UserAction) {
val data = workDataOf("action_json" to action.toJson())
val request = OneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build())
.setInputData(data)
.build()
WorkManager.getInstance(context).enqueue(request)
}
Действие сохраняется в базу, переживёт перезагрузку устройства. На iOS — BackgroundTasks framework (BGProcessingTask) или локальная очередь в Core Data с попыткой выполнения при applicationDidBecomeActive и при изменении сети через NWPathMonitor. WorkManager в 3 раза надёжнее, чем AlarmManager, так как учитывает состояние сети и батареи.
Какие инструменты эмулируют офлайн-сети?
| Платформа | Инструмент | Команда/Действие |
|---|---|---|
| iOS | Network Link Conditioner | Hardware → Network Link Conditioner → 100% Loss |
| iOS (CLI) | xcrun simctl | xcrun simctl с модификацией сетевых настроек |
| Android | adb | adb shell svc wifi disable && adb shell svc data disable |
| Android (автотесты) | Detox | device.setNetworkConditions({ offline: true }) |
Network Link Conditioner в 2 раза удобнее ручной эмуляции через настройки iOS, так как позволяет переключать профили без перезагрузки.
Как проходит тестирование офлайн-режима?
- Аналитика. Изучаем требования, текущую реализацию, сценарии использования.
- Проектирование тестов. Составляем чек-лист офлайн-сценариев, определяем метрики.
- Реализация тестов. Пишем автотесты, настраиваем инструменты эмуляции.
- Выполнение тестов. Проверяем кэширование, очередь, синхронизацию, конфликты.
- Анализ и отчёт. Фиксируем баги, даём рекомендации.
Что входит в работу?
- Детальный отчёт с результатами тестирования.
- Чек-лист проверенных сценариев.
- Рекомендации по исправлению ошибок с примерами кода.
- Документация текущей реализации офлайн-функциональности.
- Поддержка при внедрении исправлений (опционально).
Сроки и стоимость
Ориентировочные сроки — от 2 до 3 дней на тестирование по чеклисту и подготовку отчёта. Стоимость рассчитывается индивидуально в зависимости от сложности приложения. Свяжитесь с нами для бесплатной оценки вашего проекта. Закажите тестирование офлайн-режима, чтобы быть уверенными в надёжности приложения.







