You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

开发自定义崩溃上报器:如何捕获Android致命崩溃并上报至自定义后端

Great question! When building your own crash reporting pipeline for Android instead of relying on third-party tools like Firebase, the primary way to catch fatal crashes is by leveraging the Thread.UncaughtExceptionHandler interface. Let's walk through how to implement this effectively, along with key best practices:

1. Build a Custom UncaughtExceptionHandler

First, create a class that implements Thread.UncaughtExceptionHandler—this will be your crash handler that captures, processes, and reports the crash data. It's important to keep a reference to the system's default handler so you can let Android handle the crash cleanup after you've sent your report.

Here's a Kotlin example (Java implementation follows the same logic):

class CustomCrashHandler(private val defaultSystemHandler: Thread.UncaughtExceptionHandler) : Thread.UncaughtExceptionHandler {
    override fun uncaughtException(thread: Thread, throwable: Throwable) {
        // Step 1: Gather all relevant crash details
        val crashReport = StringBuilder().apply {
            append("Crash Timestamp: ${System.currentTimeMillis()}\n")
            append("Affected Thread: ${thread.name}\n")
            append("Full Stack Trace:\n${throwable.stackTraceToString()}\n")
            // Add metadata to make debugging easier
            append("App Version: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})\n")
            append("Device Model: ${Build.MODEL}\n")
            append("Android Version: ${Build.VERSION.RELEASE} (API ${Build.VERSION.SDK_INT})")
            // You can add more: user ID, current screen, network state, etc.
        }.toString()

        // Step 2: Send the report to your backend
        // WARNING: Never make network calls on the main thread here—use a background thread
        Thread {
            try {
                // Replace this with your actual API call logic
                val client = OkHttpClient()
                val request = Request.Builder()
                    .url("https://your-custom-backend.com/api/crash-reports")
                    .post(RequestBody.create(MediaType.parse("text/plain"), crashReport))
                    .build()
                client.newCall(request).execute()
            } catch (uploadError: Exception) {
                // If upload fails, store the report locally to retry later
                // Example: Save to SharedPreferences or a local file
                saveCrashReportLocally(crashReport)
            } finally {
                // Let the system handle the crash exit process
                defaultSystemHandler.uncaughtException(thread, throwable)
            }
        }.start()
    }

    private fun saveCrashReportLocally(report: String) {
        // Implement your local storage logic here
    }
}
2. Register the Handler in Your Application Class

To make your handler work across the entire app, register it in your custom Application class (this runs when your app starts up):

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        // Grab the system's default crash handler
        val defaultHandler = Thread.getDefaultUncaughtExceptionHandler()
        // Set our custom handler as the default
        Thread.setDefaultUncaughtExceptionHandler(CustomCrashHandler(defaultHandler))
    }
}

Don't forget to declare this Application class in your AndroidManifest.xml:

<application
    android:name=".MyApplication"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/Theme.MyApp">
    <!-- Your activities/services go here -->
</application>
3. Critical Best Practices
  • Background Thread for Uploads: The main thread is in a crashed state when your handler runs—never perform network operations or heavy work here. Always spin up a background thread to send the report.
  • Local Fallback for Failed Uploads: If the device is offline or your backend is down, save the crash report locally (SharedPreferences, SQLite, or a file) and retry the upload on the next app launch.
  • Obfuscation Handling: If you use ProGuard/R8 for code obfuscation, add these rules to keep stack traces readable:
    -keepattributes SourceFile,LineNumberTable
    -renamesourcefileattribute SourceFile
    
    Without these, your stack traces will show obfuscated class/method names, making debugging nearly impossible.
  • ANR Detection: Note that UncaughtExceptionHandler only catches uncaught exceptions. To detect ANRs (Application Not Responding), you'll need to monitor the /data/anr/traces.txt file using a FileObserver—though this has permission restrictions on newer Android versions (API 29+), so you'll need to handle that carefully.
  • Multi-Process Apps: If your app uses multiple processes, you'll need to register the handler in each process's initialization code, since the main process's handler won't apply to other processes.
4. Native Code Considerations

If your app includes native (C/C++) code, the above handler won't catch native crashes. For those, you'll need to use signal handlers (like signal(SIGSEGV, ...)) to capture the crash, generate a stack trace, and then report it. This requires more low-level work, but it's doable if you need full coverage.


内容的提问来源于stack exchange,提问作者zundi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:20:53