Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 39 additions & 6 deletions docs/crashlytics/android-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,37 @@ apply plugin: 'com.google.firebase.crashlytics'
// ..
```

## 4. (Optional) Enable Crashlytics NDK reporting
## 4. (Optional) Configure Crashlytics NDK and GWP-ASan support

### Enable NDK Crash Reporting

Crashlytics NDK reporting allows you to capture Native Development Kit crashes, e.g. in React Native this will capture
crashes originating from the Yoga layout engine.

Add the `firebaseCrashlytics` block line to the `android/app/build.gradle` file:
To enable NDK crash reporting, add the following to your `firebase.json` file:

```json
{
"react-native": {
"crashlytics_ndk_enabled": true
}
}
```

When `crashlytics_ndk_enabled` is set to `true`, React Native Firebase will automatically:
- Enable NDK crash reporting in the manifest
- Configure automatic native symbol upload for all release build variants

> **Note**: The automatic symbol upload configuration works with standard release builds and custom build flavors (e.g., `playRelease`, `premiumRelease`). Any build variant with "release" in its name will have symbol upload enabled.

If you need to manually configure symbol upload or override the automatic configuration, you can add the `firebaseCrashlytics` block to your `android/app/build.gradle` file:

```groovy
android {
// ...

buildTypes {
release {
/* Add the firebaseCrashlytics extension (by default,
* it's disabled to improve build speeds) and set
* nativeSymbolUploadEnabled to true along with a pointer to native libs. */

firebaseCrashlytics {
nativeSymbolUploadEnabled true
unstrippedNativeLibsDir 'build/intermediates/merged_native_libs/release/out/lib'
Expand All @@ -84,6 +98,25 @@ android {
}
```

### Configure GWP-ASan Mode

[GWP-ASan](https://developer.android.com/ndk/guides/gwp-asan) (GWP-AddressSanitizer) is a native memory allocator feature that helps detect heap memory errors. You can configure its behavior using `firebase.json`:

```json
{
"react-native": {
"crashlytics_gwp_asan_mode": "default"
}
}
```

Available values:
- `"default"` - The default behavior (system-determined, typically enabled for a small percentage of devices)
- `"never"` - Disable GWP-ASan completely
- `"always"` - Enable GWP-ASan on all devices (useful for testing, but not recommended for production due to performance impact)

> **Recommended**: Use `"default"` for production builds to get memory error detection with minimal performance impact.

## 5. Rebuild the project

Once the above steps have been completed, rebuild your Android project:
Expand Down
34 changes: 30 additions & 4 deletions docs/crashlytics/usage/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,21 +213,47 @@ Because you have stack traces readily available while you're debugging your app,
## Crashlytics NDK

React Native Firebase supports [Crashlytics NDK](https://firebase.google.com/docs/crashlytics/ndk-reports) reporting
which is enabled by default but will require a change as described in that link to enable symbol upload.
which allows Crashlytics to capture crashes originating from the Yoga layout engine used by React Native.

This allows Crashlytics to capture crashes originating from the Yoga layout engine used by React Native.
**Note:** NDK reporting is disabled by default due to memory usage concerns.

You can disable Crashlytics NDK in your `firebase.json` config.
### Enable NDK Reporting

To enable NDK crash reporting, add the following to your `firebase.json`:

```json
// <project-root>/firebase.json
{
"react-native": {
"crashlytics_ndk_enabled": true
}
}
```

When enabled, React Native Firebase will automatically:
- Enable NDK crash reporting in your Android app
- Configure automatic native symbol upload for all release build variants

For more details on Android setup, see the [Android Setup](/crashlytics/android-setup) documentation.

### Configure GWP-ASan

[GWP-ASan](https://developer.android.com/ndk/guides/gwp-asan) (GWP-AddressSanitizer) is a native memory allocator feature that helps detect heap memory errors. You can configure its behavior:

```json
// <project-root>/firebase.json
{
"react-native": {
"crashlytics_ndk_enabled": false
"crashlytics_gwp_asan_mode": "default"
}
}
```

Available values:
- `"default"` - System-determined (recommended for production)
- `"never"` - Disable GWP-ASan completely
- `"always"` - Enable on all devices (for testing only)

## Crashlytics Javascript stacktrace issue generation

React Native Crashlytics module by default installs a global javascript exception handler, and it records a crash with a javascript stack trace any time an unhandled javascript exception is thrown. Sometimes it is not desirable behavior since it might duplicate issues in combination with the default mode of javascript global exception handler chaining. We recommend leaving JS crashes enabled and turning off exception handler chaining. However, if you have special crash handling requirements, you may disable this behavior by setting the appropriate option to false:
Expand Down
94 changes: 94 additions & 0 deletions packages/crashlytics/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,25 @@ project.ext {
])
}

apply from: file('./../../app/android/firebase-json.gradle')

// Default to 'false' for the feature due to memory usage concerns
String crashlyticsNdkEnabled = 'false'
// Default to 'default' for GWP-ASan mode (other options: 'never', 'always')
String crashlyticsGwpAsanMode = 'default'

if (rootProject.ext && rootProject.ext.firebaseJson) {
def rnfbConfig = rootProject.ext.firebaseJson

// Allow users to opt-in to NDK crash reporting
if (rnfbConfig.isFlagEnabled('crashlytics_ndk_enabled', false) == true) {
crashlyticsNdkEnabled = 'true'
}

// Allow users to configure GWP-ASan mode: 'default', 'never', or 'always'
crashlyticsGwpAsanMode = rnfbConfig.getStringValue('crashlytics_gwp_asan_mode', 'default')
}

android {
def agpVersion = Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')[0].toInteger()
if (agpVersion >= 7) {
Expand All @@ -65,6 +84,10 @@ android {

defaultConfig {
multiDexEnabled = true
manifestPlaceholders = [
firebaseJsonCrashlyticsNdkEnabled: crashlyticsNdkEnabled,
firebaseJsonCrashlyticsGwpAsanMode: crashlyticsGwpAsanMode
]
}

buildFeatures {
Expand Down Expand Up @@ -100,3 +123,74 @@ ReactNative.shared.applyPackageVersion()
ReactNative.shared.applyDefaultExcludes()
ReactNative.module.applyAndroidVersions()
ReactNative.module.applyReactNativeDependency("api")

// Configure automatic NDK symbol upload for release variants if NDK is enabled
if (rootProject.ext && rootProject.ext.firebaseJson) {
def rnfbConfig = rootProject.ext.firebaseJson

if (rnfbConfig.isFlagEnabled('crashlytics_ndk_enabled', false) == true) {
rootProject.afterEvaluate {
// Find the app project (the one with com.android.application plugin)
def appProject = rootProject.subprojects.find {
it.plugins.hasPlugin('com.android.application')
}

if (appProject != null) {
appProject.afterEvaluate {
try {
def android = appProject.extensions.findByName('android')

if (android != null) {
// Try to configure all release-type variants
try {
android.applicationVariants.all { variant ->
// Match variants with 'release' in the name (case insensitive)
if (variant.name.toLowerCase().contains('release')) {
try {
// Access or create the firebaseCrashlytics extension for this variant
def buildType = android.buildTypes.findByName(variant.buildType.name)
if (buildType != null) {
buildType.configure {
// Check if firebaseCrashlytics extension exists
try {
firebaseCrashlytics {
nativeSymbolUploadEnabled = true
}
appProject.logger.info("RNFirebase: Enabled Crashlytics NDK symbol upload for build type '${variant.buildType.name}'")
} catch (Exception e) {
// Extension might not exist if Crashlytics plugin not applied
appProject.logger.warn("RNFirebase: Could not configure Crashlytics NDK symbol upload for build type '${variant.buildType.name}'. " +
"Ensure the Crashlytics Gradle plugin is applied in your app/build.gradle: ${e.message}")
}
}
}
} catch (Exception e) {
appProject.logger.warn("RNFirebase: Could not configure variant '${variant.name}': ${e.message}")
}
}
}
} catch (Exception e) {
// Fallback: just try to configure the 'release' build type directly
appProject.logger.info("RNFirebase: Using fallback approach for NDK symbol upload configuration")
try {
android.buildTypes.release {
firebaseCrashlytics {
nativeSymbolUploadEnabled = true
}
}
appProject.logger.info("RNFirebase: Enabled Crashlytics NDK symbol upload for 'release' build type")
} catch (Exception fallbackError) {
appProject.logger.warn("RNFirebase: Could not automatically enable Crashlytics NDK symbol upload. " +
"You may need to configure it manually in your app/build.gradle. " +
"See: https://firebase.google.com/docs/crashlytics/android/get-started-ndk#set-up-automatic-native-symbols-upload")
}
}
}
} catch (Exception e) {
appProject.logger.warn("RNFirebase: Failed to configure automatic Crashlytics NDK symbol upload: ${e.message}")
}
}
}
}
}
}
23 changes: 23 additions & 0 deletions packages/crashlytics/android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,29 @@
<meta-data
android:name="firebase_crashlytics_collection_enabled"
android:value="false" />

<!-- NDK crash reporting - disabled by default due to memory impact -->
<!-- Example (in Firebase.json): {
"react-native": {
"crashlytics_ndk_enabled": true
}
}
-->
<meta-data
android:name="firebase_crashlytics_ndk_enabled"
android:value="${firebaseJsonCrashlyticsNdkEnabled}" />

<!-- GWP-ASan mode - 'default', 'never', or 'always' -->
<!-- Example (in Firebase.json): {
"react-native": {
"crashlytics_gwp_asan_mode": "default"
}
}
-->
<meta-data
android:name="com.google.firebase.crashlytics.ndk.gwp_asan_mode"
android:value="${firebaseJsonCrashlyticsGwpAsanMode}" />

<provider
android:name="io.invertase.firebase.crashlytics.ReactNativeFirebaseCrashlyticsInitProvider"
android:authorities="${applicationId}.reactnativefirebasecrashlyticsinitprovider"
Expand Down
1 change: 1 addition & 0 deletions tests/firebase.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"app_check_token_auto_refresh": false,

"crashlytics_ndk_enabled": true,
"crashlytics_gwp_asan_mode": "default",
"crashlytics_debug_enabled": true,
"crashlytics_disable_auto_disabler": true,
"crashlytics_auto_collection_enabled": true,
Expand Down
Loading