Crash — idarə olunmayan istisna və ya ölümcül sistem səhvi səbəbindən mobil tətbiqin fövqəladə dayandırılması. Firebase Crashlytics məlumatlarına görə, istifadəçilərin təxminən 2%-i hər gün səhvlərlə qarşılaşır və hər bir səhv retensiyanı 10–20% azaldır. Səbəbləri başa düşmək və səhvlərin qarşısının alınması üsulları mobil tərtibatçı üçün məcburi bacarıqdır.
Əsas məqamlar
Crash — tətbiq kodunda idarə olunmayan istisna və ya ölümcül sistem siqnalı nəticəsində tətbiqin fövqəladə dayandırılmasıdır. Sistem və ya virtual maşın (JVM, ART) ölümcül vəziyyət aşkar etdikdə — NullPointerException, IndexOutOfBoundsException, OutOfMemoryError — dərhal prosesi dayandırır və yaddaşdan boşaldır. İstifadəçi heç bir sistem xəta bildirişi olmadan tətbiqin qəfil bağlandığını görür. Google-a görə, crash-free dərəcəsi 99%-dən aşağı olan tətbiqlər ayda aktiv istifadəçilərin 20%-ə qədərini itirir.
Android səhvlərin idarə edilməsi mexanizmi masaüstü sistemlərdən fərqlənir. Stack trace ilə sazlama dialoqu əvəzinə Android sadəcə prosesi öldürür və ətraflı məlumat saxlamır. Səhv haqqında məlumat toplamaq — proses bitməzdən əvvəl Thread.setDefaultUncaughtExceptionHandler vasitəsilə istisnaları tutan üçüncü tərəf kitabxanalarının (Crashlytics, Sentry, Bugsnag) işidir.
iOS ölümcül səhvləri idarə etmək üçün NSException və Mach exceptions ilə oxşar mexanizmdən istifadə edir. İdarə olunmayan istisna halında sistem tətbiqi bağlayır və hesabat .crash faylı şəklində saxlanılır. iOS-da səhvlərin toplanması Crashlytics ilə inteqrasiya və ya Xcode Organizer vasitəsilə daxili hesabat tələb edir.
Beş kateqoriya səhv mobil tətbiqlərdə bütün səhvlərin 90%-ni əhatə edir. Hər bir növü başa düşmək istehsal mühitində problemləri daha tez diaqnoz etməyə və düzəltməyə kömək edir.
NullPointerException (NPE) — bütün Java/Kotlin tətbiqlərində ən çox yayılmış səhv növüdür. Null olan obyektin metodunu çağırmağa və ya sahəsinə daxil olmağa cəhd etdikdə yaranır. Tipik ssenarilər: ekranı çevirərkən Activity-nin ilkinləşdirilməmiş sahəsi, JSON deserializasiyası zamanı serverdən null cavab, RecyclerView adapteri ilə diqqətsiz naviqasiya.
Kotlin NPE problemini dil səviyyəsində null-təhlükəsiz tiplər vasitəsilə həll edir: String? açıq yoxlama olmadan istifadə edilə bilməz. Bununla belə, Java uyğunluğu və Reflection hələ də risk yaradır. @NonNull və @Nullable annotasiyalarından istifadə edin və statik analiz alətlərində strictNullChecks-i aktivləşdirin.
fun safeLength(text: String?): Int {
return text?.length ?: 0 // null-un təhlükəsiz işlənməsi
}
IndexOutOfBoundsException siyahının və ya massivin mövcud olmayan indeksinə daxil olduqda yaranır. Ümumi ssenari: adapterlə sinxronizasiya olmadan RecyclerView-dən element silmək, bloklamasız ArrayList-in çoxthreadli dəyişdirilməsi, ViewPager-da mövqeyin səhv hesablanması. ConcurrentModificationException — kolleksiyaların eyni vaxtda iterasiyası və dəyişdirilməsi zamanı yaxın qohumdur.
Çoxthreadli giriş üçün CopyOnWriteArrayList və ya java.util.concurrent-dən Lock-free kolleksiyalarından istifadə edin. UI ilə sinxronizasiya üçün DiffUtil tətbiq edin, o, köhnə və yeni siyahı arasındakı fərqi təhlükəsiz və səmərəli hesablayır.
ClassCastException obyekti uyğun olmayan tipə çevirdikdə yaranır. Android-də tipik səbəblər: RecyclerView-da səhv ViewHolder tipi (düzgün getItemViewType olmadan müxtəlif hüceyrə tipləri), naviqasiya zamanı Fragment-in səhv çevrilməsi, müxtəlif sinif versiyaları olan Serializable obyektləri.
Kotlin-in təhlükəsiz çevirmə operatoru as? istifadə edin, tip uyğunsuzluğunda null qaytarır. Java-da — çevirmədən əvvəl instanceof vasitəsilə yoxlayın. Parcelable obyektləri üçün hər sinifdə CREATOR elan etmək məcburidir.
IllegalStateException metodun obyektin uyğun olmayan vəziyyətində çağırıldığını göstərir. Android-də tipik nümunə — onSaveInstanceState-dən sonra getSupportFragmentManager(), fragment-in commit() icazə verilmədikdə. Digər ümumi hal — artıq bağlanmış dialoqda dismiss() çağırmaq.
FragmentManager ilə əməliyyatlardan əvvəl həyat dövrü vəziyyətini yoxlayın. commitAllowingStateLoss() yalnız vəziyyət itkisinin kritik olmadığına əmin olduqda istifadə edin. Kotlin-də tip səviyyəsində yanlış vəziyyətləri istisna edən DSL-ə bənzər qurucular yaradın.
Native Crash yaddaş pozuntusu zamanı C/C++ yerli kodunda baş verir: null göstərici ilə işləmə, double-free, stack buferinin daşması. Android-də belə səhvlər NDK kitabxanalarında, oyun mühərriklərində (Unity, Unreal) və sistem asılılıqlarında olur. Native Crash Thread.setDefaultUncaughtExceptionHandler tərəfindən TUTULMUR — prosesi dərhal öldürür.
Yerli səhvlərin diaqnostikası üçün minidump faylları (Breakpad) və ya Android tombstone fayllarından istifadə edin. Firebase Crashlytics NDK SDK vasitəsilə yerli səhvlərin toplanmasını dəstəkləyir. iOS-da oxşar problem PLCrashReporter vasitəsilə həll olunur.
Üç alət mobil səhv hesabatı bazarında üstünlük təşkil edir. Hər biri stack trace toplanması, tətbiq versiyaları üzrə aqreqasiya və yeni səhvlər haqqında bildirişlər təmin edir.
Crashlytics — Firebase ekosisteminə daxil olan mobil tətbiqlər üçün ən populyar səhv hesabatçısıdır. O, avtomatik olaraq stack trace, cihaz məlumatları, OS versiyası və istifadəçinin xüsusi açarlarını toplayır. İnteqrasiya Firebase Console və Gradle Plugin vasitəsilə 10 dəqiqə çəkir. Crashlytics həmçinin real logları (Logcat) və xüsusi trekinqləri dəstəkləyir.
FirebaseCrashlytics.getInstance()
.setCustomKey("current_screen", "ProfileFragment")
FirebaseCrashlytics.getInstance()
.log("User tapped login button")
Sentry — daha çevik filtrləmə sistemi və 90+ platforma dəstəyi ilə Crashlytics-ə alternativdir. Firebase-dən fərqli olaraq, Sentry məlumatlara ciddi tələbləri olan şirkətlər üçün öz-özünə yerləşdirilən server (self-hosted) təmin edir. Sentry distributiv trekinq, breadcrumbs və CI/CD pipeline-ları ilə inteqrasiyanı dəstəkləyir.
Bugsnag Severity-based alertlərin dəstəyi ilə seçilir: səhvləri kritik, xəta və xəbərdarlığa bölür. Microsoft-dan AppCenter — kiçik layihələr üçün əsas funksionallığı olan pulsuz alətdir. Hər ikisi Android, iOS, React Native və Flutter-i dəstəkləyir.
Analiz — baş vermiş hadisənin tam mənzərəsini bərpa etmə prosesidir. Stack trace yalnız son uğursuzluq nöqtəsini göstərir, lakin problemə səbəb olan konteksti vermir. Peşəkar yanaşma dörd mərhələni əhatə edir.
Birinci mərhələ — stack trace oxumaq. İstisnanın baş verdiyi sinfi, metodu və kod sətrini müəyyən edin. Çağırış zəncirini yuxarı çərçivədən aşağıya izləyin: stekdəki son sətir — səhvin yeri, yuxarı sətirlər isə çağırışların ardıcıllığıdır. Deobfuskasiya (ProGuard/R8 mapping) istehsal qurğuları üçün məcburidir.
İkinci mərhələ — cihaz konteksti. Crashlytics cihaz modelini, OS versiyasını, mövcud yaddaşı və tətbiq versiyasını göstərir. Məsələn, yalnız Samsung Galaxy S10-da Android 11 ilə baş verən səhv konkret One UI versiyası ilə problemi göstərir, ümumi kod səhvini deyil.
Üçüncü mərhələ — test cihazında bərpa. Səhv sabit şəkildə təkrarlanmırsa, istifadəçidən dəqiq addımları soruşun və ya Remote Config-dən istifadə edərək problemli kod bölməsindən əvvəl loqlama aparın. AB-test düzəlişin auditoriyanın bir hissəsində sınaqdan keçirilməsi həlli təsdiqləməyə kömək edir.
Dördüncü mərhələ — düzəlişdən sonra monitorinq. Düzəliş dərc edildikdən sonra səhvin tezliyini 3–5 gün müşahidə edin. Səhv tamamilə yox olarsa — düzəliş işlədi. Tezlik azalıb sıfıra enməyibsə — ayrıca analiz tələb edən ikinci ssenari mövcuddur.
Sistemli yanaşma səhvlərin qarşısının alınması statik analiz alətlərini, sərhəd hallarının məcburi test edilməsini və tətbiqin bütün səviyyələrində səhvlərin düzgün idarə edilməsini əhatə edir.
Detekt (Kotlin) və Lint (Android) kompilyasiya mərhələsində potensial problemləri tapır: istifadə olunmayan dəyişənlər, potensial NPE, API-nin səhv istifadəsi. Bu alətləri CI pipeline-da xəta həddi ilə aktivləşdirin. Məsələn, Detekt 30+ xəbərdarlıq və ya hər hansı error-blocking konfiqurasiyası ilə qurğunu buraxmır.
Əhatə əsas istifadə ssenarilərinin unit-testlərlə test edilməsi reqressiv səhvlərdən əsas qorunmadır. Məlumat modellərini, ViewModel və UseCase qatlarını sərhəd halları ilə test edin: null dəyərlər, boş siyahılar, səhv JSON. Espresso və ya Compose Test vasitəsilə UI-testlər kritik flowları əhatə edir: avtorizasiya, ödəniş, onboarding.
Tətbiqi elə layihələndirin ki, bir moduldakı səhv bütün ekranı çökdürməsin. ViewModel səviyyəsində catch bloklarından istifadə edərək ehtiyat vəziyyəti qaytarın: siyahı əvəzinə placeholder göstərmək, şəbəkə olmadıqda keşlənmiş məlumat, yükləmə xətasında ehtiyat şəkil. Bu, potensial səhvi idarə olunan UX ssenarisinə çevirir.
Staged rollouts — Google Play və App Store-un standart təcrübəsi: yeni versiya əvvəlcə 5%, sonra 20% və nəhayət 100% auditoriyaya 1–3 gün intervallarla yayılır. Hər mərhələdə səhv tezliyi izlənilir: crash-free dərəcəsi 99.5%-dən aşağı düşərsə, buraxılış avtomatik dayandırılır. Firebase Remote Config problemli funksiyaları yeni versiya dərc etmədən söndürməyə imkan verir.
Renovate və ya Dependabot CI-də kitabxanaları məlumat zəiflikləri və kritik səhvlər üçün avtomatik yoxlayır. Bir asılılığın yenilənməsi bütün səhv sinfini aradan qaldıra bilər. Bununla belə, yeniləmələri istehsala buraxmazdan əvvəl staging mühitində test edin — kitabxananın yeni versiyası uyğun olmayan dəyişikliklər ehtiva edə bilər.
Tez-tez verilən suallar
Xeyr. Səhvlərin bir hissəsi tərtibatçının nəzarətindən kənar amillərdən qaynaqlanır: sistem səhvləri, avadanlıq problemləri, proşivka uyğunsuzluğu. Məqsəd tezliyi 0.1% və daha aşağı salmaq, qalan səhvləri isə reaksiya müddətinə görə minimuma endirməkdir.
Səhv hesabatçısı səhv anında stack trace, yaddaş vəziyyəti və cihaz məlumatlarını toplayır. Analitika istifadəçinin davranış məlumatlarını toplayır. Crashlytics hər iki yanaşmanı birləşdirərək səhv kontekstini istifadəçinin xüsusi açarları ilə təmin edir.
ProGuard və R8 əqli mülkiyyəti qorumaq üçün kodu gizlədir. Deobfuskasiya üçün nəşr zamanı Crashlytics-ə mapping faylı yükləyin. Mapping faylı olmadan stack trace həqiqi sinif və metod adları əvəzinə a.a(), b.b() göstərəcək.
Android-də Thread.setDefaultUncaughtExceptionHandler vasitəsilə: kitabxana öz işləyicisini qeydiyyatdan keçirir, o, idarə olunmayan istisnanı ilk alan olur, məlumatları saxlayır və yalnız sonra prosesi bitirir. iOS-da NSException üçün NSSetUncaughtExceptionHandler və siqnallar üçün Mach exception handler istifadə olunur.
Fatal — tətbiq dayandı. Non-fatal (tutulmuş istisna) — tərtibatçı istisnanı try-catch ilə tutdu, lakin bu potensial problemi göstərə bilər. Crashlytics bu tipləri fərqləndirir və paneli zibilləməmək üçün non-fatal-ı ayrıca süzməyə imkan verir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun