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

获取 Android NDK 崩溃报告

如果您的 Android 应用包含原生库,您可以通过对应用的构建配置进行一些小规模更新,利用 Firebase Crashlytics 实现原生代码的完整堆栈轨迹和详细的崩溃报告功能。本指南介绍如何使用全新 Firebase Crashlytics SDK 配置崩溃报告。

准备工作

首先,请设置 Crashlytics

  1. 在执行第 2 步(将 Firebase Crashlytics 插件添加到您的应用)时,请确保您的应用使用的是 Crashlytics Gradle 插件 v2.4.0 及更高版本,这可保证仅使用未剥离的二进制文件上传符号,以生成符号化解析的崩溃报告。

第 1 步:更新 Gradle 配置

在您的应用级 build.gradle 中,声明 Crashlytics NDK 运行时依赖项:

Java

apply plugin: 'com.android.application'
apply plugin: 'com.google.firebase.crashlytics'

dependencies {
  // ...

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

  // Declare the dependency for the Firebase Crashlytics NDK library.
  // If you previously declared the Firebase Crashlytics dependency, replace it.
  // When using the BoM, you don't specify versions in Firebase library dependencies
  implementation 'com.google.firebase:firebase-crashlytics'
  implementation 'com.google.firebase:firebase-crashlytics-ndk'
  implementation 'com.google.firebase:firebase-analytics'
}

// …
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
          }
      }
  }
}

通过使用 Firebase Android BoM,可确保您的应用始终使用 Firebase Android 库的兼容版本。

(替代方法) 在不使用 BoM 的情况下声明 Firebase 库依赖项

如果您选择不使用 Firebase BoM,则必须在其依赖项行中指定每个 Firebase 库版本。

请注意,如果您在应用中使用多个 Firebase 库,我们强烈建议您使用 BoM 来管理库版本,以确保所有版本都兼容。

  dependencies {
      // Declare the dependency for the Firebase Crashlytics NDK library.
      // If you previously declared the Firebase Crashlytics dependency, replace it.
      // When NOT using the BoM, you must specify versions in Firebase library dependencies
      implementation 'com.google.firebase:firebase-crashlytics:18.2.1'
      implementation 'com.google.firebase:firebase-crashlytics-ndk:18.2.1'
      implementation 'com.google.firebase:firebase-analytics:19.0.1'
  }
  

Kotlin+KTX

apply plugin: 'com.android.application'
apply plugin: 'com.google.firebase.crashlytics'

dependencies {
  // ...

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

  // Declare the dependency for the Firebase Crashlytics NDK library.
  // If you previously declared the Firebase Crashlytics dependency, replace it.
  // When using the BoM, you don't specify versions in Firebase library dependencies
  implementation 'com.google.firebase:firebase-crashlytics-ktx'
  implementation 'com.google.firebase:firebase-crashlytics-ndk'
  implementation 'com.google.firebase:firebase-analytics-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
          }
      }
  }
}

通过使用 Firebase Android BoM,可确保您的应用始终使用 Firebase Android 库的兼容版本。

(替代方法) 在不使用 BoM 的情况下声明 Firebase 库依赖项

如果您选择不使用 Firebase BoM,则必须在其依赖项行中指定每个 Firebase 库版本。

请注意,如果您在应用中使用多个 Firebase 库,我们强烈建议您使用 BoM 来管理库版本,以确保所有版本都兼容。

  dependencies {
      // Declare the dependency for the Firebase Crashlytics NDK library.
      // If you previously declared the Firebase Crashlytics dependency, replace it.
      // When NOT using the BoM, you must specify versions in Firebase library dependencies
      implementation 'com.google.firebase:firebase-crashlytics-ktx:18.2.1'
      implementation 'com.google.firebase:firebase-crashlytics-ndk:18.2.1'
      implementation 'com.google.firebase:firebase-analytics-ktx:19.0.1'
  }
  

Crashlytics NDK 版本 17.3.0 特别要求:如果您的应用使用 targetSdkLevel 30 或更高版本,您还必须将以下代码添加到您的 AndroidManifest.xml 中,从而在应用中停用指针标记功能:

<application android:allowNativeHeapPointerTagging="false">
...
</application>

如需了解详情,请参阅针对已标记指针的开发者支持

第 2 步:启用原生符号上传

如需生成可读的 NDK 崩溃堆栈轨迹,Crashlytics 需要了解原生二进制文件中的符号。我们的 Gradle 插件包含 uploadCrashlyticsSymbolFileBUILD_VARIANT 任务,可自动完成此过程(如需访问此任务,请确保将 nativeSymbolUploadEnabled 设置为 true)。

如需在堆栈轨迹中显示方法名称,您必须在每次构建 NDK 库后明确调用 uploadCrashlyticsSymbolFileBUILD_VARIANT 任务。例如:

>./gradlew app:assembleBUILD_VARIANT\
           app:uploadCrashlyticsSymbolFileBUILD_VARIANT

Crashlytics NDK v17.3.0+ 和 Gradle 插件 v2.4.1+ 要求原生共享对象中存在 GNU 构建 ID。您可以通过在每个二进制文件上运行 readelf -n 来验证此 ID 是否存在。如果此构建 ID 不存在,请在构建系统的标志中添加 -Wl,--build-id 来解决此问题。

第 3 步(可选):为库模块和外部依赖项上传符号

我们的符号上传任务假设您使用 CMake 之类的标准 NDK 构建工具在应用模块的 Gradle 构建过程中构建原生库。如果您在 Gradle 中使用自定义 NDK 构建流程,或者您的原生库是在库/功能模块中构建的或由第三方提供,那么您可能需要明确指定未剥离的库的路径。firebaseCrashlytics 扩展程序提供 unstrippedNativeLibsDir 属性来执行此操作。

将以下内容添加到您的应用级 build.gradle 文件:

// …
android {
    // ...
    buildTypes {
        release {
            firebaseCrashlytics {
                nativeSymbolUploadEnabled true
                unstrippedNativeLibsDir file("path/to/unstripped/dir")
            }
        }
    }
}

Crashlytics 插件将在指定的目录及其所有子目录中搜索扩展名为 .so 的原生库。 Crashlytics 会从所有这些库中提取调试符号,并将其上传到 Firebase 服务器。

unstrippedNativeLibsDir 属性接受 org.gradle.api.Project#files(Object...) 允许使用的任何参数,包括 java.lang.Stringjava.io.Fileorg.gradle.api.file.FileCollection。您可以通过提供列表或 FileCollection 实例来为单个构建变种指定多个目录。

第 4 步(可选):自定义 NDK 崩溃报告

您可以视需要在 C++ 代码中包含 crashlytics.h 头文件,以将元数据(如日志、自定义键和用户 ID)添加到 NDK 崩溃报告中。 Firebase Android SDK GitHub 代码库中提供了仅可作为头文件的 C++ 库形式的 crashlytics.h。 请阅读该头文件中的注释,了解有关使用 NDK C++ API 的说明。

第 5 步(可选):启用 Breakpad 符号文件进行符号化解析

Crashlytics Gradle 插件提供以下功能:

  • 处理未剥离的原生二进制文件,以生成符号文件。
  • 将生成的符号文件上传到我们的服务器,以便在之后对原生代码崩溃进行符号化解析时使用。

Crashlytics Gradle 插件支持两种类型的符号文件格式:
Crashlytics 符号文件 (cSYM) 和 Breakpad 符号文件。

与 Crashlytics 生成的符号文件相比,Breakpad 生成的符号文件包含更多信息,包括用于在展开过程中帮助计算堆栈帧的调用帧信息 (CFI)。使用 CFI 将产生较高保真度的堆栈轨迹,特别是对于游戏和媒体应用等高度优化的应用而言。

您可以通过以下两种方式中的任意一种使用基于 Breakpad 的符号文件生成器

  • 方案 1:通过 build.gradle 文件中的 firebaseCrashlytics 扩展启用

    将以下内容添加到您的应用级 build.gradle 文件:

    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()
            }
          }
        }
      }
    }
    

    要切换回默认的 Crashlytics 符号文件生成器,您可以执行以下任一操作:

    • 完全省略 symbolGenerator 代码块,因为该插件默认使用 Crashlytics 符号文件生成器。

    • 保留该代码块,但将 breakpad() 更改为 csym()

  • 方案 2:通过 Gradle 属性文件中的属性行启用

    您可以使用 com.google.firebase.crashlytics.symbolGenerator 属性来控制要使用的符号文件生成器。此属性的有效值是 breakpadcsym。如果未指定,当前默认值等同于 csym,但可能会在未来的版本中发生变化。

    您可以手动更新 Gradle 属性文件,也可以通过命令行更新此文件。例如,如需启用 Breakpad 符号文件生成器,请指定 breakpad 值,如以下命令所示:

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

第 6 步:查看崩溃报告

通过构建应用、上传符号并强制造成原生代码崩溃来验证 Crashlytics 是否正确报告 NDK 崩溃。在应用崩溃以便 Crashlytics 发送报告后,您将需要重启应用。 您应该会在几分钟内在 Firebase 控制台中看到崩溃。

问题排查

如果您在 Firebase 控制台和 logcat 中看到的堆栈轨迹不同,请参阅问题排查指南