Випуск оновлень мобільних додатків (Major/Minor/Patch)
Життєвий цикл додатка після першого релізу — це безперервний потік оновлень різного ваги. Patch hotfix потрібно випустити за кілька годин. Major релиз з новою архітектурою даних потребує тижнів підготовки та поетапного rollout. Підходити до них однаково — означає або гальмувати критичні фікси, або випускати великі зміни без потрібного захисту.
Семантика версій у мобільному контексті
Semver (Major.Minor.Patch) у мобільній розроблені працює дещо інакше, ніж в серверному софті. versionName — це маркетингова рядок, яку бачить користувач. versionCode (Android) та CFBundleVersion (iOS) — монотонно зростаючі цифри, які використовують сторам для визначення «новіше/старіше». Рассинхронізація між ними — джерело реальних проблем.
Patch (x.x.N): Hotfix краша, правка опечатки, фікс неверного перекладу. Інкрементуйте versionCode, змініть versionName мінорно. Для iOS можете використовувати CFBundleVersionString без смены CFBundleShortVersionString — але сторам це видять як оновлення, ревю все ще потрібний.
Minor (x.N.0): Нова фіча, зміна UI, новий екран. Без Breaking Changes в схемі даних, без змін в API-контрактах. Користувач оновлюється — нічого не ломається.
Major (N.0.0): Зміна схеми локальної БД (Room migration, CoreData migration), смена мінімальної версії ОС, рефакторинг з зміною структури даних у Keychain/SharedPreferences. Потребує міграційної стратегії — дані користувачів, збережені старою версією, мають коректно перенестися.
Найболючіша частина — Major з міграцією даних
Room (Android) та CoreData (iOS) надають механізми міграції, але вони потребують чіткого планування. Типична проблема: розробник додав поле в entity, збільшив version в @Database, але забув написати об'єкт Migration — Room виокидає IllegalStateException: Room cannot verify the data integrity при запуску у користувачів з попередньою версією.
Для CoreData аналогічна помилка — змінити модель без lightweight migration або без явного mapping model. Додаток крашится при запуску на пристроях з існуючими даними, хоча на чистій встановленні працює нормально.
Стратегія для складних міграцій: fallback з fallbackToDestructiveMigrationFrom (Room) лише якщо втрата даних прийнятна. Більшість випадків — написати явну Migration з SQL-скриптом. Тестувати міграцію на реальних даних з попередньої версії, не тільки на порожній БД.
Release процес
Android: Сборка AAB, підпис, загрузка в Play Console. Використовуйте staged rollout — почніть з 5-10%, мониторте Android Vitals (crash rate, ANR) 24 години, потім розширюйте. Для patch-оновлень прискорте rollout. Для Major — обов'язкова пауза на кожному етапі.
iOS: Сборка через Xcode Cloud або Fastlane з gym. Загрузка через Transporter або fastlane deliver. Використовуйте Phased Release (7 днів, 1-2-5-10-20-50-100%) для minor та major оновлень. Для hotfix — можна пропустити Phased Release, але ревю займе свій час.
Автоматизуйте через Fastlane: lane :release з increment_build_number, тестами, сборкою та загрузкою. CI/CD через GitHub Actions або Bitrise — кожен merge в main після тестів готує сборку для TestFlight/Internal Testing.
Чек-лист перед кожним релізом
- Міграції даних протестовані на реальних сценаріях апгрейду (не тільки чистая встановлення)
-
versionCode/CFBundleVersionбільше попередньої опублікованої - Release notes написані на всіх підтримуваних мовах
- Перевірена backward compatibility з API бэкенда (особливо важливо при Major)
- Firebase Crashlytics або Sentry підключені та працюють у release-конфігурації
Строки залежать від типу оновлення: patch — один-два дні, minor — три-п'ять днів, major — один-три тижні з міграційним тестуванням.







