Крах на приложението — аварийно прекратяване, при което програмата спира да отговаря и се затваря. В мобилното разработване крашовете са основен източник на отрицателни отзиви и спад на рейтинга. Според данни на Firebase (2024), потребителите изтриват приложението след един-два краша в 53% от случаите. Всяко затваряне намалява задържането с 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, добавя логове, 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 в използваема информация.
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 клас, който гарантира, че грешката ще бъде обработена. No Exception стил: вместо try/catch използвай sealed Result за изрично обработване на успех и грешка.
Feature flags — деактивирай проблемната функционалност от разстояние без пускане на нова версия. Firebase Remote Config позволява промяна на поведението на приложението без публикуване в магазина.
Постепенно пускане — пусни новата версия за 5% от аудиторията и наблюдавай crash rate. Ако rate остане под целевия (обикновено <0,1%), разшири до 25%, след това 50%, след това 100%. Google Play Console и App Store Connect поддържат поетапни пускания за автоматично спиране при надхвърляне на прага.
1: Класификация — определи тежестта: Critical (краш при >1% от потребителите), High (0,1–1%), Medium (<0,1%). За Critical крашове — незабавен отговор. Google Play Console автоматично класифицира крашовете по броя на засегнатите потребители.
2: Анализ на stack trace — отвори лога в Crashlytics, виж точното място на повредата. Провери custom keys: кой екран, какви данни, версия на ОС. Сравни с последното внедряване — често крашът е причинен от скорошна промяна в кода, която е засегнала неочакван сценарий на употреба.
3: Възпроизвеждане — опитай да възпроизведеш краша на устройство или емулатор с подобни параметри. Ако не успееш, провери crash log за модели: конкретни модели (Samsung A10), Android версии (API < 26), locale. Решение — добави защитно условие, което покрива сценария.
4: Поправка и мониторинг — пусни hotfix с приоритет. След пускането се увери, че crash rate за този тип пада до нула. Напиши регресионен тест който покрива сценария на краша. Без тест същата грешка може да се върне при следващото рефакториране.
Често задавани въпроси
Нормален crash rate — по-малко от 0,1% за продукционни издания. Google Play препоръчва поддържане на crash rate под 1,5%, но топ приложенията (YouTube, Instagram) поддържат 0,01–0,05%. За издания на нова функционалност се допуска временно увеличение до 0,5% с последващ спад след hotfix.
Крах — приложението се прекратява аварийно. ANR (Application Not Responding) — приложението замръзва за повече от 5 секунди, но не се затваря принудително. Потребителят вижда диалог „Приложението не отговаря“ и може да изчака или да затвори. ANR проблемите не са по-малко сериозни от крашовете и също влияят на рейтинга в магазина.
Различните устройства имат различни версии на ОС, количество памет, версии на библиотеки и дори процесори. Пример: краш на Android 6 (API 23) поради липса на runtime разрешение може да не се възпроизведе на Android 12.
Добави custom breadcrumbs в Crashlytics: записвай ключови събития преди изпълнение на операцията. Debug symbols (dSYM, ProGuard mapping) — качи ги в Crashlytics, за да видиш реалните имена на функциите, а не обърканите.
В продукция — никога. Необработени крашове влошава потребителското изживяване. Използвай try/catch с логване на грешката. В debug режим крашването е позволено за бърза обратна връзка към разработчика. Assertions — за проверка на инварианти, които никога не трябва да бъдат нарушавани, но само в debug компилации.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също