Global Exception Handler: podstata, princip fungování a implementace v projektech

Autor: IT Sectr Publikováno: 2026-05-27 Doba čtení: 8 min

Global Exception Handler — mechanismus centralizovaného zachycení neošetřených výjimek, který zabraňuje havarijnímu ukončení mobilní aplikace. Podle údajů Apple Developer, 2024 snižuje správné zpracování výjimek počet crashů o 40–60% a zlepšuje uživatelský zážitek. Bez takového handleru vede každá neošetřená výjimka na vlákně na pozadí k okamžitému ukončení aplikace.

Hlavní body

  • Global Exception Handler — sběrný bod všech neošetřených výjimek v aplikaci, zabraňuje crashům
  • iOS NSSetUncaughtExceptionHandler — funkce C pro zachycení výjimek Objective-C na platformě Apple
  • Android Thread.setDefaultUncaughtExceptionHandler — vestavěný mechanismus platformy pro globální zachycení výjimek
  • Protokolování před ukončením — hlavní úkol handleru: uložit informace o crashu před dokončením procesu
  • Graceful degradation — handler umožňuje zobrazit uživateli správnou obrazovku chyby místo havarijního ukončení

Co je Global Exception Handler?

Global Exception Handler — je centralizovaný mechanismus pro zachycení výjimek, které nebyly ošetřeny na úrovni jednotlivých funkcí nebo modulů aplikace. V kontextu mobilního vývoje slouží takový handler jako poslední obranná linie před havarijním ukončením procesu.

iOS a Android poskytují vestavěná API pro nastavení globálního handleru. Apple používá NSSetUncaughtExceptionHandler pro prostředí Objective-C a Google nabízí Thread.setDefaultUncaughtExceptionHandler v Javě/Kotlinu. Oba mechanismy zachycují výjimky, které nebyly zachyceny konstrukcemi try-catch ve všech vláknech aplikace.

Podle údajů Crashlytics (Google, 2024) dochází k přibližně 25% crashů kvůli neošetřeným výjimkám na vláknech na pozadí — oblast, kde je Global Exception Handler obzvláště kritický. Vývojáři se často zaměřují na UI vlákno a zapomínají na asynchronní operace.

Použití globálního handleru nenahrazuje místní zpracování chyb, ale doplňuje jej. Hlavním úkolem je uložit maximum informací o stavu aplikace v okamžiku výjimky a správně ukončit činnost.

Jak funguje globální handler výjimek

Mechanismus fungování Global Exception Handler je založen na zachycování signálů operačního systému nebo výjimek běhového prostředí. Když kód vyvolá výjimku, která není zachycena žádným blokem try-catch, řízení je předáno předem nastavenému handleru.

Na platformě iOS se handler registruje prostřednictvím NSSetUncaughtExceptionHandler a obdrží objekt NSException s úplným stack trace. Na Androidu se používá Thread.setDefaultUncaughtExceptionHandler, který přijímá Thread a Throwable — to poskytuje přístup k typu výjimky, zprávě a zásobníku volání.

Po obdržení dat o crashu handler provede tři povinné akce: zápis protokolu do místního úložiště, odeslání zprávy do Crashlytics nebo Sentry a správné ukončení aplikace. Podle Apple WWDC 2023 je doba práce handleru omezena na 5 sekund — poté systém proces násilně ukončí.

Pro aplikace Swift od iOS 13 se objevilo Signals API, které zpracovává nejen výjimky, ale také signály operačního systému — SIGABRT, SIGSEGV a SIGBUS, čímž rozšiřuje pokrytí handleru na nízkoúrovňové chyby paměti.

Implementace Global Exception Handler na iOS

Implementace globálního handleru na iOS vyžaduje nastavení funkce C prostřednictvím NSSetUncaughtExceptionHandler. Handler je volán synchronně v okamžiku neošetřené výjimky a obdrží úplný kontext chyby.

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

    // Uložit crash protokol do místního souboru
    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);
}

Důležitá vlastnost implementace na iOS: handler zachycuje pouze výjimky Objective-C. Chyby Swiftu, které používají mechanismus throw-catch, se do tohoto handleru nedostanou — vyžadují samostatné zpracování pomocí Swift Error Handling. Od iOS 14 Apple doporučuje kombinovat NSSetUncaughtExceptionHandler s Signals API pro maximální pokrytí.

Podle Apple Technical Note TN2151 musí být aplikace po volání handleru ukončena do 5 sekund. Jakýkoli pokus o pokračování provádění po návratu z handleru vede k nedefinovanému chování a opětovnému crashu.

Implementace Global Exception Handler na Android

Android poskytuje flexibilnější mechanismus globálního zpracování výjimek prostřednictvím Thread.setDefaultUncaughtExceptionHandler. Handler obdrží odkaz na vlákno, ve kterém došlo k výjimce, a samotný objekt Throwable.

kotlin
class GlobalExceptionHandler : Thread.UncaughtExceptionHandler {

    override fun uncaughtException(thread: Thread, throwable: Throwable) {
        // Uložit crash protokol do souboru
        val stackTrace = throwable.stackTraceToString()
        val crashLog = "CRASH: ${thread.name}\n${stackTrace}"

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

        // Odeslat do Crashlytics
        FirebaseCrashlytics.getInstance()
            .recordException(throwable)

        // Ukončit proces
        android.os.Process.killProcess(
            android.os.Process.myPid()
        )
    }
}

// Instalace v Application.onCreate
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        Thread.setDefaultUncaughtExceptionHandler(
            GlobalExceptionHandler()
        )
    }
}

Klíčový rozdíl implementace na Android: každé vlákno má svůj vlastní handler a setDefaultUncaughtExceptionHandler nastaví handler pro všechna vlákna, která nemají individuální handler. To zajišťuje globální pokrytí — od UI vlákna po vlákna na pozadí AsyncTask a korutiny.

Na Android 12+ se objevilo omezení: po volání uncaughtException musí být aplikace ukončena do 100 milisekund. Pokud handler provádí dlouhodobé operace, systém může zabít proces před dokončením zápisu protokolu. Doporučuje se používat službu na pozadí pro odeslání crash zprávy.

Osvědčené postupy při práci s Global Exception Handler

První pravidlo — nepokoušejte se obnovit aplikaci po neošetřené výjimce. Stav aplikace po crashu je nedefinovaný a pokračování v práci může vést k poškození uživatelských dat.

Minimalizace doby práce handleru

Časové omezení — hlavní technické omezení Global Exception Handler. Na iOS je to 5 sekund, na Android — 100 milisekund. Uvnitř handleru je povoleno pouze uložit minimální sadu dat: typ výjimky, zásobník volání a stav několika klíčových proměnných.

Odesílání síťových požadavků, zápis do databáze a složitou serializaci je třeba přesunout do odloženého mechanismu — například uložit protokol do souboru a odeslat jej při příštím spuštění aplikace.

Kombinace se systémy pro hlášení crash

Služby pro hlášení crash — Firebase Crashlytics, Sentry, Bugsnag — samy nastavují globální handler. Pokud vývojář nastaví svůj vlastní handler nad ně, musí po svých akcích předat řízení systému pro hlášení crash. Na Androidu se používá kompozice handlerů: provést vlastní logiku, poté zavolat předchozí handler.

Pro Firebase Crashlytics se doporučuje vůbec nenastavovat vlastní Thread.setDefaultUncaughtExceptionHandler — Crashlytics SDK to dělá automaticky při inicializaci.

Protokolování dalších informací

Uživatelský kontext — kromě standardního zásobníku volání je užitečné protokolovat verzi aplikace, verzi OS, množství volné paměti a dobu běhu do crashu. Tato data jsou kritická pro reprodukci a odstranění problému.

Na iOS lze NSSetUncaughtExceptionHandler použít nejen k zápisu, ale také k dočasnému ukládání dat do NSUserDefaults s příznakem synchronize — to zaručuje uchování dat i při okamžitém ukončení procesu.

Testování handleru před vydáním

Povinné testování — Global Exception Handler musí být testován v každé fázi CI/CD. Na iOS lze iniciovat testovací výjimku pomocí @throw NSException, na Android — pomocí throw RuntimeException(). Ověřuje se, že je handler volán, protokol je uložen a aplikace je správně ukončena.

Podle Google I/O 2023 dochází k více než 30% crashů v produkci na zařízeních, která vývojář netestoval — různé verze Androidu, vlastní firmware, omezená paměť.

Typické chyby při použití handleru

První a nejčastější chyba — pokus o pokračování provádění aplikace po zpracování výjimky. Po volání uncaughtException je aplikace v nestabilním stavu a jakékoli další operace mohou způsobit kaskádu chyb a poškození dat.

Druhá chyba — provádění dlouhodobých operací uvnitř handleru. Síťové požadavky, zápis velkých souborů nebo složité výpočty nestihnou dokončit před násilným ukončením procesu. Podle Apple Technical Q&A QA1468 je pokus o odeslání HTTP požadavku uvnitř handleru hlavní příčinou ztracených crash zpráv.

Třetí chyba — ignorování vláken na pozadí. Global Exception Handler nastavený pouze pro hlavní vlákno nechrání před crashy v korutinách, DispatchQueue, AsyncTask nebo RxJava. Na Androidu by každé vlákno mělo mít svůj vlastní handler — a setDefaultUncaughtExceptionHandler řeší tento problém pouze pro vlákna bez individuálního handleru.

Čtvrtá chyba — chybějící fallback pro signály operačního systému. NSSetUncaughtExceptionHandler na iOS nezachycuje SIGABRT, SIGSEGV a SIGBUS. Pro tyto signály je vyžadováno samostatné nastavení handlerů prostřednictvím sigaction API. Vývojáři se o tom dozví, až když aplikace spadne bez jediné crash zprávy.

Pátá chyba — protokolování důvěrných údajů. Do crash protokolu se dostanou e-maily, autorizační tokeny nebo osobní údaje uživatelů. To porušuje GDPR a Apple App Store Review Guidelines. Vždy filtrujte předávaná data pomocí regexu nebo whitelistu povolených polí.

Často kladené otázky

Lze obnovit činnost aplikace po globální výjimce?

Ne — po volání Global Exception Handler je stav aplikace nedefinovaný. Jakýkoli pokus o pokračování v práci může vést k poškození dat. Jediným správným krokem je uložit crash protokol a ukončit proces.

Zachycuje Global Exception Handler všechny typy chyb?

Ne všechny — na iOS NSSetUncaughtExceptionHandler chytá pouze výjimky Objective-C. Chyby Swiftu a signály OS (SIGSEGV, SIGABRT) vyžadují samostatné handlery. Na Androidu Thread.setDefaultUncaughtExceptionHandler zachycuje všechny RuntimeException, ale ne chyby nativního kódu přes JNI.

Jak předat řízení systému pro hlášení crash po svém handleru?

Uložte odkaz na předchozí handler prostřednictvím Thread.getDefaultUncaughtExceptionHandler() před nastavením vlastního handleru. Na konci svého handleru zavolejte previousHandler.uncaughtException(thread, throwable) — to zaručuje, že Crashlytics nebo Sentry obdrží svá data.

Co dělat, pokud crash nastal v nativním kódu C/C++?

Pro nativní kód je vyžadováno zpracování signálů prostřednictvím sigaction() — SIGSEGV, SIGABRT, SIGBUS. Na Androidu lze použít Google Breakpad nebo Crashpad. Na iOS od verze 13 je k dispozici Signals API pro zpracování mach výjimek.

Může Global Exception Handler ovlivnit výkon?

Ne — nastavení handleru ovlivňuje pouze okamžik vzniku výjimky. Při normálním provozu aplikace nedochází k žádné režii. Jediným rizikem je únik paměti, pokud handler uchovává odkaz na Activity nebo Context, čímž brání jejich uvolnění garbage collectorem.

Shrnutí

  • Global Exception Handler — poslední obranná linie před crashem, povinný v každé produkční aplikaci
  • iOS NSSetUncaughtExceptionHandler zachycuje výjimky Objective-C s limitem 5 sekund na zpracování
  • Android Thread.setDefaultUncaughtExceptionHandler funguje pro všechna vlákna bez osobního handleru
  • Doba práce handleru musí být minimální — uložit data a ukončit proces bez pokusu o obnovu
  • Signály OS (SIGSEGV, SIGABRT) nejsou zachyceny standardními handlery — vyžadují sigaction API
  • Systémy pro hlášení crash by měly být volány prostřednictvím kompozice handlerů s předáním řízení po vlastní logice
  • Testování handleru v CI/CD — povinná fáze, která zabraňuje ztrátě crash zpráv v produkci

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také