Тестування сумісності мобільного додатку на різних пристроях
Дизайнер намалював макет під iPhone 14 Pro з екраном 6.1'' та Dynamic Island. Розробник перевіряв на тому ж пристрої. Релиз вийшов, та виявилося: на Samsung Galaxy A03 з екраном 720×1600 кнопка «Підтвердити» йде за межі екрана, бо верстали під safe area, якого на старих Samsung немає. На iPad Mini нижня навігація займає третину екрана, бо ніхто не тестував на планшеті.
Пристрої занадто різні. Єдиного рішення немає — есть методичне тестування.
Чим різняться пристрої
Не тільки розміром екрана. Ось що реально впливає на поведінку додатку:
Розрізнення та щільність пікселів. ldpi (120 dpi), mdpi (160), hdpi (240), xhdpi (320), xxhdpi (480), xxxhdpi (640). Іконки без адаптованих варіантів виглядають розмито або гігантськими. На Redmi з 720p та Samsung з 1080p при тій же фізичній діагоналі — різна щільність, різні dp→px перерахування.
Соотношение сторон. Стандарт 16:9 (720×1280) застарілий. Актуальні: 20:9 (Samsung S-series), 19.5:9 (iPhone), 21:9 (Sony Xperia), складні пристрої зі змінним соотношенням. Верстка, яка хардкодує висоту елементів, ломается на нестандартних пропорціях.
Safe Area та вирізи. Dynamic Island (iPhone 14 Pro+), notch-hole (Samsung), punch-hole camera (більшість сучасних Android). На Android — WindowInsets та displayCutout. Без обробки вирізів контент йде під камеру.
Продуктивність залізо. Qualcomm Snapdragon 8 Gen 3 у флагмані vs MediaTek Helio G85 у бюджетнику — це різні рівні продуктивності. Анімації на 120 fps, які плавно працюють на флагмані, дергаються на mid-range. Складні Compose-лейауты з multiple recompositions це почувають.
Апаратні можливості. Немає NFC (бюджетні пристрої), немає барометра, немає LiDAR, немає Face ID. Без перевірки PackageManager.hasSystemFeature() спроба використати недоступне залізо — крєш або silent fail.
Матриця пристроїв
Складаємо на основі аналітики (Firebase, Mixpanel по device_model), загальної статистики ринку та бізнес-вимог:
| Категорія | Приклади | Чому включаємо |
|---|---|---|
| Флагман iOS | iPhone 15 Pro, iPhone 14 | Цільова аудиторія, Dynamic Island |
| Компактний iOS | iPhone SE 3rd gen | Маленький екран, немає notch |
| Планшет iOS | iPad (10th gen), iPad Pro | Широкий екран, Split View |
| Флагман Android | Google Pixel 8, Samsung S24 | Поточна Android, OLED |
| Mid-range Android | Samsung A54, Xiaomi Redmi Note 12 | Найбільша доля ринку |
| Бюджетний Android | Samsung A03, Redmi 10 | Низька продуктивність, 720p |
| Планшет Android | Samsung Galaxy Tab S9 | Адаптивний layout |
| Складаний | Samsung Z Fold 5 | Якщо підтримується форм-фактор |
Мінімальна матриця для більшості проектів: 5–7 пристроїв. Більше — через BrowserStack або Firebase Test Lab (реальні пристрої без покупки).
Тестування адаптивного layout
На Android — WindowSizeClass з Jetpack Compose:
val windowSizeClass = calculateWindowSizeClass(this)
when (windowSizeClass.widthSizeClass) {
WindowWidthSizeClass.Compact -> PhoneLayout() // < 600dp
WindowWidthSizeClass.Medium -> TabletLayout() // 600–840dp
WindowWidthSizeClass.Expanded -> DesktopLayout() // > 840dp
}
Тестуємо всі три класи: Compact (телефон portrait), Medium (планшет portrait або телефон landscape), Expanded (планшет landscape).
На iOS — horizontalSizeClass у SwiftUI:
@Environment(\.horizontalSizeClass) var sizeClass
var body: some View {
if sizeClass == .compact {
VStack { ... }
} else {
HStack { ... } // iPad, landscape iPhone Plus
}
}
Специфіка складних пристроїв
Samsung Galaxy Z Fold — два режими: складена (compact, 22:9) та розкрита (великий екран, ~4:3). Додаток повинен коректно переходити між режимами без втрати стану. onConfigurationChanged вызывается при складанні/розкриванні. Якщо Activity пересоздаётся — усі незбережені дані у формі теряються.
Перевіряємо: фокус у TextField збережений, скрол-позиція відновлена, модальні вікна не «прибухають».
Перевірка апаратних можливостей
// Android: перевіряємо перед використанням
val hasBluetooth = packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
val hasNfc = packageManager.hasSystemFeature(PackageManager.FEATURE_NFC)
val hasCamera = packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
Якщо функція недоступна — приховуємо UI-елемент або показуємо пояснення. Не падаємо, не показуємо недоступну кнопку.
Строки
2–3 дні — складання матриці пристроїв по аналітиці, тестування на приоритетних пристроях (емулятори + облачна ферма), звіт з матрицею несумісностей та скриншотами. Вартість розраховується індивідуально.







