Краш приложения — аварийное завершение, при котором программа перестаёт отвечать и закрывается. В мобильной разработке краши — основной источник негативных отзывов и снижения рейтинга. По данным Firebase (2024), пользователи удаляют приложение после одного-двух крашей в 53% случаев. Каждый вылет снижает retention на 3–5%. Системы мониторинга вроде Crashlytics и Sentry помогают быстро находить и исправлять причины падений до массового воздействия на пользователей.
Главное
Краш — неожиданное завершение программы, вызванное исключительной ситуацией, которую код не обработал. В мобильных ОС краш приводит к немедленному закрытию приложения и показу экрана «Приложение остановлено» или возврату на домашний экран.
Краши делятся на два больших класса. Обработанные ошибки — try/catch блоки перехватывают исключение, приложение продолжает работать, возможно с потерей функциональности. Необработанные краши — исключение всплывает до уровня ОС, и система убивает процесс. Второй тип особенно опасен, так как пользователь не может сохранить данные.
Система с двумя миллионами пользователей и 0.1% crash rate теряет 2 000 пользователей на каждом релизе. По данным Google Play Console (2024), приложения с crash rate выше 1.5% исключаются из рекомендаций и теряют до 30% органического трафика.
NullPointerException (NPE) — король крашей в Java/Kotlin. Попытка вызвать метод на null-объекте. В Kotlin NPE встречается реже благодаря null safety, но всё ещё возможен при использовании !! оператора или взаимодействии с Java-кодом. Google (2024) оценивает: NPE составляют 25% всех крашей Android-приложений.
IndexOutOfBoundsException — обращение к элементу списка по несуществующему индексу. Частая причина: данные пришли с сервера в неожиданном формате, а UI пытается отобразить позицию, которой нет. Решение — всегда проверяй размер коллекции перед доступом по индексу.
ANR (Application Not Responding) — Android-специфичная проблема. UI-поток блокируется более чем на 5 секунд. Основные причины: сетевые запросы на главном потоке, тяжёлые вычисления, синхронизация с базой данных. StrictMode в Android помогает выявить блокировки UI-потока на этапе разработки.
OutOfMemoryError (OOM) — приложение превысило лимит памяти. В мобильных устройствах с 2–4 GB RAM OOM — частая проблема при работе с большими изображениями или бесконечными списками без пагинации. Решение — Glide/Coil для загрузки изображений, LruCache для кеширования, ViewHolder в RecyclerView.
Runtime exceptions — ошибки, которые компилятор не проверяет на этапе сборки. Они проявляются только при выполнении кода на конкретном устройстве с конкретными данными. В Java это RuntimeException и его подклассы: NullPointerException, IllegalArgumentException, ArithmeticException.
Фатальные ошибки (FATAL) — не runtime, а системные сбои. Signal 11 (SIGSEGV) — нарушение сегментации памяти в native-коде. Signal 6 (SIGABRT) — аварийное завершение, вызванное самим приложением через abort(). Такие краши тяжело диагностировать, так как stack trace часто не показывает понятный контекст.
В iOS основные причины — NSInvalidArgumentException (неожиданный nil в параметре) и EXC_BAD_ACCESS (доступ к освобождённой памяти). Swift уменьшил количество крашей по сравнению с Objective-C, но ошибки в ObjC runtime и C-библиотеках всё ещё приводят к падениям.
Firebase Crashlytics — стандарт для мобильных приложений. Автоматически собирает stack trace, добавляет логи, user ID и метаданные устройства. Группирует краши по сигнатуре (класс ошибки + строка). Real-time alerts — уведомления, когда crash rate превышает заданный порог (например, >0.1% за час).
Sentry — альтернатива с более гибкими возможностями. Позволяет создавать custom contexts, добавлять breadcrumbs (предшествующие события), настраивать in-app filtering для исключения неважных ошибок. Source maps для Kotlin и Swift позволяют видеть исходный код, а не обфусцированные имена.
Best practices для логов: отправляй ключевые метаданные перед выполнением опасной операции — так в логе будет видно, что делал пользователь перед крашем. Добавляй custom keys (номер версии API, последний экран, размер входных данных). Это превращает бесполезный stack trace в actionable информацию.
class PaymentViewModel : ViewModel() {
fun processPayment(amount: Double) {
crashlytics.setCustomKey("last_screen", "payment")
crashlytics.setCustomKey("amount", amount)
try {
api.charge(amount)
} catch (e: Exception) {
crashlytics.recordException(e)
}
}
}
Optional binding и null safety — в Kotlin используй `?` для nullable-типов, `let` и `?:` для безопасной обработки null. В Swift — optionals и guard let. Modern Kotlin (2024) добавил Contract-аннотации: `@ContractsDsl` позволяет объявить, что функция не возвращает null, и компилятор это проверяет.
Error handling в сети — каждый сетевой запрос должен обрабатывать timeout, ошибки парсинга и отказ сервера. Retrofit с Result-типом — sealed class, который гарантирует, что ошибка будет обработана. No Exception-стиль: вместо try/catch используй sealed Result для явной обработки успеха и ошибки.
Feature flags — отключай проблемный функционал удалённо без релиза новой версии. Если серверная операция вызывает краш на старых устройствах — флаг отключает её для этой группы. Firebase Remote Config позволяет менять поведение приложения без публикации в магазине.
Постепенный rollout — выпускай новую версию на 5% аудитории и мониторь crash rate. Если rate остаётся ниже целевого (обычно <0.1%), расширяй до 25%, затем 50%, затем 100%. Google Play Console и App Store Connect поддерживают staged rollouts для автоматической остановки при превышении порога.
Шаг 1: Классификация — определи severity: Critical (краш у >1% пользователей), High (0.1–1%), Medium (<0.1%). Для Critical крашей — immediate response. Для остальных — стандартный процесс багфикса в текущем спринте. Google Play Console автоматически классифицирует краши по количеству затронутых пользователей.
Шаг 2: Анализ stack trace — открой лог в Crashlytics, посмотри точное место падения. Проверь custom keys: какой экран, какие данные, версия ОС. Сопоставь с последним деплоем — часто краш вызван свежим изменением в коде, который затронул неожиданный сценарий использования.
Шаг 3: Воспроизведение — попробуй воспроизвести краш на устройстве или эмуляторе с аналогичными параметрами. Если не получается — проверь crash log на паттерны: конкретные модели (Samsung A10), версии Android (API < 26), локали. Решение — добавь защитное условие, которое покрывает сценарий.
Шаг 4: Фикс и мониторинг — выпусти hotfix с приоритетом. После релиза убедись, что crash rate по этому типу падает до нуля. Напиши regression-тест, который покрывает сценарий краша. Без теста тот же баг может вернуться в следующем рефакторинге.
Часто задаваемые вопросы
Нормальный crash rate — менее 0.1% для production-релизов. Google Play рекомендует держать crash rate ниже 1.5%, но топовые приложения (YouTube, Instagram) держат 0.01–0.05%. Для релизов новой функциональности допускается временный рост до 0.5% с последующим снижением после хотфикса.
Краш — приложение аварийно завершается. ANR (Application Not Responding) — приложение зависает более чем на 5 секунд, но не закрывается принудительно. Пользователь видит диалог «Приложение не отвечает» и может дождаться или закрыть. ANR-проблемы не менее серьёзны, чем краши, и тоже влияют на рейтинг в магазине.
Разные устройства имеют разные версии ОС, объём памяти, версии библиотек и даже процессоры. Пример: краш на Android 6 (API 23) из-за отсутствия runtime permission может не воспроизводиться на Android 12. Анализируй crash log по фильтрам: OS version, device model, amount of RAM. Это укажет на специфику проблемы.
Добавь custom breadcrumbs в Crashlytics: записывай ключевые события перед выполнением операции. Если краш возникает на 3-м шаге онбординга — это указывает на проблему в конкретном экране. Debug symbols (dSYM, ProGuard mapping) — обязательно загружай в Crashlytics, чтобы видеть реальные имена функций, а не обфусцированные.
В production — никогда. Необработанный краш ухудшает пользовательский опыт. Используй try/catch с логированием ошибки. В debug-режиме допустимо крашить для быстрой обратной связи разработчику. Assertions — для проверки инвариантов, которые никогда не должны нарушаться, но только в debug-сборках.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также