Crash, işlenmeyen bir istisna veya ölümcül sistem hatası nedeniyle bir mobil uygulamanın anormal şekilde sonlanmasıdır. Firebase Crashlytics'e göre, kullanıcıların yaklaşık %2'si günlük olarak çökmelerle karşılaşır ve her çökme, kullanıcı tutma oranını %10–20 oranında azaltır. Çökmelerin nedenlerini ve önleme yöntemlerini anlamak, her mobil geliştirici için temel bir beceridir.
Anahtar Noktalar
Crash, uygulama kodunda işlenmeyen bir istisna veya ölümcül bir sistem sinyali nedeniyle oluşan bir uygulamanın anormal şekilde sonlanmasıdır. Sistem veya sanal makine (JVM, ART) ölümcül bir durum tespit ettiğinde — NullPointerException, IndexOutOfBoundsException, OutOfMemoryError — süreci hemen durdurur ve bellekten boşaltır. Kullanıcı, herhangi bir sistem hata bildirimi olmadan uygulamanın aniden kapandığını görür. Google'a göre, çökmesiz oranı %99'un altında olan uygulamalar, aylık aktif kullanıcılarının %20'sine kadarını kaybeder.
Android'de çökme işleme mekanizması masaüstü sistemlerden farklıdır. Yığın izi içeren bir hata ayıklama iletişim kutusu yerine, Android ayrıntılı bilgiyi kaydetmeden süreci öldürür. Çökme bilgisi toplamak, süreç sonlandırılmadan önce Thread.setDefaultUncaughtExceptionHandler aracılığıyla istisnaları yakalayan üçüncü taraf kitaplıkların (Crashlytics, Sentry, Bugsnag) işidir.
iOS, ölümcül hataları işlemek için NSException ve Mach istisnaları ile benzer bir mekanizma kullanır. İşlenmeyen bir istisna oluştuğunda, sistem uygulamayı sonlandırır ve rapor .crash dosyası olarak kaydedilir. iOS'ta çökme toplamak, Crashlytics ile entegrasyon veya Xcode Organizer aracılığıyla yerleşik rapor gerektirir.
Beş kategori çökme, mobil uygulamalardaki tüm hataların %90'ını kapsar. Her türü anlamak, üretimdeki sorunları daha hızlı teşhis etmeye ve düzeltmeye yardımcı olur.
NullPointerException (NPE), tüm Java/Kotlin uygulamalarında en yaygın çökme türüdür. Null olan bir nesnenin metodunu çağırmaya veya alanına erişmeye çalıştığınızda oluşur. Tipik senaryolar: ekran döndürme sırasında başlatılmamış Activity alanı, JSON seri durumdan çıkarma sırasında sunucudan null yanıtı, RecyclerView bağdaştırıcısında dikkatsiz gezinme.
Kotlin, null güvenli türler aracılığıyla NPE sorununu dil düzeyinde çözer: String? açık kontrol olmadan kullanılamaz. Ancak, Java uyumluluğu ve Yansıma hala riskler oluşturur. @NonNull ve @Nullable ek açıklamalarını kullanın ve statik analiz araçlarında strictNullChecks'i etkinleştirin.
fun safeLength(text: String?): Int {
return text?.length ?: 0 // null'un güvenli işlenmesi
}
IndexOutOfBoundsException, bir listenin veya dizinin var olmayan bir dizinine erişirken oluşur. Yaygın senaryolar: bağdaştırıcıyla senkronize etmeden RecyclerView'dan öğe kaldırma, kilitleme olmadan ArrayList'in çoklu iş parçacıklı değişikliği, ViewPager'da yanlış konum hesaplaması. ConcurrentModificationException, koleksiyonları aynı anda yineleme ve değiştirme sırasında yakın bir akrabadır.
Çoklu iş parçacığı erişimi için CopyOnWriteArrayList veya java.util.concurrent'den kilitsiz koleksiyonlar kullanın. UI senkronizasyonu için, eski ve yeni listeler arasındaki farkı güvenli ve verimli bir şekilde hesaplayan DiffUtil kullanın.
ClassCastException, bir nesne uyumsuz bir türe dönüştürüldüğünde oluşur. Android'de tipik nedenler: RecyclerView'da yanlış ViewHolder türü (uygun getItemViewType olmadan farklı hücre türleri), gezinme sırasında yanlış Fragment dönüştürme, farklı sınıf sürümlerine sahip Serializable nesneleri.
as? operatörü aracılığıyla Kotlin'in güvenli dönüşümünü kullanın, tür uyumsuzluğu durumunda null döndürür. Java'da — dönüştürmeden önce instanceof ile kontrol edin. Parcelable nesneleri için her sınıfta CREATOR bildirmelisiniz.
IllegalStateException, bir nesnenin uygun olmayan durumunda bir metodun çağrıldığını belirtir. Android'de tipik bir örnek — onSaveInstanceState'dan sonra getSupportFragmentManager(), bir fragment'in commit()'ine izin verilmediğinde. Başka bir yaygın durum — zaten kapatılmış bir iletişim kutusunda dismiss() çağırmak.
FragmentManager işlemlerinden önce yaşam döngüsü durumunu kontrol edin. commitAllowingStateLoss()'u yalnızca durum kaybının kritik olmadığından emin olduğunuzda kullanın. Kotlin'de, tür düzeyinde geçersiz durumları ortadan kaldıran DSL benzeri oluşturucular oluşturun.
Native Crash, bellek ihlalleri nedeniyle yerel C/C++ kodunda oluşur: null işaretçi başvurusu, çift serbest bırakma, yığın arabellek taşması. Android'de bu tür çökmeler NDK kitaplıklarında, oyun motorlarında (Unity, Unreal) ve sistem bağımlılıklarında meydana gelir. Native Crash, Thread.setDefaultUncaughtExceptionHandler tarafından YAKALANMAZ — süreci anında öldürür.
Yerel çökmeleri teşhis etmek için minidump dosyaları (Breakpad) veya Android tombstones kullanın. Firebase Crashlytics, NDK SDK aracılığıyla yerel çökme toplamayı destekler. iOS'ta benzer bir sorun PLCrashReporter kullanılarak çözülür.
Üç araç mobil çökme raporlama pazarına hakimdir. Her biri yığın izi toplama, uygulama sürümüne göre toplama ve yeni çökmeler hakkında bildirimler sağlar.
Crashlytics, Firebase ekosisteminin bir parçası olan mobil uygulamalar için en popüler çökme raporlayıcısıdır. Otomatik olarak yığın izlerini, cihaz bilgilerini, işletim sistemi sürümünü ve kullanıcının özel anahtarlarını toplar. Entegrasyon, Firebase Console ve Gradle Plugin aracılığıyla 10 dakika sürer. Crashlytics ayrıca gerçek zamanlı günlükleri (Logcat) ve kullanıcı izlemelerini destekler.
FirebaseCrashlytics.getInstance()
.setCustomKey("current_screen", "ProfileFragment")
FirebaseCrashlytics.getInstance()
.log("User tapped login button")
Sentry, daha esnek bir filtreleme sistemi ve 90'dan fazla platform desteği ile Crashlytics'e bir alternatiftir. Firebase'in aksine Sentry, katı veri gereksinimleri olan şirketler için kendi kendine barındırılan (self-hosted) bir sunucu sağlar. Sentry, dağıtık izleme, breadcrumbs ve CI/CD hattı entegrasyonunu destekler.
Bugsnag, şiddet tabanlı uyarıları desteklemesiyle öne çıkar: çökmeleri critical, error ve warning olarak sınıflandırır. Microsoft'un AppCenter'ı, küçük projeler için temel işlevselliğe sahip ücretsiz bir araçtır. Her ikisi de Android, iOS, React Native ve Flutter'ı destekler.
Çökme analizi, olanların tam resmini yeniden oluşturma sürecidir. Yığın izi yalnızca son hata noktasını gösterir ancak soruna yol açan bağlamı sağlamaz. Profesyonel bir yaklaşım dört aşama içerir.
Birinci aşama — yığın izini okumak. İstisnanın oluştuğu sınıfı, metodu ve kod satırını belirleyin. Çağrı zincirini üst çerçeveden alt çerçeveye doğru izleyin: yığındaki son satır çökme konumudur ve üst satırlar çağrı sırasıdır. Üretim yapıları için karartma çözme (ProGuard/R8 eşlemesi) zorunludur.
İkinci aşama — cihaz bağlamı. Crashlytics cihaz modelini, işletim sistemi sürümünü, kullanılabilir belleği ve uygulama sürümünü gösterir. Örneğin, yalnızca Android 11 ile Samsung Galaxy S10'da oluşan bir çökme, genel bir kod hatası değil, belirli bir One UI sürümüyle ilgili bir soruna işaret eder.
Üçüncü aşama — test cihazında yeniden üretme. Çökme tutarlı bir şekilde yeniden üretilmiyorsa, kullanıcıya tam adımları sorun veya sorunlu kod bölümünden önce günlük kaydı için Remote Config kullanın. Düzeltmenin hedef kitlenin bir kısmında AB testi yapılması, çözümü onaylamaya yardımcı olur.
Dördüncü aşama — düzeltme sonrası izleme. Düzeltmeyi yayınladıktan sonra, çökme oranını 3–5 gün boyunca izleyin. Çökme tamamen kaybolursa — düzeltme işe yaramıştır. Sıklık azaldıysa ancak sıfıra inmediyse — ayrı analiz gerektiren ikinci bir senaryo vardır.
Sistematik bir yaklaşım ile çökme önleme, statik analiz araçlarını, zorunlu sınır durum testlerini ve uygulamanın tüm seviyelerinde uygun hata yönetimini içerir.
Detekt (Kotlin) ve Lint (Android), derleme zamanında potansiyel sorunları bulur: kullanılmayan değişkenler, potansiyel NPE'ler, yanlış API kullanımı. Bu araçları bir hata eşiğiyle CI hattına ekleyin. Örneğin, 30+ uyarı veya herhangi bir hata engelleme yapılandırmasına sahip Detekt, derlemeyi geçirmez.
Birim testleriyle temel kullanım senaryolarının kapsanması, gerileme çökmelerine karşı temel korumadır. Sınır durumlarıyla (null değerler, boş listeler, geçersiz JSON) veri modellerini, ViewModel ve UseCase katmanlarını test edin. Espresso veya Compose Test aracılığıyla UI testleri, kritik akışları kapsar: kimlik doğrulama, ödeme, onboarding.
Uygulamayı bir modüldeki hatanın tüm ekranı çökertmeyeceği şekilde tasarlayın. Yedek durumla ViewModel düzeyinde catch blokları kullanın: liste yerine yer tutucu gösterme, çevrimdışıyken önbelleğe alınmış veri, yükleme hatasında yedek görüntü. Bu, potansiyel bir çökmeyi kontrollü bir UX senaryosuna dönüştürür.
Aşamalı kullanıma sunma, Google Play ve App Store'da standart bir uygulamadır: yeni bir sürüm, 1–3 gün arayla %5, ardından %20 ve ardından %100 kitleye dağıtılır. Her aşamada çökme oranı izlenir: çökmesiz oran %99,5'in altına düşerse, kullanıma sunma otomatik olarak durur. Firebase Remote Config, yeni bir sürüm yayınlamadan sorunlu özellikleri devre dışı bırakmaya olanak tanır.
CI'daki Renovate veya Dependabot, kitaplıkları bilinen güvenlik açıkları ve kritik hatalar için otomatik olarak kontrol eder. Tek bir bağımlılığı güncellemek, tüm bir çökme sınıfını ortadan kaldırabilir. Ancak, üretime sunmadan önce güncellemeleri hazırlık ortamında test edin — yeni bir kitaplık sürümü uyumsuz değişiklikler içerebilir.
Sıkça Sorulan Sorular
Hayır. Bazı çökmeler geliştiricinin kontrolü dışındaki faktörlerden kaynaklanır: sistem hataları, donanım sorunları, ürün yazılımı uyumsuzluğu. Hedef, oranı %0,1 veya altına düşürmek ve kalan çökmeler için yanıt süresini en aza indirmektir.
Çökme raporlayıcısı, çökme anında yığın izi, bellek durumu ve cihaz bilgilerini toplar. Analitik, kullanıcı davranış verilerini toplar. Crashlytics her iki yaklaşımı birleştirir, kullanıcının özel anahtarlarıyla birlikte çökme bağlamı sağlar.
ProGuard ve R8, fikri mülkiyeti korumak için kodu karartır. Karartmayı çözmek için, yayınlama sırasında eşleme dosyasını Crashlytics'e yükleyin. Eşleme dosyası olmadan, yığın izi gerçek sınıf ve metot adları yerine a.a(), b.b() gösterecektir.
Android'de Thread.setDefaultUncaughtExceptionHandler aracılığıyla: kitaplık kendi işleyicisini kaydeder, işlenmeyen istisnayı ilk alan odur, verileri kaydeder ve ancak o zaman süreci sonlandırır. iOS'ta NSException için NSSetUncaughtExceptionHandler ve sinyaller için Mach exception handler kullanılır.
Fatal — uygulama sonlandı. Non-fatal (yakalanan istisna) — geliştirici istisnayı try-catch ile yakaladı, ancak potansiyel bir soruna işaret edebilir. Crashlytics bu türleri ayırt eder ve kontrol panelini karıştırmamak için non-fatal'ları ayrı ayrı filtrelemeye olanak tanır.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun