Global Exception Handler — idarə olunmamış istisnaların mərkəzləşdirilmiş şəkildə tutulması mexanizmi, mobil tətbiqin qəzaya uğramasının qarşısını alır. Apple Developer, 2024 məlumatlarına görə, istisnaların düzgün idarə edilməsi crash hallarının sayını 40–60% azaldır və istifadəçi təcrübəsini yaxşılaşdırır. Belə bir handler olmadan, fon thread-də hər hansı bir idarə olunmamış istisna dərhal tətbiqin bağlanmasına səbəb olur.
Əsas məqamlar
Global Exception Handler — tətbiqin ayrı-ayrı funksiyaları və ya modulları səviyyəsində idarə olunmamış istisnaların tutulması üçün mərkəzləşdirilmiş mexanizmdir. Mobil inkişaf kontekstində belə bir handler prosesin qəzaya uğramasından əvvəl son müdafiə xətti rolunu oynayır.
iOS və Android qlobal handler qurmaq üçün daxili API-lər təqdim edir. Apple Objective-C mühiti üçün NSSetUncaughtExceptionHandler istifadə edir, Google isə Java/Kotlin-də Thread.setDefaultUncaughtExceptionHandler təklif edir. Hər iki mexanizm tətbiqin bütün thread-lərində try-catch konstruksiyaları tərəfindən tutulmamış istisnaları yaxalayır.
Crashlytics (Google, 2024) məlumatlarına görə, crash-ların təxminən 25%-i fon thread-lərində idarə olunmamış istisnalar səbəbindən baş verir — bu, Global Exception Handler-in xüsusilə kritik olduğu sahədir. Tərtibatçılar tez-tez UI thread-inə diqqət yetirir, asinxron əməliyyatları unudurlar.
Qlobal handler-in istifadəsi yerli xəta idarəetməsini əvəz etmir, onu tamamlayır. Əsas vəzifə — istisna anında tətbiqin vəziyyəti haqqında maksimum məlumatı saxlamaq və işi düzgün şəkildə başa çatdırmaqdır.
İş mexanizmi — Global Exception Handler əməliyyat sistemi siqnallarının və ya icra zamanı istisnalarının tutulmasına əsaslanır. Kod heç bir try-catch bloku tərəfindən tutulmayan bir istisna atdıqda, idarəetmə əvvəlcədən qurulmuş handler-ə ötürülür.
iOS platformasında handler NSSetUncaughtExceptionHandler vasitəsilə qeydiyyatdan keçir və tam stack trace ilə NSException obyektini alır. Android-də Thread.setDefaultUncaughtExceptionHandler istifadə olunur, bu da Thread və Throwable qəbul edir — bu, istisna növünə, mesaja və çağırış stack-inə giriş imkanı verir.
Crash məlumatı alındıqdan sonra handler üç məcburi hərəkəti yerinə yetirir: lokal yaddaşda log yazmaq, Crashlytics və ya Sentry-ə hesabat göndərmək və tətbiqi düzgün şəkildə başa çatdırmaq. Apple WWDC 2023 məlumatlarına görə, handler-in işləmə müddəti 5 saniyə ilə məhdudlaşdırılıb — bundan sonra sistem prosesi məcburi şəkildə sonlandırır.
iOS 13-dən etibarən Swift tətbiqləri üçün Signals API meydana çıxdı, bu, təkcə istisnaları deyil, həm də əməliyyat sistemi siqnallarını — SIGABRT, SIGSEGV və SIGBUS-u emal edir, handler-in əhatə dairəsini aşağı səviyyəli yaddaş səhvlərinə qədər genişləndirir.
Tətbiq — iOS-da qlobal handler qurmaq üçün NSSetUncaughtExceptionHandler vasitəsilə C funksiyası təyin edilməlidir. Handler idarə olunmamış istisna anında sinxron şəkildə çağırılır və tam xəta kontekstini alır.
void handleUncaughtException(NSException exception) {
NSDictionary userInfo = [exception userInfo];
NSArray stackTrace = [exception callStackSymbols];
NSString reason = [exception reason];
// Crash log-u lokal fayla saxlayırıq
NSString logPath = [NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
[exceptionLog writeToFile:logPath atomically:YES];
}
int main(int argc, char argv[]) {
NSSetUncaughtExceptionHandler(&handleUncaughtException);
return UIApplicationMain(argc, argv, nil, nil);
}
iOS tətbiqinin vacib xüsusiyyəti: handler yalnız Objective-C istisnalarını tutur. Throw-catch mexanizmindən istifadə edən Swift səhvləri bu handler-ə düşmür — onlar üçün Swift Error Handling vasitəsilə ayrıca emal tələb olunur. iOS 14-dən etibarən Apple maksimum əhatə üçün NSSetUncaughtExceptionHandler ilə Signals API-nin birləşdirilməsini tövsiyə edir.
Apple Technical Note TN2151-ə görə, handler çağırıldıqdan sonra tətbiq 5 saniyə ərzində başa çatmalıdır. Handler-dən qayıtdıqdan sonra icranı davam etdirmək cəhdi qeyri-müəyyən davranışa və təkrar crash-a səbəb olur.
Android Thread.setDefaultUncaughtExceptionHandler vasitəsilə daha çevik qlobal istisna emal mexanizmi təqdim edir. Handler istisnanın baş verdiyi thread-ə istinadı və Throwable obyektini alır.
class GlobalExceptionHandler : Thread.UncaughtExceptionHandler {
override fun uncaughtException(thread: Thread, throwable: Throwable) {
// Crash log-u fayla saxlayırıq
val stackTrace = throwable.stackTraceToString()
val crashLog = "CRASH: ${thread.name}\n${stackTrace}"
val file = File(context.cacheDir, "crash_log.txt")
file.writeText(crashLog)
// Crashlytics-ə göndəririk
FirebaseCrashlytics.getInstance()
.recordException(throwable)
// Prosesi başa çatdırırıq
android.os.Process.killProcess(
android.os.Process.myPid()
)
}
}
// Application.onCreate-də quraşdırma
class App : Application() {
override fun onCreate() {
super.onCreate()
Thread.setDefaultUncaughtExceptionHandler(
GlobalExceptionHandler()
)
}
}
Android tətbiqinin əsas fərqi: hər bir thread-in öz handler-i var və setDefaultUncaughtExceptionHandler fərdi handler təyin edilməmiş bütün thread-lər üçün handler qurur. Bu, qlobal əhatəni təmin edir — UI thread-dən tutmuş fon AsyncTask və korutinlərə qədər.
Android 12+-də məhdudiyyət yarandı: uncaughtException çağırıldıqdan sonra tətbiq 100 millisaniyə ərzində başa çatmalıdır. Handler uzunmüddətli əməliyyatlar yerinə yetirirsə, sistem log yazılması bitməzdən əvvəl prosesi öldürə bilər. Crash hesabatı göndərmək üçün fon xidməti istifadə etmək tövsiyə olunur.
Birinci qayda — idarə olunmamış istisnadan sonra tətbiqi bərpa etməyə çalışmayın. Crash-dan sonra tətbiqin vəziyyəti qeyri-müəyyəndir və işi davam etdirmək istifadəçi məlumatlarının zədələnməsinə səbəb ola bilər.
Vaxt məhdudiyyəti — Global Exception Handler-in əsas texniki məhdudiyyətidir. iOS-da bu 5 saniyə, Android-də — 100 millisaniyədir. Handler daxilində yalnız minimal məlumat dəstini saxlamaq icazəlidir: istisna növü, çağırış stack-i və bir neçə əsas dəyişənin vəziyyəti.
Şəbəkə sorğularının göndərilməsi, verilənlər bazasına yazma və mürəkkəb serializasiya təxirə salınmış mexanizmə köçürülməlidir — məsələn, log-u fayla yazmaq və növbəti tətbiq açılışında göndərmək.
Crash-reporting xidmətləri — Firebase Crashlytics, Sentry, Bugsnag — özləri qlobal handler qururlar. Əgər tərtibatçı öz handlerini onların üzərində qurursa, öz hərəkətlərindən sonra idarəetməni crash-reporting sisteminə ötürməlidir. Android-də handler kompozisiyası istifadə olunur: öz məntiqi icra edilir, sonra əvvəlki handler çağırılır.
Firebase Crashlytics üçün ümumiyyətlə öz Thread.setDefaultUncaughtExceptionHandler qurmaq tövsiyə edilmir — Crashlytics SDK bunu avtomatik olaraq inizializasiya zamanı edir.
İstifadəçi konteksti — standart çağırış stack-indən əlavə, tətbiq versiyasını, OS versiyasını, boş yaddaşın miqdarını və crash-a qədər işləmə müddətini loglamaq faydalıdır. Bu məlumatlar problemin təkrar istehsalı və həlli üçün kritik əhəmiyyət daşıyır.
iOS-da NSSetUncaughtExceptionHandler təkcə yazmaq üçün deyil, həm də məlumatları NSUserDefaults-da synchronize bayrağı ilə müvəqqəti saxlamaq üçün istifadə edilə bilər — bu, proses dərhal sonlansa belə məlumatların qorunmasını təmin edir.
Məcburi test — Global Exception Handler CI/CD-nin hər mərhələsində test edilməlidir. iOS-da test istisnası @throw NSException vasitəsilə, Android-də isə throw RuntimeException() vasitəsilə başladıla bilər. Handler-in çağırıldığı, log-un saxlandığı və tətbiqin düzgün şəkildə başa çatdığı yoxlanılır.
Google I/O 2023 məlumatlarına görə, istehsalda crash-ların 30%-dən çoxu tərtibatçının test etmədiyi cihazlarda baş verir — müxtəlif Android versiyaları, xüsusi proqram təminatı, məhdud yaddaş.
Birinci və ən geniş yayılmış səhv — istisna emal edildikdən sonra tətbiqin işini davam etdirmək cəhdi. uncaughtException çağırıldıqdan sonra tətbiq qeyri-sabit vəziyyətdədir və hər hansı sonrakı əməliyyat kaskad səhvlərə və məlumat zədələnməsinə səbəb ola bilər.
İkinci səhv — handler daxilində uzunmüddətli əməliyyatların yerinə yetirilməsi. Şəbəkə sorğuları, böyük faylların yazılması və ya mürəkkəb hesablamalar prosesin məcburi sonlandırılmasından əvvəl bitməyə vaxt tapmır. Apple Technical Q&A QA1468-ə görə, handler daxilində HTTP sorğusu göndərmək cəhdi itirilmiş crash hesabatlarının aparıcı səbəbidir.
Üçüncü səhv — fon thread-lərinin nəzərə alınmaması. Yalnız əsas thread üçün qurulmuş Global Exception Handler korutinlərdə, DispatchQueue, AsyncTask və ya RxJava-da crash-lardan qorumur. Android-də hər bir thread-in öz handler-i olmalıdır — setDefaultUncaughtExceptionHandler bu problemi yalnız fərdi handler-i olmayan thread-lər üçün həll edir.
Dördüncü səhv — OS siqnalları üçün fallback-in olmaması. iOS-da NSSetUncaughtExceptionHandler SIGABRT, SIGSEGV və SIGBUS-u tutmur. Bu siqnallar üçün sigaction API vasitəsilə ayrıca handler-lərin qurulması tələb olunur. Tərtibatçılar bu barədə yalnız tətbiq heç bir crash hesabatı olmadan çökdükdə öyrənirlər.
Beşinci səhv — məxfi məlumatların loglanması. Crash log-a e-poçtlar, avtorizasiya tokenləri və ya istifadəçilərin şəxsi məlumatları düşür. Bu, GDPR və Apple App Store Review Guidelines-ni pozur. Ötürülən məlumatları həmişə regex və ya icazə verilən sahələrin whitelist siyahısı vasitəsilə filtrləyin.
Tez-tez verilən suallar
Xeyr — Global Exception Handler çağırıldıqdan sonra tətbiqin vəziyyəti qeyri-müəyyəndir. İşi davam etdirmək cəhdi məlumatların zədələnməsinə səbəb ola bilər. Yeganə düzgün hərəkət — crash logunu saxlamaq və prosesi başa çatdırmaqdır.
Hamısını yox — iOS-da NSSetUncaughtExceptionHandler yalnız Objective-C istisnalarını tutur. Swift səhvləri və OS siqnalları (SIGSEGV, SIGABRT) ayrıca handler-lər tələb edir. Android-də Thread.setDefaultUncaughtExceptionHandler bütün RuntimeException-ları tutur, lakin JNI vasitəsilə native kod səhvlərini tutmur.
Öz handler-inizi qurmazdan əvvəl Thread.getDefaultUncaughtExceptionHandler() vasitəsilə əvvəlki handler-ə istinadı saxlayın. Öz handler-inizin sonunda previousHandler.uncaughtException(thread, throwable) çağırın — bu, Crashlytics və ya Sentry-nin məlumatlarını almasını təmin edir.
Native kod üçün sigaction() vasitəsilə siqnalların emalı tələb olunur — SIGSEGV, SIGABRT, SIGBUS. Android-də Google Breakpad və ya Crashpad istifadə edilə bilər. iOS 13-dən etibarən mach-istisnalarının emalı üçün Signals API mövcuddur.
Xeyr — handler-in qurulması yalnız istisna anında təsir edir. Normal tətbiq işində overhead yoxdur. Yeganə risk — handler Activity və ya Context-ə istinad saxlayırsa, onların zibil yığıcı tərəfindən təmizlənməsinin qarşısını alaraq yaddaş sızmasıdır.
Xülasə
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