Global Exception Handler — en centraliserad mekanism för att fånga ohanterade undantag som förhindrar att en mobilapplikation kraschar. Enligt Apple Developer, 2024 minskar korrekt undantagshantering antalet krascher med 40–60% och förbättrar användarupplevelsen. Utan en sådan hanterare leder varje ohanterat undantag i en bakgrundstråd till omedelbar avstängning av appen.
Huvudpunkter
Global Exception Handler — är en centraliserad mekanism för att fånga undantag som inte har hanterats på nivån av enskilda funktioner eller moduler i applikationen. I mobilutvecklingssammanhang fungerar en sådan hanterare som den sista försvarslinjen innan processen tvångsavslutas.
iOS och Android tillhandahåller inbyggda API:er för att installera en global hanterare. Apple använder NSSetUncaughtExceptionHandler för Objective-C-miljön och Google erbjuder Thread.setDefaultUncaughtExceptionHandler i Java/Kotlin. Båda mekanismerna fångar undantag som inte har fångats av try-catch-konstruktioner i alla appens trådar.
Enligt Crashlytics (Google, 2024) inträffar cirka 25% av krascherna på grund av ohanterade undantag i bakgrundstrådar — ett område där Global Exception Handler är särskilt kritisk. Utvecklare fokuserar ofta på UI-tråden och glömmer asynkrona operationer.
Att använda en global hanterare ersätter inte lokal felhantering utan kompletterar den. Huvuduppgiften är att spara maximal information om applikationens tillstånd vid undantagstillfället och avsluta korrekt.
Funktionsmekanism — Global Exception Handler bygger på att fånga operativsystemssignaler eller körtidsundantag. När kod kastar ett undantag som inte fångas av något try-catch-block överförs kontrollen till den förinställda hanteraren.
På iOS-plattformen registreras hanteraren via NSSetUncaughtExceptionHandler och får ett NSException-objekt med full stack trace. På Android används Thread.setDefaultUncaughtExceptionHandler som tar emot Thread och Throwable — detta ger tillgång till undantagstyp, meddelande och anropsstack.
Efter att ha mottagit crash-data utför hanteraren tre obligatoriska åtgärder: skriva logg till lokal lagring, skicka rapport till Crashlytics eller Sentry och avsluta applikationen korrekt. Enligt Apple WWDC 2023 är hanterarens arbetstid begränsad till 5 sekunder — därefter avslutas processen tvångsvis.
För Swift-applikationer från iOS 13 och framåt har Signals API introducerats, som inte bara hanterar undantag utan även operativsystemssignaler — SIGABRT, SIGSEGV och SIGBUS — och utökar hanterarens täckning till lågnivåminnesfel.
Implementering — den globala hanteraren på iOS kräver att en C-funktion ställs in via NSSetUncaughtExceptionHandler. Hanteraren anropas synkront vid ett ohanterat undantag och får full felkontext.
void handleUncaughtException(NSException exception) {
NSDictionary userInfo = [exception userInfo];
NSArray stackTrace = [exception callStackSymbols];
NSString reason = [exception reason];
// Spara crash-logg i lokal fil
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);
}
Viktig egenskap för iOS-implementeringen: hanteraren fångar endast Objective-C-undantag. Swift-fel som använder throw-catch-mekanismen når inte denna hanterare — de kräver separat hantering via Swift Error Handling. Från iOS 14 rekommenderar Apple att kombinera NSSetUncaughtExceptionHandler med Signals API för maximal täckning.
Enligt Apple Technical Note TN2151 måste applikationen avslutas inom 5 sekunder efter att hanteraren anropats. Alla försök att fortsätta exekveringen efter att ha återvänt från hanteraren leder till odefinierat beteende och ytterligare krasch.
Android erbjuder en mer flexibel mekanism för global undantagshantering via Thread.setDefaultUncaughtExceptionHandler. Hanteraren får en referens till tråden där undantaget inträffade och själva Throwable-objektet.
class GlobalExceptionHandler : Thread.UncaughtExceptionHandler {
override fun uncaughtException(thread: Thread, throwable: Throwable) {
// Spara crash-logg i fil
val stackTrace = throwable.stackTraceToString()
val crashLog = "CRASH: ${thread.name}\n${stackTrace}"
val file = File(context.cacheDir, "crash_log.txt")
file.writeText(crashLog)
// Skicka till Crashlytics
FirebaseCrashlytics.getInstance()
.recordException(throwable)
// Avsluta processen
android.os.Process.killProcess(
android.os.Process.myPid()
)
}
}
// Installation i Application.onCreate
class App : Application() {
override fun onCreate() {
super.onCreate()
Thread.setDefaultUncaughtExceptionHandler(
GlobalExceptionHandler()
)
}
}
Nyckelskillnad i Android-implementeringen: varje tråd har sin egen hanterare och setDefaultUncaughtExceptionHandler ställer in en hanterare för alla trådar som inte har en individuell hanterare. Detta säkerställer global täckning — från UI-tråden till bakgrunds-AsyncTask och korutiner.
Från Android 12+ har en begränsning införts: efter anrop av uncaughtException måste applikationen avslutas inom 100 millisekunder. Om hanteraren utför långvariga operationer kan systemet döda processen innan loggskrivningen är klar. Det rekommenderas att använda en bakgrundstjänst för att skicka crash-rapporten.
Första regeln — försök inte återställa applikationen efter ett ohanterat undantag. Applikationens tillstånd efter en krasch är odefinierat och att fortsätta arbetet kan leda till skada på användardata.
Tidsbegränsning — den främsta tekniska begränsningen för Global Exception Handler. På iOS är detta 5 sekunder, på Android — 100 millisekunder. Inuti hanteraren är endast lagring av minimal data tillåten: undantagstyp, anropsstack och tillståndet för några nyckelvariabler.
Nätverksförfrågningar, databasskrivning och komplex serialisering bör flyttas till en fördröjd mekanism — till exempel spara loggen i en fil och skicka den vid nästa appstart.
Crash-rapporteringstjänster — Firebase Crashlytics, Sentry, Bugsnag — installerar själva en global hanterare. Om utvecklaren installerar sin egen hanterare ovanpå dem måste han överlämna kontrollen till crash-rapporteringssystemet efter sina åtgärder. På Android används hanterarkomposition: utför egen logik, anropa sedan föregående hanterare.
För Firebase Crashlytics rekommenderas att inte alls installera en anpassad Thread.setDefaultUncaughtExceptionHandler — Crashlytics SDK gör detta automatiskt vid initiering.
Användarkontext — förutom standardanropsstacken är det bra att logga appversion, OS-version, mängden ledigt minne och tid till krasch. Dessa data är avgörande för reproduktion och åtgärdande av problemet.
På iOS kan NSSetUncaughtExceptionHandler användas inte bara för loggning utan även för tillfällig lagring av data i NSUserDefaults med synchronize-flaggan — detta garanterar att data bevaras även vid omedelbar processavslutning.
Obligatorisk testning — Global Exception Handler måste testas i varje steg av CI/CD. På iOS kan ett testundantag initieras via @throw NSException, på Android — via throw RuntimeException(). Det kontrolleras att hanteraren anropas, loggen sparas och applikationen avslutas korrekt.
Enligt Google I/O 2023 inträffar mer än 30% av krascherna i produktion på enheter som utvecklaren inte testat — olika Android-versioner, anpassad firmware, begränsat minne.
Första och vanligaste misstaget — försök att fortsätta exekveringen av applikationen efter att undantaget har hanterats. Efter anrop av uncaughtException är applikationen i ett instabilt tillstånd och ytterligare operationer kan orsaka kaskadfel och dataskador.
Andra misstaget — att utföra långvariga operationer inuti hanteraren. Nätverksförfrågningar, skrivning av stora filer eller komplexa beräkningar hinner inte slutföras innan processen tvångsavslutas. Enligt Apple Technical Q&A QA1468 är försök att skicka en HTTP-förfrågan inuti hanteraren den främsta orsaken till förlorade crash-rapporter.
Tredje misstaget — ignorering av bakgrundstrådar. En Global Exception Handler som bara är inställd för huvudtråden skyddar inte mot krascher i korutiner, DispatchQueue, AsyncTask eller RxJava. På Android bör varje tråd ha sin egen hanterare — och setDefaultUncaughtExceptionHandler löser detta problem endast för trådar utan individuell hanterare.
Fjärde misstaget — avsaknad av reservplan för operativsystemssignaler. NSSetUncaughtExceptionHandler på iOS fångar inte SIGABRT, SIGSEGV och SIGBUS. För dessa signaler krävs separat installation av hanterare via sigaction API. Utvecklare får reda på detta först när applikationen kraschar utan någon crash-rapport.
Femte misstaget — loggning av konfidentiell data. E-postmeddelanden, auktoriseringstoken eller personuppgifter hamnar i crash-loggarna. Detta bryter mot GDPR och Apple App Store Review Guidelines. Filtrera alltid överförd data via regex eller en vitlista över tillåtna fält.
Vanliga frågor
Nej — efter anrop av Global Exception Handler är applikationens tillstånd odefinierat. Alla försök att fortsätta arbetet kan leda till dataskador. Den enda korrekta åtgärden är att spara crash-logg och avsluta processen.
Inte alla — på iOS fångar NSSetUncaughtExceptionHandler endast Objective-C-undantag. Swift-fel och operativsystemssignaler (SIGSEGV, SIGABRT) kräver separata hanterare. På Android fångar Thread.setDefaultUncaughtExceptionHandler alla RuntimeException men inte native-kodfel via JNI.
Spara en referens till föregående hanterare via Thread.getDefaultUncaughtExceptionHandler() innan du installerar din egen hanterare. I slutet av din hanterare, anropa previousHandler.uncaughtException(thread, throwable) — detta garanterar att Crashlytics eller Sentry får sina data.
För native-kod krävs signalhantering via sigaction() — SIGSEGV, SIGABRT, SIGBUS. På Android kan Google Breakpad eller Crashpad användas. På iOS från version 13 finns Signals API för hantering av mach-undantag.
Nej — installation av hanteraren påverkar endast vid undantagstillfället. Vid normal applikationsdrift finns ingen overhead. Den enda risken är minnesläcka om hanteraren håller en referens till Activity eller Context, vilket förhindrar deras sophämtning.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också