Global Exception Handler: esența, principiul de funcționare și implementarea în proiecte

Autor: IT Sectr Publicat: 2026-05-27 Timp de citire: 8 min

Global Exception Handler — un mecanism centralizat de interceptare a excepțiilor neprocesate, care previne închiderea bruscă a aplicației mobile. Conform datelor Apple Developer, 2024, gestionarea corectă a excepțiilor reduce numărul de crash-uri cu 40–60% și îmbunătățește experiența utilizatorului. Fără un astfel de handler, orice excepție neprocesată într-un fir de fundal duce la închiderea imediată a aplicației.

Principalele puncte

  • Global Exception Handler — punctul de colectare a tuturor excepțiilor neprocesate din aplicație, prevenind crash-urile
  • iOS NSSetUncaughtExceptionHandler — funcție C pentru interceptarea excepțiilor Objective-C pe platforma Apple
  • Android Thread.setDefaultUncaughtExceptionHandler — mecanismul integrat al platformei pentru interceptarea globală a excepțiilor
  • Logare înainte de închidere — sarcina principală a handler-ului: salvarea informațiilor despre crash înainte de terminarea procesului
  • Graceful degradation — handler-ul permite afișarea unui ecran de eroare corect în locul închiderii bruște

Ce este Global Exception Handler?

Global Exception Handler — este un mecanism centralizat de interceptare a excepțiilor care nu au fost gestionate la nivelul funcțiilor sau modulelor individuale ale aplicației. În contextul dezvoltării mobile, un astfel de handler reprezintă ultima linie de apărare înainte de terminarea forțată a procesului.

iOS și Android oferă API-uri integrate pentru instalarea unui handler global. Apple folosește NSSetUncaughtExceptionHandler pentru mediul Objective-C, iar Google oferă Thread.setDefaultUncaughtExceptionHandler în Java/Kotlin. Ambele mecanisme interceptează excepțiile care nu au fost prinse de constructiile try-catch în toate firele de execuție ale aplicației.

Conform datelor Crashlytics (Google, 2024), aproximativ 25% din crash-uri apar din cauza excepțiilor neprocesate în firele de fundal — un domeniu în care Global Exception Handler este deosebit de critic. Dezvoltatorii se concentrează adesea pe firul UI, uitând de operațiile asincrone.

Utilizarea handler-ului global nu înlocuiește gestionarea locală a erorilor, ci o completează. Sarcina principală este salvarea maximului de informații despre starea aplicației în momentul excepției și încheierea corectă a funcționării.

Cum funcționează handler-ul global de excepții

Mecanismul de funcționare al Global Exception Handler se bazează pe interceptarea semnalelor sistemului de operare sau a excepțiilor de timp de execuție. Când codul aruncă o excepție care nu este prinsă de niciun bloc try-catch, controlul este transferat handler-ului prestabilit.

Pe platforma iOS, handler-ul se înregistrează prin NSSetUncaughtExceptionHandler și primește obiectul NSException cu stack trace complet. Pe Android se folosește Thread.setDefaultUncaughtExceptionHandler, care primește Thread și Throwable — oferind acces la tipul excepției, mesaj și stiva de apeluri.

După primirea datelor despre crash, handler-ul execută trei acțiuni obligatorii: scrierea log-ului în stocarea locală, trimiterea raportului către Crashlytics sau Sentry și încheierea corectă a aplicației. Conform Apple WWDC 2023, timpul de lucru al handler-ului este limitat la 5 secunde — după aceasta, sistemul forțează terminarea procesului.

Pentru aplicațiile Swift începând cu iOS 13 a apărut Signals API, care procesează nu doar excepțiile, ci și semnalele sistemului de operare — SIGABRT, SIGSEGV și SIGBUS, extinzând zona de acoperire a handler-ului la erorile de memorie de nivel scăzut.

Implementarea Global Exception Handler pe iOS

Implementarea handler-ului global pe iOS necesită setarea unei funcții C prin NSSetUncaughtExceptionHandler. Handler-ul este apelat sincron în momentul excepției neprocesate și primește contextul complet al erorii.

objective-c
void handleUncaughtException(NSException exception) {
    NSDictionary userInfo = [exception userInfo];
    NSArray stackTrace = [exception callStackSymbols];
    NSString reason = [exception reason];

    // Salvăm log-ul de crash într-un fișier local
    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);
}

O caracteristică importantă a implementării iOS: handler-ul interceptează doar excepțiile Objective-C. Erorile Swift, care folosesc mecanismul throw-catch, nu ajung la acest handler — pentru ele este necesară o procesare separată prin Swift Error Handling. Începând cu iOS 14, Apple recomandă combinarea NSSetUncaughtExceptionHandler cu Signals API pentru o acoperire maximă.

Conform Apple Technical Note TN2151, după apelarea handler-ului, aplicația trebuie să se încheie în termen de 5 secunde. Orice tentativă de a continua execuția după revenirea din handler duce la un comportament nedefinit și la un nou crash.

Implementarea Global Exception Handler pe Android

Android oferă un mecanism mai flexibil de gestionare globală a excepțiilor prin Thread.setDefaultUncaughtExceptionHandler. Handler-ul primește o referință către firul de execuție în care a apărut excepția și obiectul Throwable propriu-zis.

kotlin
class GlobalExceptionHandler : Thread.UncaughtExceptionHandler {

    override fun uncaughtException(thread: Thread, throwable: Throwable) {
        // Salvăm log-ul de crash într-un fișier
        val stackTrace = throwable.stackTraceToString()
        val crashLog = "CRASH: ${thread.name}\n${stackTrace}"

        val file = File(context.cacheDir, "crash_log.txt")
        file.writeText(crashLog)

        // Trimitem către Crashlytics
        FirebaseCrashlytics.getInstance()
            .recordException(throwable)

        // Încheiem procesul
        android.os.Process.killProcess(
            android.os.Process.myPid()
        )
    }
}

// Instalare în Application.onCreate
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        Thread.setDefaultUncaughtExceptionHandler(
            GlobalExceptionHandler()
        )
    }
}

Diferența cheie a implementării Android: fiecare fir de execuție are propriul handler, iar setDefaultUncaughtExceptionHandler setează handler-ul pentru toate firele care nu au un handler individual. Aceasta asigură acoperire globală — de la firul UI până la AsyncTask-urile de fundal și corutine.

Pe Android 12+ a apărut o limitare: după apelarea uncaughtException, aplicația trebuie să se încheie în termen de 100 de milisecunde. Dacă handler-ul execută operații îndelungate, sistemul poate ucide procesul înainte de finalizarea scrierii log-ului. Se recomandă utilizarea unui serviciu de fundal pentru trimiterea raportului de crash.

Cele mai bune practici cu Global Exception Handler

Prima regulă — nu încercați să restabiliți funcționarea aplicației după o excepție neprocesată. Starea aplicației după crash este nedefinită, iar continuarea lucrului poate duce la deteriorarea datelor utilizatorului.

Minimizarea timpului de lucru al handler-ului

Limitarea de timp — principala constrângere tehnică a Global Exception Handler. Pe iOS este 5 secunde, pe Android — 100 de milisecunde. În interiorul handler-ului este permisă doar salvarea unui set minim de date: tipul excepției, stiva de apeluri și starea câtorva variabile cheie.

Trimiterea cererilor de rețea, scrierea în baza de date și serializarea complexă trebuie mutate într-un mecanism amânat — de exemplu, salvarea log-ului într-un fișier și trimiterea acestuia la următoarea pornire a aplicației.

Combinarea cu sistemele de raportare crash

Serviciile de raportare crash — Firebase Crashlytics, Sentry, Bugsnag — își instalează singure handler-ul global. Dacă dezvoltatorul își instalează propriul handler peste ele, trebuie să transmită controlul sistemului de raportare crash după acțiunile sale. Pe Android se folosește compoziția handler-elor: se execută logica proprie, apoi se apelează handler-ul anterior.

Pentru Firebase Crashlytics se recomandă să nu se instaleze deloc un Thread.setDefaultUncaughtExceptionHandler personalizat — Crashlytics SDK o face automat la inițializare.

Logarea informațiilor suplimentare

Contextul utilizatorului — pe lângă stiva standard de apeluri, este util să se logheze versiunea aplicației, versiunea sistemului de operare, cantitatea de memorie liberă și timpul de funcționare până la crash. Aceste date sunt esențiale pentru reproducerea și remedierea problemei.

În iOS se poate folosi NSSetUncaughtExceptionHandler nu doar pentru scriere, ci și pentru stocarea temporară a datelor în NSUserDefaults cu flag-ul synchronize — aceasta garantează salvarea datelor chiar și la terminarea imediată a procesului.

Testarea handler-ului înainte de lansare

Testare obligatorie — Global Exception Handler trebuie testat în fiecare etapă a CI/CD. Pe iOS se poate iniția o excepție de test prin @throw NSException, pe Android — prin throw RuntimeException(). Se verifică că handler-ul este apelat, log-ul este salvat și aplicația se încheie corect.

Conform Google I/O 2023, peste 30% din crash-uri în producție apar pe dispozitive pe care dezvoltatorul nu le-a testat — versiuni diferite de Android, firmware personalizat, memorie limitată.

Greșeli tipice la utilizarea handler-ului

Prima și cea mai frecventă greșeală — încercarea de a continua execuția aplicației după procesarea excepției. După apelarea uncaughtException, aplicația se află într-o stare instabilă, iar orice operații ulterioare pot provoca cascada de erori și deteriorarea datelor.

A doua greșeală — executarea de operații lungi în interiorul handler-ului. Cererile de rețea, scrierea fișierelor mari sau calculele complexe nu au timp să se finalizeze înainte de terminarea forțată a procesului. Conform Apple Technical Q&A QA1468, încercarea de a trimite o cerere HTTP în interiorul handler-ului este principala cauză a rapoartelor de crash pierdute.

A treia greșeală — ignorarea firelor de fundal. Global Exception Handler, setat doar pentru firul principal, nu protejează împotriva crash-urilor în corutine, DispatchQueue, AsyncTask sau RxJava. Pe Android, fiecare fir de execuție ar trebui să aibă propriul handler — iar setDefaultUncaughtExceptionHandler rezolvă această problemă doar pentru firele fără handler individual.

A patra greșeală — lipsa unui fallback pentru semnalele sistemului de operare. NSSetUncaughtExceptionHandler pe iOS nu interceptează SIGABRT, SIGSEGV și SIGBUS. Pentru aceste semnale este necesară instalarea separată de handler-e prin sigaction API. Dezvoltatorii află despre aceasta doar când aplicația se prăbușește fără niciun raport de crash.

A cincea greșeală — logarea datelor confidențiale. În log-ul de crash ajung emailuri, token-uri de autorizare sau date personale ale utilizatorilor. Aceasta încalcă GDPR și Apple App Store Review Guidelines. Filtrați întotdeauna datele transmise prin regex sau o listă whitelist de câmpuri permise.

Întrebări frecvente

Se poate restabili funcționarea aplicației după o excepție globală?

Nu — după apelarea Global Exception Handler, starea aplicației este nedefinită. Orice încercare de a continua poate duce la deteriorarea datelor. Singura acțiune corectă — salvați log-ul de crash și încheiați procesul.

Global Exception Handler interceptează toate tipurile de erori?

Nu toate — pe iOS, NSSetUncaughtExceptionHandler prinde doar excepțiile Objective-C. Erorile Swift și semnalele sistemului de operare (SIGSEGV, SIGABRT) necesită handler-e separate. Pe Android, Thread.setDefaultUncaughtExceptionHandler interceptează toate RuntimeException, dar nu și erorile de cod native prin JNI.

Cum să transmit controlul sistemului de raportare crash după propriul handler?

Salvați referința către handler-ul anterior prin Thread.getDefaultUncaughtExceptionHandler() înainte de a vă instala propriul handler. La sfârșitul handler-ului dvs., apelați previousHandler.uncaughtException(thread, throwable) — aceasta garantează că Crashlytics sau Sentry își vor primi datele.

Ce să faceți dacă crash-ul a avut loc în codul nativ C/C++?

Pentru codul nativ este necesară gestionarea semnalelor prin sigaction() — SIGSEGV, SIGABRT, SIGBUS. Pe Android se poate utiliza Google Breakpad sau Crashpad. Pe iOS, începând cu versiunea 13, este disponibil Signals API pentru gestionarea excepțiilor mach.

Poate Global Exception Handler să afecteze performanța?

Nu — instalarea handler-ului afectează doar momentul apariției excepției. În funcționarea normală a aplicației nu există overhead. Singurul risc este scurgerea de memorie dacă handler-ul păstrează o referință către Activity sau Context, împiedicând colectarea lor de gunoi.

Concluzii

  • Global Exception Handler — ultima linie de apărare înainte de crash, obligatoriu în orice aplicație de producție
  • iOS NSSetUncaughtExceptionHandler interceptează excepțiile Objective-C cu o limită de 5 secunde pentru procesare
  • Android Thread.setDefaultUncaughtExceptionHandler funcționează pentru toate firele fără handler individual
  • Timpul de lucru al handler-ului trebuie să fie minim — salvați datele și încheiați procesul fără încercarea de restabilire
  • Semnalele sistemului de operare (SIGSEGV, SIGABRT) nu sunt interceptate de handler-ele standard — este necesar sigaction API
  • Sistemele de raportare crash trebuie apelate prin compoziția handler-elor, transmițând controlul după logica proprie
  • Testarea handler-ului în CI/CD — o etapă obligatorie care previne pierderea rapoartelor de crash în producție

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și