Skip to content

Commit fe14a8d

Browse files
committed
feat: gwp and ndk setup
1 parent ef52c5a commit fe14a8d

File tree

5 files changed

+160
-12
lines changed

5 files changed

+160
-12
lines changed

docs/crashlytics/android-setup.md

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,23 +57,37 @@ apply plugin: 'com.google.firebase.crashlytics'
5757
// ..
5858
```
5959

60-
## 4. (Optional) Enable Crashlytics NDK reporting
60+
## 4. (Optional) Configure Crashlytics NDK and GWP-ASan support
61+
62+
### Enable NDK Crash Reporting
6163

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

65-
Add the `firebaseCrashlytics` block line to the `android/app/build.gradle` file:
67+
To enable NDK crash reporting, add the following to your `firebase.json` file:
68+
69+
```json
70+
{
71+
"react-native": {
72+
"crashlytics_ndk_enabled": true
73+
}
74+
}
75+
```
76+
77+
When `crashlytics_ndk_enabled` is set to `true`, React Native Firebase will automatically:
78+
- Enable NDK crash reporting in the manifest
79+
- Configure automatic native symbol upload for all release build variants
80+
81+
> **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.
82+
83+
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:
6684

6785
```groovy
6886
android {
6987
// ...
7088
7189
buildTypes {
7290
release {
73-
/* Add the firebaseCrashlytics extension (by default,
74-
* it's disabled to improve build speeds) and set
75-
* nativeSymbolUploadEnabled to true along with a pointer to native libs. */
76-
7791
firebaseCrashlytics {
7892
nativeSymbolUploadEnabled true
7993
unstrippedNativeLibsDir 'build/intermediates/merged_native_libs/release/out/lib'
@@ -84,6 +98,25 @@ android {
8498
}
8599
```
86100

101+
### Configure GWP-ASan Mode
102+
103+
[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`:
104+
105+
```json
106+
{
107+
"react-native": {
108+
"crashlytics_gwp_asan_mode": "default"
109+
}
110+
}
111+
```
112+
113+
Available values:
114+
- `"default"` - The default behavior (system-determined, typically enabled for a small percentage of devices)
115+
- `"never"` - Disable GWP-ASan completely
116+
- `"always"` - Enable GWP-ASan on all devices (useful for testing, but not recommended for production due to performance impact)
117+
118+
> **Recommended**: Use `"default"` for production builds to get memory error detection with minimal performance impact.
119+
87120
## 5. Rebuild the project
88121

89122
Once the above steps have been completed, rebuild your Android project:

docs/crashlytics/usage/index.md

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,21 +213,47 @@ Because you have stack traces readily available while you're debugging your app,
213213
## Crashlytics NDK
214214

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

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

220-
You can disable Crashlytics NDK in your `firebase.json` config.
220+
### Enable NDK Reporting
221+
222+
To enable NDK crash reporting, add the following to your `firebase.json`:
223+
224+
```json
225+
// <project-root>/firebase.json
226+
{
227+
"react-native": {
228+
"crashlytics_ndk_enabled": true
229+
}
230+
}
231+
```
232+
233+
When enabled, React Native Firebase will automatically:
234+
- Enable NDK crash reporting in your Android app
235+
- Configure automatic native symbol upload for all release build variants
236+
237+
For more details on Android setup, see the [Android Setup](/crashlytics/android-setup) documentation.
238+
239+
### Configure GWP-ASan
240+
241+
[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:
221242

222243
```json
223244
// <project-root>/firebase.json
224245
{
225246
"react-native": {
226-
"crashlytics_ndk_enabled": false
247+
"crashlytics_gwp_asan_mode": "default"
227248
}
228249
}
229250
```
230251

252+
Available values:
253+
- `"default"` - System-determined (recommended for production)
254+
- `"never"` - Disable GWP-ASan completely
255+
- `"always"` - Enable on all devices (for testing only)
256+
231257
## Crashlytics Javascript stacktrace issue generation
232258

233259
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:

packages/crashlytics/android/build.gradle

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,19 @@ apply from: file('./../../app/android/firebase-json.gradle')
6161

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

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

68-
// Allow users to opt-in to NDK crash reporting (or whatever feature)
70+
// Allow users to opt-in to NDK crash reporting
6971
if (rnfbConfig.isFlagEnabled('crashlytics_ndk_enabled', false) == true) {
7072
crashlyticsNdkEnabled = 'true'
7173
}
74+
75+
// Allow users to configure GWP-ASan mode: 'default', 'never', or 'always'
76+
crashlyticsGwpAsanMode = rnfbConfig.getStringValue('crashlytics_gwp_asan_mode', 'default')
7277
}
7378

7479
android {
@@ -80,7 +85,8 @@ android {
8085
defaultConfig {
8186
multiDexEnabled = true
8287
manifestPlaceholders = [
83-
firebaseJsonCrashlyticsNdkEnabled: crashlyticsNdkEnabled
88+
firebaseJsonCrashlyticsNdkEnabled: crashlyticsNdkEnabled,
89+
firebaseJsonCrashlyticsGwpAsanMode: crashlyticsGwpAsanMode
8490
]
8591
}
8692

@@ -117,3 +123,74 @@ ReactNative.shared.applyPackageVersion()
117123
ReactNative.shared.applyDefaultExcludes()
118124
ReactNative.module.applyAndroidVersions()
119125
ReactNative.module.applyReactNativeDependency("api")
126+
127+
// Configure automatic NDK symbol upload for release variants if NDK is enabled
128+
if (rootProject.ext && rootProject.ext.firebaseJson) {
129+
def rnfbConfig = rootProject.ext.firebaseJson
130+
131+
if (rnfbConfig.isFlagEnabled('crashlytics_ndk_enabled', false) == true) {
132+
rootProject.afterEvaluate {
133+
// Find the app project (the one with com.android.application plugin)
134+
def appProject = rootProject.subprojects.find {
135+
it.plugins.hasPlugin('com.android.application')
136+
}
137+
138+
if (appProject != null) {
139+
appProject.afterEvaluate {
140+
try {
141+
def android = appProject.extensions.findByName('android')
142+
143+
if (android != null) {
144+
// Try to configure all release-type variants
145+
try {
146+
android.applicationVariants.all { variant ->
147+
// Match variants with 'release' in the name (case insensitive)
148+
if (variant.name.toLowerCase().contains('release')) {
149+
try {
150+
// Access or create the firebaseCrashlytics extension for this variant
151+
def buildType = android.buildTypes.findByName(variant.buildType.name)
152+
if (buildType != null) {
153+
buildType.configure {
154+
// Check if firebaseCrashlytics extension exists
155+
try {
156+
firebaseCrashlytics {
157+
nativeSymbolUploadEnabled = true
158+
}
159+
appProject.logger.info("RNFirebase: Enabled Crashlytics NDK symbol upload for build type '${variant.buildType.name}'")
160+
} catch (Exception e) {
161+
// Extension might not exist if Crashlytics plugin not applied
162+
appProject.logger.warn("RNFirebase: Could not configure Crashlytics NDK symbol upload for build type '${variant.buildType.name}'. " +
163+
"Ensure the Crashlytics Gradle plugin is applied in your app/build.gradle: ${e.message}")
164+
}
165+
}
166+
}
167+
} catch (Exception e) {
168+
appProject.logger.warn("RNFirebase: Could not configure variant '${variant.name}': ${e.message}")
169+
}
170+
}
171+
}
172+
} catch (Exception e) {
173+
// Fallback: just try to configure the 'release' build type directly
174+
appProject.logger.info("RNFirebase: Using fallback approach for NDK symbol upload configuration")
175+
try {
176+
android.buildTypes.release {
177+
firebaseCrashlytics {
178+
nativeSymbolUploadEnabled = true
179+
}
180+
}
181+
appProject.logger.info("RNFirebase: Enabled Crashlytics NDK symbol upload for 'release' build type")
182+
} catch (Exception fallbackError) {
183+
appProject.logger.warn("RNFirebase: Could not automatically enable Crashlytics NDK symbol upload. " +
184+
"You may need to configure it manually in your app/build.gradle. " +
185+
"See: https://firebase.google.com/docs/crashlytics/android/get-started-ndk#set-up-automatic-native-symbols-upload")
186+
}
187+
}
188+
}
189+
} catch (Exception e) {
190+
appProject.logger.warn("RNFirebase: Failed to configure automatic Crashlytics NDK symbol upload: ${e.message}")
191+
}
192+
}
193+
}
194+
}
195+
}
196+
}

packages/crashlytics/android/src/main/AndroidManifest.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@
1818
android:name="firebase_crashlytics_ndk_enabled"
1919
android:value="${firebaseJsonCrashlyticsNdkEnabled}" />
2020

21+
<!-- GWP-ASan mode - 'default', 'never', or 'always' -->
22+
<!-- Example (in Firebase.json): {
23+
"react-native": {
24+
"crashlytics_gwp_asan_mode": "default"
25+
}
26+
}
27+
-->
28+
<meta-data
29+
android:name="com.google.firebase.crashlytics.ndk.gwp_asan_mode"
30+
android:value="${firebaseJsonCrashlyticsGwpAsanMode}" />
31+
2132
<provider
2233
android:name="io.invertase.firebase.crashlytics.ReactNativeFirebaseCrashlyticsInitProvider"
2334
android:authorities="${applicationId}.reactnativefirebasecrashlyticsinitprovider"

tests/firebase.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"app_check_token_auto_refresh": false,
99

1010
"crashlytics_ndk_enabled": true,
11+
"crashlytics_gwp_asan_mode": "default",
1112
"crashlytics_debug_enabled": true,
1213
"crashlytics_disable_auto_disabler": true,
1314
"crashlytics_auto_collection_enabled": true,

0 commit comments

Comments
 (0)