Global Exception Handler — ein zentralisierter Mechanismus zum Abfangen unbehandelter Ausnahmen, der das Abstürzen mobiler Anwendungen verhindert. Laut Apple Developer, 2024 reduziert die korrekte Ausnahmebehandlung die Anzahl der Abstürze um 40–60% und verbessert die Benutzererfahrung. Ohne einen solchen Handler führt jede unbehandelte Ausnahme in einem Hintergrundthread zum sofortigen Schließen der Anwendung.
Wichtige Punkte
Global Exception Handler — ist ein zentralisierter Mechanismus zum Abfangen von Ausnahmen, die auf der Ebene einzelner Funktionen oder Module der Anwendung nicht behandelt wurden. Im Kontext der mobilen Entwicklung fungiert ein solcher Handler als letzte Verteidigungslinie vor dem abnormalen Beenden des Prozesses.
iOS und Android bieten integrierte APIs zum Festlegen eines globalen Handlers. Apple verwendet NSSetUncaughtExceptionHandler für die Objective-C-Umgebung, während Google Thread.setDefaultUncaughtExceptionHandler in Java/Kotlin anbietet. Beide Mechanismen fangen Ausnahmen ab, die von try-catch-Konstrukten in allen Threads der Anwendung nicht abgefangen wurden.
Laut Crashlytics (Google, 2024) treten etwa 25% der Abstürze aufgrund unbehandelter Ausnahmen in Hintergrundthreads auf — ein Bereich, in dem der Global Exception Handler besonders kritisch ist. Entwickler konzentrieren sich oft auf den UI-Thread und vergessen asynchrone Operationen.
Die Verwendung eines globalen Handlers ersetzt nicht die lokale Fehlerbehandlung, sondern ergänzt sie. Die Hauptaufgabe besteht darin, maximale Informationen über den Zustand der Anwendung zum Zeitpunkt der Ausnahme zu speichern und ordnungsgemäß zu beenden.
Der Arbeitsmechanismus des Global Exception Handler basiert auf dem Abfangen von Betriebssystemsigalen oder Laufzeitausnahmen. Wenn Code eine Ausnahme auslöst, die von keinem try-catch-Block abgefangen wird, wird die Kontrolle an einen vorab registrierten Handler übergeben.
Auf iOS wird der Handler über NSSetUncaughtExceptionHandler registriert und erhält ein NSException-Objekt mit vollständigem Stack-Trace. Auf Android wird Thread.setDefaultUncaughtExceptionHandler verwendet, der Thread und Throwable akzeptiert — dies ermöglicht den Zugriff auf den Ausnahmetyp, die Meldung und den Aufrufstapel.
Nach Erhalt der Absturzdaten führt der Handler drei obligatorische Aktionen durch: Schreiben eines Protokolls in den lokalen Speicher, Senden eines Berichts an Crashlytics oder Sentry und ordnungsgemäßes Beenden der Anwendung. Laut Apple WWDC 2023 ist die Ausführungszeit des Handlers auf 5 Sekunden begrenzt — danach beendet das System den Prozess zwangsweise.
Für Swift-Anwendungen ab iOS 13 wurde die Signals API eingeführt, die nicht nur Ausnahmen, sondern auch Betriebssystemsigale — SIGABRT, SIGSEGV und SIGBUS — behandelt und die Abdeckung des Handlers auf speicherbezogene Fehler niedriger Ebene erweitert.
Die Implementierung eines globalen Handlers auf iOS erfordert das Setzen einer C-Funktion über NSSetUncaughtExceptionHandler. Der Handler wird synchron im Moment einer unbehandelten Ausnahme aufgerufen und erhält den vollständigen Fehlerkontext.
void handleUncaughtException(NSException exception) {
NSDictionary userInfo = [exception userInfo];
NSArray stackTrace = [exception callStackSymbols];
NSString reason = [exception reason];
// Crash-Log in lokaler Datei speichern
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);
}
Ein wichtiges Merkmal der iOS-Implementierung: Der Handler fängt nur Objective-C-Ausnahmen. Swift-Fehler, die den throw-catch-Mechanismus verwenden, erreichen diesen Handler nicht — sie erfordern eine separate Behandlung über Swift Error Handling. Ab iOS 14 empfiehlt Apple, NSSetUncaughtExceptionHandler mit der Signals API zu kombinieren, um eine maximale Abdeckung zu erreichen.
Laut Apple Technical Note TN2151 muss die Anwendung nach dem Aufruf des Handlers innerhalb von 5 Sekunden beendet werden. Jeder Versuch, die Ausführung nach der Rückkehr aus dem Handler fortzusetzen, führt zu undefiniertem Verhalten und einem erneuten Absturz.
Android bietet einen flexibleren Mechanismus zur globalen Ausnahmebehandlung über Thread.setDefaultUncaughtExceptionHandler. Der Handler erhält einen Verweis auf den Thread, in dem die Ausnahme aufgetreten ist, und das Throwable-Objekt selbst.
class GlobalExceptionHandler : Thread.UncaughtExceptionHandler {
override fun uncaughtException(thread: Thread, throwable: Throwable) {
// Crash-Log in Datei speichern
val stackTrace = throwable.stackTraceToString()
val crashLog = "CRASH: ${thread.name}\n${stackTrace}"
val file = File(context.cacheDir, "crash_log.txt")
file.writeText(crashLog)
// An Crashlytics senden
FirebaseCrashlytics.getInstance()
.recordException(throwable)
// Prozess beenden
android.os.Process.killProcess(
android.os.Process.myPid()
)
}
}
// Einrichtung in Application.onCreate
class App : Application() {
override fun onCreate() {
super.onCreate()
Thread.setDefaultUncaughtExceptionHandler(
GlobalExceptionHandler()
)
}
}
Ein wesentlicher Unterschied der Android-Implementierung: Jeder Thread hat seinen eigenen Handler, und setDefaultUncaughtExceptionHandler legt den Handler für alle Threads fest, die keinen individuellen Handler zugewiesen haben. Dies gewährleistet eine globale Abdeckung — vom UI-Thread bis zu Hintergrund-AsyncTask und Coroutinen.
Ab Android 12+ gibt es eine Einschränkung: Nach dem Aufruf von uncaughtException muss die Anwendung innerhalb von 100 Millisekunden beendet werden. Wenn der Handler langlebige Operationen ausführt, kann das System den Prozess beenden, bevor das Protokoll geschrieben wird. Es wird empfohlen, einen Hintergrunddienst zum Senden von Absturzberichten zu verwenden.
Die erste Regel — versuchen Sie nicht, den Betrieb der Anwendung nach einer unbehandelten Ausnahme wiederherzustellen. Der Zustand der Anwendung nach einem Absturz ist undefiniert, und die Fortsetzung der Ausführung kann zur Beschädigung von Benutzerdaten führen.
Zeitbegrenzung — die wichtigste technische Einschränkung des Global Exception Handler. Auf iOS beträgt sie 5 Sekunden, auf Android 100 Millisekunden. Innerhalb des Handlers darf nur ein minimaler Datensatz gespeichert werden: Ausnahmetyp, Aufrufstapel und der Zustand einiger Schlüsselvariablen.
Das Senden von Netzwerkanfragen, das Schreiben in die Datenbank und komplexe Serialisierung sollten auf einen verzögerten Mechanismus verschoben werden — zum Beispiel das Protokoll in einer Datei speichern und beim nächsten Start der Anwendung senden.
Crash-Reporting-Dienste — Firebase Crashlytics, Sentry, Bugsnag — legen ihren eigenen globalen Handler fest. Wenn ein Entwickler einen zusätzlichen benutzerdefinierten Handler festlegt, muss er nach seinen eigenen Aktionen die Kontrolle an das Crash-Reporting-System übergeben. Auf Android wird die Handler-Komposition verwendet: Führen Sie Ihre Logik aus und rufen Sie dann den vorherigen Handler auf.
Für Firebase Crashlytics wird empfohlen, gar keinen benutzerdefinierten Thread.setDefaultUncaughtExceptionHandler zu setzen — das Crashlytics SDK erledigt dies automatisch bei der Initialisierung.
Benutzerkontext — zusätzlich zum Standard-Aufrufstapel ist es nützlich, die App-Version, die OS-Version, die verfügbare Speichergröße und die Betriebszeit vor dem Absturz zu protokollieren. Diese Daten sind für die Reproduktion und Behebung des Problems von entscheidender Bedeutung.
Auf iOS kann NSSetUncaughtExceptionHandler nicht nur zum Schreiben, sondern auch zur vorübergehenden Datenspeicherung in NSUserDefaults mit dem synchronize-Flag verwendet werden — dies garantiert die Persistenz selbst bei sofortiger Prozessbeendigung.
Obligatorische Tests — der Global Exception Handler muss in jeder Phase des CI/CD getestet werden. Auf iOS kann eine Testausnahme über @throw NSException ausgelöst werden, auf Android über throw RuntimeException(). Es wird überprüft, ob der Handler aufgerufen wird, das Protokoll gespeichert wird und die Anwendung ordnungsgemäß beendet wird.
Laut Google I/O 2023 treten mehr als 30% der Abstürze in der Produktion auf Geräten auf, die der Entwickler nicht getestet hat — verschiedene Android-Versionen, benutzerdefinierte Firmware, begrenzter Speicher.
Der erste und häufigste Fehler — der Versuch, die Ausführung der Anwendung nach der Behandlung einer Ausnahme fortzusetzen. Nach dem Aufruf von uncaughtException befindet sich die Anwendung in einem instabilen Zustand, und jede weitere Operation kann Kaskadenfehler und Datenbeschädigung verursachen.
Der zweite Fehler — die Ausführung langlebiger Operationen innerhalb des Handlers. Netzwerkanfragen, das Schreiben großer Dateien oder komplexe Berechnungen werden vor dem zwangsweisen Beenden des Prozesses nicht abgeschlossen. Laut Apple Technical Q&A QA1468 ist der Versuch, eine HTTP-Anfrage innerhalb des Handlers zu senden, die Hauptursache für verlorene Absturzberichte.
Der dritte Fehler — das Ignorieren von Hintergrundthreads. Ein nur für den Hauptthread festgelegter Global Exception Handler schützt nicht vor Abstürzen in Coroutinen, DispatchQueue, AsyncTask oder RxJava. Auf Android sollte jeder Thread seinen eigenen Handler haben — und setDefaultUncaughtExceptionHandler löst dies nur für Threads ohne individuellen Handler.
Der vierte Fehler — fehlender Fallback für Betriebssystemsigale. NSSetUncaughtExceptionHandler auf iOS fängt SIGABRT, SIGSEGV und SIGBUS nicht ab. Diese Signale erfordern eine separate Handlereinrichtung über die sigaction API. Entwickler erfahren dies erst, wenn die App ohne einen einzigen Absturzbericht abstürzt.
Der fünfte Fehler — Protokollierung vertraulicher Daten. Im Absturzprotokoll können E-Mails, Authentifizierungstoken oder persönliche Daten von Benutzern auftauchen. Dies verstößt gegen die DSGVO und die Apple App Store Review Guidelines. Filtern Sie die übermittelten Daten immer mit Regex oder einer Whitelist erlaubter Felder.
Häufig gestellte Fragen
Nein — nach dem Aufruf des Global Exception Handler ist der Zustand der Anwendung undefiniert. Jeder Versuch, die Ausführung fortzusetzen, kann zu Datenbeschädigung führen. Die einzig korrekte Aktion ist, das Absturzprotokoll zu speichern und den Prozess zu beenden.
Nicht alle — auf iOS fängt NSSetUncaughtExceptionHandler nur Objective-C-Ausnahmen. Swift-Fehler und OS-Signale (SIGSEGV, SIGABRT) erfordern separate Handler. Auf Android fängt Thread.setDefaultUncaughtExceptionHandler alle RuntimeExceptions, aber keine nativen Codefehler über JNI.
Speichern Sie einen Verweis auf den vorherigen Handler über Thread.getDefaultUncaughtExceptionHandler(), bevor Sie Ihren eigenen setzen. Rufen Sie am Ende Ihres Handlers previousHandler.uncaughtException(thread, throwable) auf — dies stellt sicher, dass Crashlytics oder Sentry ihre Daten erhalten.
Für nativen Code ist eine Signalbehandlung über sigaction() erforderlich — SIGSEGV, SIGABRT, SIGBUS. Auf Android können Sie Google Breakpad oder Crashpad verwenden. Auf iOS ab Version 13 ist die Signals API zur Behandlung von Mach-Ausnahmen verfügbar.
Nein — das Setzen des Handlers wirkt sich nur auf den Moment aus, in dem eine Ausnahme auftritt. Im normalen Betrieb der Anwendung gibt es keinen Overhead. Das einzige Risiko ist ein Speicherleck, wenn der Handler einen Verweis auf eine Activity oder einen Context behält und so die Garbage Collection verhindert.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch