Тестирование совместимости мобильного приложения на разных версиях ОС
Поддержка iOS 15 и Android 10 означает не просто «не падает» — означает, что все функции работают корректно, без артефактов UI, без silent failures в местах, где новый API вернул бы ошибку, а старый просто ничего не делает. Разрыв между minSdkVersion 26 и compileSdkVersion 35 — это 8 лет эволюции Android API. Пропустить одну deprecated-замену — и на Android 10 в продакшене упадёт NoSuchMethodError.
Матрица версий: как выбрать
Тестировать на каждой версии ОС — нерационально. Принцип:
| Приоритет | Версии iOS | Версии Android |
|---|---|---|
| Обязательно | Текущая − 1 (iOS 17, 18) | Android 12, 13, 14 (API 31–34) |
| Важно | minDeploymentTarget (iOS 15) | minSdkVersion (API 26–28) |
| По аналитике | Версии с долей > 5% у вашей ЦА | То же |
Аналитика Firebase или Mixpanel по os_version даёт реальную картину. Если 8% пользователей на iOS 15 — тестируем. Если 0.3% на iOS 14 — нет.
Deprecated API: где ловить проблемы
Android
Проблемы с устаревшими API чаще всего в следующих областях:
Уведомления (API 26+). На Android 8+ все уведомления требуют NotificationChannel. Без него notify() тихо игнорируется. Приложение думает, что показало уведомление — нет.
// Проверка: создаём канал только на API 26+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(CHANNEL_ID, "General", NotificationManager.IMPORTANCE_DEFAULT)
notificationManager.createNotificationChannel(channel)
}
Разрешения (API 33+). READ_EXTERNAL_STORAGE на Android 13+ заменена на гранулированные: READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO. Запрос старого разрешения на Android 13 не даёт доступа к медиа.
Foreground Service (API 34+). Android 14 требует указывать тип foreground service: dataSync, mediaPlayback, location и др. Без типа — SecurityException при старте.
Инструмент для проверки: lint с правилом NewApi. В Android Studio: Analyze → Inspect Code. Флаги:
android {
lint {
abortOnError = true
error += setOf("NewApi", "InlinedApi")
}
}
NewApi — вызов API, доступного выше minSdkVersion без @RequiresApi или проверки Build.VERSION.SDK_INT. Это автоматически находит большинство проблем совместимости до запуска.
iOS
@available и #available — обязательные паттерны:
if #available(iOS 16.0, *) {
// NavigationStack, доступен с iOS 16
NavigationStack { ... }
} else {
NavigationView { ... } // deprecated, но работает до iOS 15
}
Компилятор предупреждает об использовании нового API без @available-проверки — это ловится статически. Но есть нюанс: предупреждение, не ошибка. В больших кодовых базах такие предупреждения теряются.
Самая частая потеря: SwiftUI-компоненты, добавленные в новых версиях iOS. ContentUnavailableView (iOS 17), NavigationStack (iOS 16), Charts (iOS 16) — без fallback приложение упадёт на iOS 15 с dyld: Symbol not found.
Инструмент: Xcode Simulator с конкретными версиями
Скачиваем дополнительные runtime: Xcode → Settings → Platforms → + → iOS 15.x Simulator Runtime. После загрузки создаём симулятор нужной версии и тестируем на нём.
Тестовый процесс
Не гоняем весь E2E-suite на каждой версии — это избыточно. Дифференцированный подход:
- Smoke-тест на минимальной поддерживаемой версии: основные флоу работают, приложение стартует.
- Полный регрессионный тест на текущей версии ОС.
- Точечное тестирование на промежуточных версиях — только функции, использующие API конкретной версии.
Список «рисковых» функций по версиям ведём в документе: функция → минимальная версия → тестируется на.
Как выявляем несовместимости без устройств
Firebase Test Lab — тестирование на виртуальных устройствах с разными API-уровнями. Быстро, дёшево, покрывает большинство несовместимостей. Для более тонких проблем (кастомные прошивки Samsung, MediaTek vs Qualcomm) — реальные устройства.
Статический анализ — lint для Android, Xcode Build & Analyze для iOS. Запускаем в CI на каждый PR.
Сроки
2–3 дня — составление матрицы версий по аналитике, тестирование на приоритетных версиях, статический анализ на deprecated API, отчёт с матрицей несовместимостей. Стоимость рассчитывается индивидуально.







