Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

Get Android NDK crash reports

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.

Before you begin

  1. 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.

  2. Recommended: To get features like crash-free users, breadcrumb logs, and velocity alerts, 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 > Project settings in the Firebase console.

    • If you're creating a new Firebase project, enable Google Analytics during the project creation workflow.

  3. Make sure you've clicked the Enable Crashlytics button for your app in the Crashlytics dashboard of the Firebase console.

Step 1: Add the Firebase Crashlytics SDK for NDK to your app

Using the Firebase Android BoM, declare the dependency for the Crashlytics NDK Android library in your module (app-level) Gradle file (usually app/build.gradle).

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.

Java

dependencies {
    // Import the BoM for the Firebase platform
    implementation platform('com.google.firebase:firebase-bom:28.4.2')

    // Declare 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 the Firebase Android libraries.

(Alternative) Declare 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 highly recommend using the BoM to manage library versions, which ensures that all versions are compatible.

dependencies {
    // Declare 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:18.2.3'
    implementation 'com.google.firebase:firebase-analytics:19.0.2'
}

Kotlin+KTX

dependencies {
    // Import the BoM for the Firebase platform
    implementation platform('com.google.firebase:firebase-bom:28.4.2')

    // Declare 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-ktx'
}

By using the Firebase Android BoM, your app will always use compatible versions of the Firebase Android libraries.

(Alternative) Declare 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 highly recommend using the BoM to manage library versions, which ensures that all versions are compatible.

dependencies {
    // Declare 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:18.2.3'
    implementation 'com.google.firebase:firebase-analytics-ktx:19.0.2'
}

Step 2: Add the Firebase Crashlytics plugin to your app

  1. In your project-level build.gradle file, add the Crashlytics Gradle plugin as a buildscript dependency.

    buildscript {
        repositories {
            // Check that you have Google's Maven repository (if not, add it).
            google()
        }
    
        dependencies {
            // ...
    
            // Check that you have the Google services Gradle plugin v4.3.2 or later
            // (if not, add it).
            classpath 'com.google.gms:google-services:4.3.10'
    
            // Add the Crashlytics Gradle plugin
            classpath 'com.google.firebase:firebase-crashlytics-gradle:2.7.1'
        }
    }
    
    allprojects {
        repositories {
            // Check that you have Google's Maven repository (if not, add it).
            google()
        }
    }
  2. In your app-level build.gradle file, apply the Crashlytics Gradle plugin:

    apply plugin: 'com.android.application'
    apply plugin: 'com.google.gms.google-services' // Google services Gradle plugin
    
    // Apply the Crashlytics Gradle plugin
    apply plugin: 'com.google.firebase.crashlytics'
    

Step 3: Add the firebaseCrashlytics extension to your build

In your module (app-level) Gradle file (usually app/build.gradle), add the firebaseCrashlytics extension.

Java

// ...

android {
  // ...
  buildTypes {
      release {
          // Add this extension
          firebaseCrashlytics {
              // Enable processing and uploading of native symbols to Crashlytics 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
          }
      }
  }
}

Kotlin+KTX

// ...

android {
  // ...
  buildTypes {
      release {
          // Add this extension
          firebaseCrashlytics {
              // Enable processing and uploading of native symbols to Crashlytics 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 your project to upload native symbols at build time

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.

  1. So that you can access this task, make sure that nativeSymbolUploadEnabled is set to true in your module (app-level) Gradle file.

  2. 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
    
  3. 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 readelf -n on each binary. If the build ID is absent, add -Wl,--build-id to your build system's flags to fix the problem.

Step 5 (optional): Upload symbols for library modules and external dependencies

The Crashlytics symbol upload task assumes that you're building your native libraries as part of your app module's Gradle build, using standard NDK build tools such as CMake.

However, if you're using a customized NDK build process within Gradle, or your native libraries are built in a library/feature module or provided by a third-party, you may need to explicitly specify the path to your unstripped libraries. The firebaseCrashlytics extension provides the property unstrippedNativeLibsDir to do this.

Add the following to your module (app-level) build.gradle file:

// ...

android {
    // ...
    buildTypes {
        release {
            firebaseCrashlytics {
                nativeSymbolUploadEnabled true
                unstrippedNativeLibsDir file("PATH/TO/UNSTRIPPED/DIRECTORY")
            }
        }
    }
}

The Crashlytics plugin will search the specified directory and all its subdirectories for native libraries with a .so extension. Crashlytics then extracts debugging symbols from all such libraries and uploads them to the Firebase servers.

Note the following about the unstrippedNativeLibsDir property:

  • You can specify any argument allowable for org.gradle.api.Project#files(Object...), including: java.lang.String, java.io.File, or org.gradle.api.file.FileCollection.

  • You can specify multiple directories for a single build flavor by providing a list or FileCollection instance.

Step 6 (optional): Enable Breakpad symbol file for symbolication

The Crashlytics Gradle plugin provides the following functionality:

  • Processes your unstripped native binaries to generate symbol files.
  • Uploads the generated symbol files to our servers to be used later when symbolicating native crashes.

The Crashlytics Gradle plugin supports two types of symbol file formats:
the Crashlytics symbol file (cSYM) and the Breakpad symbol file.

A Breakpad-generated symbol file contains more information than a Crashlytics-generated symbol file, including the Call Frame Info (CFI) which is used in the unwinding process to help calculate stack frames. Using CFI will result in higher-fidelity stack traces, especially for highly-optimized applications such as games and media apps.

You can enable use of the Breakpad-based symbol file generator in one of two ways:

  • Option 1: Enable via the firebaseCrashlytics extension in your build.gradle file

    Add the following to your app-level build.gradle file:

    android {
      // ...
      buildTypes {
        // ...
        release {
          // ...
          firebaseCrashlytics {
            // existing; required for either symbol file generator
            nativeSymbolUploadEnabled true
            // Add this optional new block to specify breakpad() or csym()
            symbolGenerator {
               breakpad()
            }
          }
        }
      }
    }
    

    To switch back to the default Crashlytics symbol file generator, you can do either of the following:

    • Omit the symbolGeneratorblock entirely, as the plugin uses the Crashlytics symbol file generator by default.

    • Keep the block, but change breakpad() to csym().

  • Option 2: Enable via a property line in your Gradle properties file

    You can use the com.google.firebase.crashlytics.symbolGenerator property to control which symbol file generator to use. Valid values for the property are breakpad or csym. If unspecified, the current default is equivalent to csym, though that may change in future versions.

    You can manually update your Gradle properties file or update the file via the command line. For example, to enable the Breakpad symbol file generator, specify the value of breakpad as shown in the following command:

    ./gradlew -Pcom.google.firebase.crashlytics.symbolGenerator=breakpad \
    app:assembleRelease app:uploadCrashlyticsSymbolFileRelease
    

Step 7: See your crash reports

Verify that Crashlytics is properly reporting NDK crashes by building your app, uploading symbols, and forcing a native crash. You’ll need to restart the app after it crashes for Crashlytics to send the report. You should see the crash in your Firebase console within a few minutes.

Troubleshooting

If you're seeing different stack traces in the Firebase console and in the logcat, refer to the Troubleshooting guide.

Next steps