If your Android app contains native libraries, you can enable full stack traces and detailed crash reports for your native code from Firebase Crashlytics with a few small updates to your app's build configuration.
This guide describes how to configure crash reporting with the Firebase Crashlytics SDK for NDK.
If you're looking for how to get started with Crashlytics in your Unity projects, check out the Unity Getting Started guide.
Before you begin
If you haven't already, add Firebase to your Android project. If you don't have an Android app, you can download a sample app.
Recommended: To automatically get breadcrumb logs to understand user actions leading up to a crash, non-fatal, or ANR event, you need to enable Google Analytics in your Firebase project.
If your existing Firebase project doesn't have Google Analytics enabled, you can enable Google Analytics from the Integrations tab of your
in the > Project settingsFirebase console. If you're creating a new Firebase project, enable Google Analytics during the project creation workflow.
Make sure your app has the following minimum required versions:
- Gradle 8.0
- Android Gradle plugin 8.1.0
- Google services Gradle plugin 4.4.1
Step 1: Add the Crashlytics SDK for NDK to your app
In your module (app-level) Gradle file (usually<project>/<app-module>/build.gradle.kts
or
<project>/<app-module>/build.gradle
),
add the dependency for the Crashlytics NDK library for Android. We recommend using the
Firebase Android BoM
to control library versioning.
For an optimal experience with Crashlytics, we recommend enabling Google Analytics in your Firebase project and adding the Firebase SDK for Google Analytics to your app.
dependencies { // Import the BoM for the Firebase platform implementation(platform("com.google.firebase:firebase-bom:33.7.0")) // Add the dependencies for the Crashlytics NDK and Analytics libraries // When using the BoM, you don't specify versions in Firebase library dependencies implementation("com.google.firebase:firebase-crashlytics-ndk") implementation("com.google.firebase:firebase-analytics") }
By using the Firebase Android BoM, your app will always use compatible versions of Firebase Android libraries.
(Alternative) Add Firebase library dependencies without using the BoM
If you choose not to use the Firebase BoM, you must specify each Firebase library version in its dependency line.
Note that if you use multiple Firebase libraries in your app, we strongly recommend using the BoM to manage library versions, which ensures that all versions are compatible.
dependencies { // Add the dependencies for the Crashlytics NDK and Analytics libraries // When NOT using the BoM, you must specify versions in Firebase library dependencies implementation("com.google.firebase:firebase-crashlytics-ndk:19.3.0") implementation("com.google.firebase:firebase-analytics:22.1.2") }
Step 2: Add the Crashlytics Gradle plugin to your app
In your root-level (project-level) Gradle file (
<project>/build.gradle.kts
or<project>/build.gradle
), add the Crashlytics Gradle plugin to theplugins
block:Kotlin
plugins { // Make sure that you have the AGP plugin 8.1+ dependency id("com.android.application") version "8.1.4" apply false // ... // Make sure that you have the Google services Gradle plugin 4.4.1+ dependency id("com.google.gms.google-services") version "4.4.2" apply false // Add the dependency for the Crashlytics Gradle plugin id("com.google.firebase.crashlytics") version "3.0.2" apply false }
Groovy
plugins { // Make sure that you have the AGP plugin 8.1+ dependency id 'com.android.application' version '8.1.4' apply false // ... // Make sure that you have the Google services Gradle plugin 4.4.1+ dependency id 'com.google.gms.google-services' version '4.4.2' apply false // Add the dependency for the Crashlytics Gradle plugin id 'com.google.firebase.crashlytics' version '3.0.2' apply false }
In your module (app-level) Gradle file (usually
<project>/<app-module>/build.gradle.kts
or<project>/<app-module>/build.gradle
), add the Crashlytics Gradle plugin:Kotlin
plugins { id("com.android.application") // ... // Make sure that you have the Google services Gradle plugin id("com.google.gms.google-services") // Add the Crashlytics Gradle plugin id("com.google.firebase.crashlytics") }
Groovy
plugins { id 'com.android.application' // ... // Make sure that you have the Google services Gradle plugin id 'com.google.gms.google-services' // Add the Crashlytics Gradle plugin id 'com.google.firebase.crashlytics' }
Step 3: Add the Crashlytics extension to your build
In your module (app-level) Gradle file
(usually <project>/<app-module>/build.gradle.kts
or
<project>/<app-module>/build.gradle
), configure the Crashlytics extension.
Kotlin
import com.google.firebase.crashlytics.buildtools.gradle.CrashlyticsExtension // ... android { // ... buildTypes { getByName("release") { // Add this extension configure<CrashlyticsExtension> { // Enable processing and uploading of native symbols to Firebase servers. // By default, this is disabled to improve build speeds. // This flag must be enabled to see properly-symbolicated native // stack traces in the Crashlytics dashboard. nativeSymbolUploadEnabled = true } } } }
Groovy
// ... android { // ... buildTypes { release { // Add this extension firebaseCrashlytics { // Enable processing and uploading of native symbols to Firebase servers. // By default, this is disabled to improve build speeds. // This flag must be enabled to see properly-symbolicated native // stack traces in the Crashlytics dashboard. nativeSymbolUploadEnabled true } } } }
Step 4: Set up automatic uploading of native symbols
To produce readable stack traces from NDK crashes, Crashlytics needs to know
about the symbols in your native binaries. The Crashlytics Gradle plugin
includes the uploadCrashlyticsSymbolFileBUILD_VARIANT
task to automate this process.
So that you can access the task for automated symbol uploading, make sure that
nativeSymbolUploadEnabled
is set totrue
in your module (app-level) Gradle file.For method names to appear in your stack traces, you must explicitly invoke the
uploadCrashlyticsSymbolFileBUILD_VARIANT
task after each build of your NDK library. For example:>./gradlew app:assembleBUILD_VARIANT\ app:uploadCrashlyticsSymbolFileBUILD_VARIANT
Both the Crashlytics SDK for NDK and the Crashlytics Gradle plugin depend on the presence of the GNU build ID within the native shared objects.
You can verify the presence of this ID by running
on each binary. If the build ID is absent, addreadelf -n
to your build system's flags to fix the problem.-Wl,--build-id
Step 5: Force a test crash to finish setup
To finish setting up Crashlytics and see initial data in the Crashlytics dashboard of the Firebase console, you need to force a test crash.
Add code to your app that you can use to force a test crash.
You can use the following code in your app's
MainActivity
to add a button to your app that, when pressed, causes a crash. The button is labeled "Test Crash".Kotlin
val crashButton = Button(this) crashButton.text = "Test Crash" crashButton.setOnClickListener { throw RuntimeException("Test Crash") // Force a crash } addContentView(crashButton, ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT))
Java
Button crashButton = new Button(this); crashButton.setText("Test Crash"); crashButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { throw new RuntimeException("Test Crash"); // Force a crash } }); addContentView(crashButton, new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
Build and run your app.
Force the test crash in order to send your app's first crash report:
Open your app from your test device or emulator.
In your app, press the "Test Crash" button that you added using the code above.
After your app crashes, restart it so that your app can send the crash report to Firebase.
Go to the Crashlytics dashboard of the Firebase console to see your test crash.
If you've refreshed the console and you're still not seeing the test crash after five minutes, enable debug logging to see if your app is sending crash reports.
And that's it! Crashlytics is now monitoring your app for crashes, and you
can view and investigate crash reports and statistics in the
Crashlytics dashboard.
Next steps
(Recommended) Get help debugging crashes caused by native memory errors by collecting GWP-ASan reports. These memory-related errors can be associated with memory corruption within your app, which is the leading cause of app security vulnerabilities. To take advantage of this debugging feature, make sure your app has GWP-ASan explicitly enabled and uses the latest Crashlytics SDK for NDK (v18.3.6+ or Firebase BoM v31.3.0+).
Customize your crash report setup by adding opt-in reporting, logs, keys, and tracking of non-fatal errors.
Integrate with Google Play so that you can filter your Android app's crash reports by Google Play track directly in the Crashlytics dashboard. This allows you to better focus your dashboard on specific builds.
Troubleshooting
If you're seeing different stack traces in the Firebase console and in the logcat, refer to the Troubleshooting guide.
Alternative options for uploading symbols
The main workflow on this page above is applicable for standard Gradle builds. However, some apps use a different configuration or tooling (for example a build process other than Gradle). In these situations, the following options might be helpful for successfully uploading symbols.
Option: Upload symbols for library modules and external dependencies
This option can be helpful in the following situations:
- If you use a customized NDK build process within Gradle
- If your native libraries are built in a library/feature module or provided by a third-party
- If the automatic symbol uploading task is failing or you're seeing unsymbolicated crashes in the dashboard
Option: Upload symbols for non-Gradle builds or inaccessible unstripped native libraries
This option can be helpful in the following situations:
If you use a build process other than Gradle
If your unstripped native libraries are provided to you in some way that they're not accessible during Gradle builds