Чому ANR небезпечні для вашого додатку?
Уявіть: ваш додаток зависає на 5 секунд, користувач бачить чорний екран і діалог закриття. В Crashlytics приходить ANR без стеку — тільки ім'я Activity. Причина невідома. Так втрачаються користувачі та рейтинг у Google Play. Згідно з офіційною документацією, ANR (Application Not Responding) виникає, коли головний потік блокується довше 5 секунд на input-подію або 10 секунд для BroadcastReceiver.
| Тип події |
Поріг |
| Input-подія |
5 с |
| BroadcastReceiver |
10 с |
| Service (startService) |
20 с |
Користувач бачить чорний екран і діалог «Додаток не відповідає», після чого система завершує процес. У Crashlytics з'являється запис без стеку — тільки ім'я ANR і Activity. Це гірше крэша: без трейсу ви не знаєте причину. Ми налаштовуємо ANR-моніторинг під ключ: підключаємо Firebase Crashlytics або Sentry, читаємо ApplicationExitInfo для точних трейсів та налаштовуємо алерти в Slack. У результаті ви бачите, який код викликав зависання, і усуваєте його до масових скарг. Економія часу на налагодженні — до 50%. Докладніше про ANR можна прочитати в документації Android. Оцінимо ваш проект безкоштовно — напишіть нам.
Звідки беруться ANR
Найчастіше це не один важкий виклик, а ланцюжок. Наприклад, корутина на Dispatchers.Main викликає runBlocking, всередині якого — Room.database.query() без suspend. На слабкому пристрої з зайнятим диском це 5+ секунд блокування.
Друге за частотою джерело — SharedPreferences при холодному старті. На старих версіях Android на бюджетних пристроях перше читання з SharedPreferences блокує main thread до 800 мс, якщо файл не в page cache.
// Антипатерн — читання SharedPreferences на main thread при старті
class SplashActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val token = getSharedPreferences("prefs", MODE_PRIVATE)
.getString("auth_token", null) // блокує main thread
}
}
Правильно: винести в DataStore (корутинний) або читати в lifecycleScope.launch(Dispatchers.IO).
Які інструменти для моніторингу ANR кращі?
Порівняємо три популярні рішення:
| Інструмент |
Метод детекції |
Складність |
Точність трейсів |
| Firebase Crashlytics |
Watchdog + ApplicationExitInfo (API 30+) |
Низька (один рядок) |
Обмежена (не завжди стек) |
| Sentry |
Watchdog з налаштовуваним таймаутом |
Середня (конфігурація) |
Висока (повний стек) |
| Android Vitals |
Агрегація Google Play |
Без SDK |
Дані по ANR Rate, без стеку |
Firebase Crashlytics — найпростіший шлях, якщо він уже підключений. Але для глибокого аналізу використовуйте Sentry або ApplicationExitInfo. Sentry дає на 70% більше інформативних трейсів, ніж Crashlytics. ApplicationExitInfo точніший за watchdog: він зберігає повний thread dump в момент ANR, а не тільки поточний стек.
Як налаштувати Crashlytics ANR
- Додайте залежність у
build.gradle:
implementation("com.google.firebase:firebase-crashlytics:18.+")
- Ініціалізуйте SDK у
Application.onCreate().
- Crashlytics автоматично реєструє ANR через
ApplicationExitInfo на API 30+ або через власний watchdog на старіших версіях.
Як налаштувати Sentry ANR
SentryAndroid.init(this) { options ->
options.dsn = "https://[email protected]/project"
options.isAnrEnabled = true
options.anrTimeoutIntervalMillis = 5000
options.isAnrReportInDebug = false // не спамим у debug
}
Sentry запускає watchdog-потік, який кожні 1000 мс перевіряє, чи живий main thread. Якщо немає відповіді довше anrTimeoutIntervalMillis — знімає стек і відправляє подію.
ApplicationExitInfo — точне джерело трейсів
На Android 10+ система зберігає причину завершення процесу в ApplicationExitInfo. Це в 3 рази точніше за watchdog-потоки:
val activityManager = getSystemService(ActivityManager::class.java)
val exitReasons = activityManager.getHistoricalProcessExitReasons(null, 0, 10)
exitReasons.filter { it.reason == ApplicationExitInfo.REASON_ANR }.forEach { info ->
info.traceInputStream?.use { stream ->
val trace = stream.bufferedReader().readText()
// відправляємо trace у ваш моніторинг
Log.e("ANR", trace)
}
}
traceInputStream містить повний thread dump — ті ж дані, що в /data/anr/traces.txt. Можна прочитати при наступному запуску і відправити в Sentry або Datadog як attachment.
Діагностика через StrictMode
У debug-збірці StrictMode допомагає зловити потенційні ANR до продакшену:
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.penaltyFlashScreen()
.build()
)
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.build()
)
}
penaltyFlashScreen() підсвічує екран червоним при кожному диск-читанні на main thread — розробник бачить проблему негайно.
Налаштування алертів
У Firebase Crashlytics налаштуйте velocity alert на ANR:
- Поріг: > 1% crash-free sessions affected за 1 годину.
- Канал: Slack webhook через Firebase Alert Channels.
У Sentry — через Issue Alerts з умовою event.type:transaction AND event.tags.mechanism:ANR.
Що входить у налаштування ANR-моніторингу
- Підключення ANR-детектора (Firebase Crashlytics або Sentry, або обидва)
- Налаштування читання
ApplicationExitInfo на API 30+ для точних трейсів
- Включення StrictMode у debug-збірці для превентивної діагностики
- Конфігурація velocity alerts з нотифікацією в Slack
- Аналіз Android Vitals baseline для порівняння з конкурентами
- Документація щодо відтворення ANR та рекомендації з усунення
- Підтримка після налаштування (2 тижні — безкоштовно)
Наш досвід: понад 5 років у Android-розробці, понад 50 проектів з моніторингом. Гарантуємо зниження ANR Rate нижче 0.2% після оптимізації.
Як швидко налаштувати ANR-моніторинг?
Базове налаштування з Firebase Crashlytics займає від 4 годин до 1 дня. Якщо потрібен Sentry та аналіз ApplicationExitInfo — 2 дні. Ми надаємо готовий дашборд та алерти. Зв'яжіться з нами — отримайте детальну оцінку вашого проекту.
Строки та вартість
Базове налаштування — від 4 годин до 1 дня. З аналізом ApplicationExitInfo та дашбордом — 2 дні. Вартість розраховується індивідуально залежно від складності проекту та кількості екранів. Інвестиції окупаються за рахунок зниження відтоку користувачів. Отримайте оцінку — напишіть нам.
Аналітика мобільних застосунків: Firebase, Amplitude, AppsFlyer та атрибуція
Наша команда регулярно стикається з проектами, де аналітика вже «налаштована», але реальних інсайтів немає. Типовий приклад — стартап з 50k DAU: трекінг десятків подій без жодної відповіді на питання «чому користувачі не доходять до оплати». За два тижні ми побудували базову воронку і з'ясували, що 70% аудиторії відвалюється на екрані верифікації номера телефону. Після локалізації бага retention зріс на 12%. Висновок: аналітика повинна починатися з конкретних питань, а не з трекінгу всього підряд.
Чому таксономія подій — основа аналітики мобільних застосунків?
Firebase Analytics, Amplitude, Mixpanel — технічно схожі. Різниця в тому, що ви в них кладете. Типова помилка: події screen_view, button_tap_1, button_tap_2 без контексту. Через місяць ніхто не пам'ятає, що таке button_tap_2.
Правильна таксономія: об'єкт + дія + контекст. product_viewed, checkout_started, payment_completed з параметрами product_id, category, price, source. Це дозволяє будувати воронки, когортний аналіз та retention без додаткового трекінгу.
Ми фіксуємо naming convention у tracking plan — документі (Google Sheet або Amplitude Data Catalog), де описано кожну подію, її параметри та умови спрацьовування. Tracking plan синхронізується з командою аналітиків до початку розробки, а не після. Такий підхід гарантує, що через місяць дані залишаться інтерпретованими, а не перетворяться на звалище. Досвід впровадження на 50+ проектах підтверджує: при відсутності tracking plan вартість підтримки аналітики зростає у 2-3 рази за рахунок переробок.
Що обрати для аналітики мобільних застосунків: Firebase, Amplitude чи Mixpanel?
Таблиця нижче показує ключові відмінності трьох популярних платформ. Вибір залежить від бюджету, трафіку та завдань.
| Критерій |
Firebase Analytics |
Amplitude |
Mixpanel |
| Безкоштовний ліміт |
Безліміт (в рамках Spark-плану) |
До 10 млн events/міс |
До 1 тис. MTU/міс (Special) |
| Затримка даних |
До 24 годин (стандарт) |
Хвилини (real-time) |
Хвилини (real-time) |
| Воронки та когорти |
Базові воронки, обмежена кількість |
Глибокі воронки, Journeys, когорти |
Funnels, Retention, Insights |
| BigQuery-експорт |
Так (безкоштовно, сирі дані) |
Так (підписка) |
Так (Enterprise) |
| Session Replay |
Ні |
Є (iOS/Android SDK) |
Ні |
| Інтеграція з рекламою |
Google Ads (нативна) |
Через Universal Links |
Через партнерів |
Firebase Analytics — безкоштовно, глибока інтеграція з Google Ads, BigQuery-експорт для сирих даних. Обмеження: затримка даних до 24 годин, обмежені воронки. Для стартапів з Google Ads трафіком — перший вибір.
Amplitude — продуктова аналітика з акцентом на когорти та шляхи користувача. Journeys (колишній Pathfinder) показує реальні шляхи між подіями — не передбачувані воронки, а фактичні маршрути. Session Replay — запис сесій для UX-аналізу. Безкоштовний тир до 10 млн events/місяць достатній для більшості продуктів на старті.
Mixpanel — ближче до Amplitude, сильніший у сегментації в реальному часі. Insights, Funnels, Retention — базові інструменти, які закривають 90% аналітичних завдань продакта.
Більш формальні визначення цих платформ можна знайти у Wikipedia (Firebase) та Wikipedia (Amplitude).
Як вирішити проблему мультиканальної атрибуції з AppsFlyer?
Знати звідки прийшов користувач — окреме завдання. Firebase Attribution працює лише всередині Google-екосистеми. Для мультиканальної атрибуції (Facebook Ads, TikTok, Apple Search Ads, programmatic) потрібен MMP — Mobile Measurement Partner.
AppsFlyer — лідер ринку. OneLink — universal deep link, який працює на iOS та Android і коректно атрибутує встановлення з будь-якого каналу. Protect360 — вбудований захист від fraud (фейкові встановлення, click injection на Android). Adjust та Branch — конкуренти з подібним функціоналом. Branch сильний у deep linking; Adjust популярний у gaming.
Згідно з Apple, з iOS 14.5 застосунки повинні отримувати дозвіл користувача через ATT перед збором IDFA для відстеження. AppsFlyer використовує probabilistic matching (IP + user agent + timing) для цих користувачів — точність нижча, але краще ніж нічого. SKAdNetwork та Privacy Preserving Attribution надають агреговані дані від Apple із затримкою 24-72 години.
Як налаштувати crash-аналітику, щоб не пропускати баги?
Firebase Crashlytics — стандарт для crash reporting. Автоматично групує креші за стектрейсом, показує affected users %, velocity alerts при зростанні crash rate більш ніж на 10% за годину.
Важливо: символікація. На iOS .dSYM файли повинні автоматично завантажуватися при кожній збірці — через Fastlane upload_symbols_to_crashlytics або Xcode Cloud built-in. Без символів креш у Crashlytics виглядає як набір адрес пам'яті. Це трапляється частіше, ніж здається при переході на новий CI — в одному проекті з аудиторією 500k користувачів ми виявили, що 40% крешів залишалися несимволізованими через пропущений етап у CI/CD. Після автоматизації час реакції на баги скоротився з 3 годин до 15 хвилин.
Для React Native та Flutter — @sentry/react-native та sentry_flutter дають додатковий контекст: breadcrumbs, мережеві запити перед крешем, стан Redux/Provider.
Нижче — порівняння популярних інструментів crash-аналітики для вибору під свої завдання.
| Критерій |
Firebase Crashlytics |
Sentry |
Instabug |
| Безкоштовний ліміт |
Безліміт (в рамках Spark) |
5k events/міс |
250 MAU |
| Групування |
За стектрейсом + параметри |
За fingerprint |
За стектрейсом + метадані |
| Символікація |
Автоматична (через файл) |
Автоматична (через CLI) |
Автоматична |
| Velocity alerts |
Так (за % зміни) |
Так (за кількістю) |
Так (за порогом) |
| Дод. контекст |
Logs, Keys, Custom Keys |
Breadcrumbs, User, Tags |
User steps, мережеві запити |
| Ціна |
Безкоштовно (у Firebase) |
Від $26/міс (Team) |
Від $99/міс |
Налаштування оточення
Три оточення з окремими Firebase проектами: dev, staging, production. Змішувати аналітику з тестових сесій і production — поширена помилка, яка спотворює всі метрики. На iOS через GoogleService-Info.plist для кожної схеми, на Android через google-services.json у папці кожного flavor.
Терміни: базова аналітика з Firebase + Crashlytics — 3-5 днів. Повноцінний tracking plan + Amplitude/Mixpanel з воронками та когортами — 2-3 тижні. Атрибуція через AppsFlyer з deep linking та fraud protection — 1-2 тижні. Вартість розраховується індивідуально залежно від складності інтеграцій.
Що входить у нашу роботу
В рамках впровадження аналітики ми надаємо:
- Розробку та узгодження tracking plan з командами продукту та маркетингу.
- Інтеграцію SDK (Firebase, Amplitude, Mixpanel, AppsFlyer) з урахуванням вашого стеку (Swift/Kotlin/Flutter/React Native).
- Налаштування воронок, когорт, дашбордів та алертів.
- Автоматизацію символікації та завантаження .dSYM через Fastlane.
- Документацію щодо подій та параметрів.
- Навчання команди роботі з аналітичною платформою.
- Два тижні пост-релізної підтримки та коригування трекінгу.
Наш досвід — 7 років впровадження аналітики та понад 80 успішних проектів у сфері мобільної розробки. Ми гарантуємо коректність даних і прозорість кожного етапу.
Зв'яжіться з нами, щоб отримати консультацію з налаштування аналітики вашого застосунку. Замовте аудит поточної аналітики — і ми покажемо, які метрики ви втрачаєте.