Реалізація міграції кешу при оновленні мобільного додатку
Уявіть: ви випустили оновлення, а користувачі масово скаржаться на вильоти та старі дані. Причина — неінвалідований кеш. Старі зображення завантажені під старими ключами, JSON-відповіді серіалізовані в застарілий формат, HTTP-кеш містить заголовки з битими URL. Якщо не очистити кеш при оновленні — користувач бачить перемішані дані з різних версій, або додаток падає на десеріалізації. Розглянемо на прикладі реального проекту: додаток для доставки, де після оновлення користувачі бачили ціни зі старої відповіді API, що призводило до збитків. Правильна інвалідація кешу вирішила проблему за один день. Міграція кешу — обов'язковий етап будь-якого оновлення. Ми, розробники з 10-річним досвідом, зібрали перевірені методи для iOS та Android.
Чому кеш стає невалідним після оновлення?
Причина — несумісність форматів даних між версіями. Припустимо, у версії 1.0 API повертав об'єкт { "name": "foo" }, а в 2.0 — { "full_name": "foo bar" }. Якщо додаток закешував старий JSON і намагається десеріалізувати його в нову модель — крах. Аналогічно із зображеннями: змінилися шляхи, розміри або хеші. Згідно з документацією Apple URLCache, HTTP-кеш також може містити застарілі заголовки, що призводить до помилок завантаження.
Версіонування ключів кешу
Найпростіший і найнадійніший підхід: прив'язати ключі кешу до версії додатку або до версії API.
// Android — простір імен кешу за версією
object CacheKeyBuilder {
private val appVersion = BuildConfig.VERSION_CODE
fun forImage(imageId: String) = "img_v${appVersion}_$imageId"
fun forApiResponse(endpoint: String) = "api_v${appVersion}_$endpoint"
} // iOS — ключ з номером білда
struct CacheKeyBuilder {
static let appVersion = Bundle.main.buildVersionNumber
static func imageKey(_ id: String) -> String {
"img_v\(appVersion)_\(id)"
}
static func apiKey(_ endpoint: String) -> String {
"api_v\(appVersion)_\(endpoint)"
}
}При оновленні VERSION_CODE або buildVersionNumber всі ключі змінюються — старий кеш перестає використовуватися. Але при цьому старі файли залишаються на диску і потрібне явне очищення.
Очищення застарілого кешу при старті
// iOS class CacheManager {
private let defaults = UserDefaults.standard
private let lastVersionKey = "lastCachedVersion"
func cleanupIfNeeded() {
let current = Bundle.main.buildVersionNumber
let last = defaults.string(forKey: lastVersionKey) ?? ""
guard current != last else { return }
clearDiskCache()
clearURLCache()
defaults.set(current, forKey: lastVersionKey)
}
private func clearDiskCache() {
let cacheDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
try? FileManager.default.removeItem(at: cacheDir.appendingPathComponent("ImageCache"))
}
private func clearURLCache() {
URLCache.shared.removeAllCachedResponses()
}
}Викликаємо в application(_:didFinishLaunchingWithOptions:) до ініціалізації UI.
// Android — очищення при старті
class CacheCleaner(private val context: Context) {
fun cleanIfNeeded() {
val prefs = context.getSharedPreferences("cache", Context.MODE_PRIVATE)
val lastVersion = prefs.getInt("lastVersion", 0)
val currentVersion = BuildConfig.VERSION_CODE
if (lastVersion == currentVersion) return
Glide.get(context).clearDiskCache()
val cacheDir = File(context.cacheDir, "http-cache")
cacheDir.deleteRecursively()
prefs.edit().putInt("lastVersion", currentVersion).apply()
}
}Виклик з Application.onCreate() у фоновому потоці.
Kingfisher (iOS) та Glide (Android)
Обидві бібліотеки використовують власні дискові кеші. Kingfisher зберігає кеш у Library/Caches/com.onevcat.Kingfisher.ImageCache. Очищення:
KingfisherManager.shared.cache.clearDiskCache() KingfisherManager.shared.cache.clearMemoryCache() Glide: Glide.get(context).clearDiskCache() — тільки з фонового потоку. Офіційні репозиторії: Kingfisher, Glide.
Порівняння підходів
| Підхід | Складність | Час виконання | Ризик втрати даних |
|---|---|---|---|
| Повне очищення кешу | Низька | 0.5 дня | Високий (всі тимчасові дані зникають) |
| Версіонування ключів + фонове очищення старих | Середня | 1 день | Низький (важливий кеш зберігається до застарівання) |
| Інкрементальна міграція | Висока | 2-3 дні | Дуже низький (тільки несумісні записи) |
Як обрати стратегію міграції кешу?
Для невеликих проєктів достатньо повного очищення при кожному оновленні — це швидко реалізувати і легко перевірити. Якщо важливі швидкість запуску та користувацький досвід, обирайте версіонування ключів з фоновим очищенням. Для фінансових або медичних додатків, де кожен запис критичний, використовуйте інкрементальну міграцію з точковою інвалідацією.
Що входить у роботу
| Етап | Результат |
|---|---|
| Аудит кешування | Опис усіх точок кешування, поточні ризики |
| Проектування стратегії | Вибір підходу під вашу архітектуру |
| Реалізація модулів | Native-код для iOS та Android з Unit-тестами |
| Інтеграція та тестування | Перевірка на кількох версіях додатку |
| Документація | Інструкція з підтримки та деплою |
| Навчання команди | Розбір коду та best practices |
Процес роботи
- Аудит кешування — 0.5 дня.
- Проектування стратегії — 0.5 дня.
- Реалізація на iOS та Android — 1-2 дні.
- Тестування на реальних оновленнях — 0.5 дня.
- Деплой та моніторинг — 0.5 дня.
Терміни
Базова інвалідація кешу при оновленні: від 0,5 дня. З версіонованими ключами, збереженням важливого кешу та фоновим очищенням: від 1 дня. Для складних проектів з кількома джерелами кешу: від 2 до 3 днів.
Чек-лист міграції кешу
Чек-лист міграції кешу
- [ ] Версіонування ключів для зображень та API
- [ ] Код очищення кешу при старті (залежно від версії)
- [ ] Очищення HTTP-кешу (URLCache / HttpCache)
- [ ] Фонове очищення старих файлів (не блокує запуск)
- [ ] Тест: оновлення з версії N-1 до N та перевірка даних
- [ ] Моніторинг крашів після оновлення (Crashlytics)
Версіонування ключів надійніше за повне очищення кешу — воно не вимагає видалення всіх файлів, що економить час старту. Однак старі файли все одно необхідно видаляти при старті, щоб не заповнити сховище.
Наші інженери мають 10+ років досвіду в мобільній розробці та гарантують коректну міграцію кешу без втрати даних. Зв'яжіться з нами для аудиту поточної системи кешування. Отримайте консультацію з вирішення проблем з кешем. Економія часу на розробку — до 2 днів, а зниження витрат на підтримку покриває вартість реалізації протягом місяця.







