Как заставить пользователей обновить приложение
Практика3 минРедакция Innovialabs
Коротко
Приложение при запуске узнает с сервера минимальную и актуальную версии: ниже минимальной — блокирующий экран обновления, ниже актуальной — мягкое предложение, а API продолжает поддерживать старых клиентов до перехода.
Короткий ответ
Нужны две вещи, заложенные с первого релиза:
- Проверка версии при запуске. Приложение получает с бэкенда или из remote config два значения:
min_supported_versionиlatest_version. - Две реакции. Версия ниже минимальной — жесткое обновление (hard update), без него дальше не пройти. Ниже актуальной — мягкое (soft update), можно отложить.
Если такой проверки нет в уже установленных версиях, «заставить» их обновиться нельзя — только сломать их API, что хуже. Поэтому механизм добавляют в самую первую версию.
Проверка минимальной версии
Источник значений:
- Свой бэкенд — эндпоинт конфигурации или заголовок в ответах API. Полный контроль, можно задавать разные версии для iOS и Android.
- Remote config (например, Firebase Remote Config) — меняется без деплоя, есть условия по платформе и аудитории.
Пример конфигурации:
{
"ios": { "min_supported_version": "2.3.0", "latest_version": "2.5.1" },
"android": { "min_supported_version": "2.3.0", "latest_version": "2.5.1" }
}
Важно:
- Сравнивайте версии по частям как числа, а не как строки:
2.10.0новее2.9.0. - Повышайте минимальную версию только после того, как сборка доступна в обоих магазинах — иначе пользователь увидит «обновитесь», а обновления еще нет.
- Если конфиг не загрузился (нет сети), не блокируйте пользователя — используйте последнее сохраненное значение.
- Дополнительно передавайте версию приложения в заголовке каждого запроса. Сервер может ответить кодом
426 Upgrade Required, если клиент слишком старый.
Android: Google Play In-App Updates
Google Play предоставляет API In-App Updates с двумя режимами:
- IMMEDIATE — полноэкранный поток обновления, Play сам скачивает, устанавливает и перезапускает приложение.
- FLEXIBLE — загрузка в фоне, пользователь продолжает работать; когда загрузка завершена, вы предлагаете перезапуск.
val appUpdateManager = AppUpdateManagerFactory.create(context)
appUpdateManager.appUpdateInfo.addOnSuccessListener { info ->
if (info.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE &&
info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
) {
appUpdateManager.startUpdateFlowForResult(
info,
updateLauncher,
AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build()
)
}
}
Приоритет обновления можно задать при публикации через Play Developer API, а clientVersionStalenessDays() показывает, как давно доступна новая версия. API работает только для установок из Google Play, поэтому собственная проверка min_supported_version все равно нужна.
iOS: своя логика
Встроенного аналога In-App Updates в iOS нет. Обычный подход:
- Сравнить текущую версию с
min_supported_versionиlatest_versionиз вашего конфига. - Показать свой экран или диалог и открыть страницу приложения в App Store.
- Можно запросить текущую версию в App Store через iTunes Search API, но собственный конфиг надежнее: вы сами решаете, когда версия становится обязательной.
Учитывайте phased release в App Store: новая версия доходит до пользователей постепенно, при этом вручную обновиться можно сразу.
Версионирование API для старых клиентов
Принудительное обновление — крайняя мера. Основная защита — API, совместимый со старыми версиями:
- Добавляйте поля, но не удаляйте и не меняйте смысл существующих.
- Ломающие изменения выпускайте в новой версии API (
/v2/...) и держите старую, пока доля клиентов на ней не станет приемлемой. - Отслеживайте распределение пользователей по версиям приложения — это основа решения, когда поднимать минимальную версию.
- Клиент должен корректно переживать неизвестные поля и значения перечислений.
UX мягкого и жесткого обновления
| Мягкое | Жесткое | |
|---|---|---|
| Когда | Новые функции, исправления | Уязвимость, несовместимый API, юридические требования |
| Вид | Баннер или закрываемый диалог | Полноэкранный экран без обхода |
| Частота | Не чаще, чем разумно, с запоминанием «позже» | При каждом запуске до обновления |
| Текст | Что нового и зачем обновиться | Почему без обновления нельзя продолжить |
Не злоупотребляйте жестким обновлением: каждый блокирующий экран — риск, что часть пользователей не вернется.