Global Exception Handler — a centralized mechanism for catching unhandled exceptions that prevents mobile application crashes. According to Apple Developer, 2024, proper exception handling reduces crash occurrences by 40–60% and improves user experience. Without such a handler, any unhandled exception in a background thread leads to immediate app termination.
Key Takeaways
Global Exception Handler — is a centralized mechanism for catching exceptions that were not handled at the level of individual functions or modules of the application. In the context of mobile development, such a handler acts as the last line of defense before the process terminates abnormally.
iOS and Android provide built-in APIs for setting a global handler. Apple uses NSSetUncaughtExceptionHandler for the Objective-C environment, while Google offers Thread.setDefaultUncaughtExceptionHandler in Java/Kotlin. Both mechanisms catch exceptions that were not caught by try-catch constructs across all application threads.
According to Crashlytics (Google, 2024), about 25% of crashes occur due to unhandled exceptions in background threads — an area where Global Exception Handler is especially critical. Developers often focus on the UI thread, forgetting about asynchronous operations.
Using a global handler does not replace local error handling but complements it. The main task is to save maximum information about the application state at the moment of the exception and terminate gracefully.
The working mechanism of Global Exception Handler is based on intercepting operating system signals or runtime exceptions. When code throws an exception that is not caught by any try-catch block, control is transferred to a pre-registered handler.
On iOS, the handler is registered via NSSetUncaughtExceptionHandler and receives an NSException object with a full stack trace. On Android, Thread.setDefaultUncaughtExceptionHandler is used, which accepts Thread and Throwable — providing access to the exception type, message, and call stack.
After receiving crash data, the handler performs three mandatory actions: writing a log to local storage, sending a report to Crashlytics or Sentry, and properly terminating the application. According to Apple WWDC 2023, the handler’s execution time is limited to 5 seconds — after that, the system forcibly terminates the process.
For Swift applications starting from iOS 13, Signals API has been introduced, which handles not only exceptions but also operating system signals — SIGABRT, SIGSEGV, and SIGBUS, extending the handler’s coverage to low-level memory errors.
Implementation of a global handler on iOS requires setting a C-function via NSSetUncaughtExceptionHandler. The handler is called synchronously at the moment of an unhandled exception and receives the full error context.
void handleUncaughtException(NSException exception) {
NSDictionary userInfo = [exception userInfo];
NSArray stackTrace = [exception callStackSymbols];
NSString reason = [exception reason];
// Save crash log to local file
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);
}
An important feature of the iOS implementation: the handler catches only Objective-C exceptions. Swift errors using the throw-catch mechanism do not reach this handler — they require separate handling via Swift Error Handling. Starting from iOS 14, Apple recommends combining NSSetUncaughtExceptionHandler with Signals API for maximum coverage.
According to Apple Technical Note TN2151, after the handler is called, the application must terminate within 5 seconds. Any attempt to continue execution after returning from the handler leads to undefined behavior and a subsequent crash.
Android provides a more flexible mechanism for global exception handling via Thread.setDefaultUncaughtExceptionHandler. The handler receives a reference to the thread where the exception occurred and the Throwable object itself.
class GlobalExceptionHandler : Thread.UncaughtExceptionHandler {
override fun uncaughtException(thread: Thread, throwable: Throwable) {
// Save crash log to file
val stackTrace = throwable.stackTraceToString()
val crashLog = "CRASH: ${thread.name}\n${stackTrace}"
val file = File(context.cacheDir, "crash_log.txt")
file.writeText(crashLog)
// Send to Crashlytics
FirebaseCrashlytics.getInstance()
.recordException(throwable)
// Terminate process
android.os.Process.killProcess(
android.os.Process.myPid()
)
}
}
// Setup in Application.onCreate
class App : Application() {
override fun onCreate() {
super.onCreate()
Thread.setDefaultUncaughtExceptionHandler(
GlobalExceptionHandler()
)
}
}
A key difference of the Android implementation: each thread has its own handler, and setDefaultUncaughtExceptionHandler sets the handler for all threads that do not have an individual one assigned. This ensures global coverage — from the UI thread to background AsyncTask and coroutines.
On Android 12+, there is a limitation: after calling uncaughtException, the application must terminate within 100 milliseconds. If the handler performs long-running operations, the system may kill the process before the log is written. It is recommended to use a background service for sending crash reports.
The first rule — do not attempt to restore application operation after an unhandled exception. The application state after a crash is undefined, and continuing execution may lead to user data corruption.
Time limit — the main technical constraint of Global Exception Handler. On iOS it is 5 seconds, on Android — 100 milliseconds. Inside the handler, only a minimal set of data should be saved: exception type, call stack, and the state of a few key variables.
Sending network requests, writing to a database, and complex serialization should be deferred to a delayed mechanism — for example, save the log to a file and send it on the next application launch.
Crash-reporting services — Firebase Crashlytics, Sentry, Bugsnag — set their own global handler. If a developer sets a custom handler on top, they need to pass control to the crash-reporting system after their own actions. On Android, handler composition is used: execute your logic, then call the previous handler.
For Firebase Crashlytics, it is recommended not to set a custom Thread.setDefaultUncaughtExceptionHandler at all — the Crashlytics SDK does this automatically on initialization.
User context — in addition to the standard call stack, it is useful to log the application version, OS version, available memory size, and uptime before the crash. This data is critically important for reproducing and fixing the issue.
On iOS, NSSetUncaughtExceptionHandler can be used not only for writing but also for temporary data storage in NSUserDefaults with the synchronize flag — this guarantees persistence even upon immediate process termination.
Mandatory testing — the Global Exception Handler must be tested at every stage of CI/CD. On iOS, a test exception can be triggered via @throw NSException, on Android — via throw RuntimeException(). Verify that the handler is called, the log is saved, and the application terminates correctly.
According to Google I/O 2023, more than 30% of crashes in production occur on devices that the developer did not test — different Android versions, custom firmware, limited memory.
The first and most common mistake — attempting to continue application execution after handling an exception. After calling uncaughtException, the application is in an unstable state, and any further operations may cause cascading errors and data corruption.
The second mistake — performing long-running operations inside the handler. Network requests, writing large files, or complex computations do not complete before the process is forcibly terminated. According to Apple Technical Q&A QA1468, attempting to send an HTTP request inside the handler is the leading cause of lost crash reports.
The third mistake — ignoring background threads. A Global Exception Handler set only for the main thread does not protect against crashes in coroutines, DispatchQueue, AsyncTask, or RxJava. On Android, each thread should have its own handler — and setDefaultUncaughtExceptionHandler only solves this for threads without an individual handler.
The fourth mistake — lack of fallback for OS signals. NSSetUncaughtExceptionHandler on iOS does not catch SIGABRT, SIGSEGV, and SIGBUS. These signals require separate handler setup via sigaction API. Developers discover this only when the app crashes without a single crash report.
The fifth mistake — logging confidential data. Crash logs may contain emails, authorization tokens, or personal user data. This violates GDPR and Apple App Store Review Guidelines. Always filter transmitted data using regex or a whitelist of allowed fields.
Frequently Asked Questions
No — after a Global Exception Handler is invoked, the application state is undefined. Any attempt to continue execution may lead to data corruption. The only correct action is to save the crash log and terminate the process.
Not all — on iOS, NSSetUncaughtExceptionHandler catches only Objective-C exceptions. Swift errors and OS signals (SIGSEGV, SIGABRT) require separate handlers. On Android, Thread.setDefaultUncaughtExceptionHandler catches all RuntimeExceptions but not native code errors via JNI.
Save a reference to the previous handler via Thread.getDefaultUncaughtExceptionHandler() before setting your own. At the end of your handler, call previousHandler.uncaughtException(thread, throwable) — this ensures that Crashlytics or Sentry receive their data.
For native code, signal handling via sigaction() is required — SIGSEGV, SIGABRT, SIGBUS. On Android, you can use Google Breakpad or Crashpad. On iOS starting from version 13, Signals API is available for handling mach exceptions.
No — setting the handler only affects the moment an exception occurs. In normal application operation, there is no overhead. The only risk is a memory leak if the handler holds a reference to an Activity or Context, preventing garbage collection.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also