From e889bacae2af989d98ec1bb37158e3ae72d5aa76 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Wed, 23 Sep 2026 09:58:18 +0200 Subject: [PATCH 1/2] feat(core): Expose native breadcrumb off-switches Expose enableAutoBreadcrumbTracking (iOS) and enableActivityLifecycleBreadcrumbs, enableAppLifecycleBreadcrumbs, enableSystemEventBreadcrumbs, enableAppComponentBreadcrumbs (Android) so apps can turn off the native breadcrumbs, which largely duplicate the JS breadcrumbs. All default to the native default (true). iOS is read by cocoa's dictionary parser; Android is mapped in RNSentryStart. Part of #6747. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 1 + .../java/io/sentry/react/RNSentryStart.java | 15 +++++ .../io/sentry/react/RNSentryStartTest.java | 46 +++++++++++++++ packages/core/etc/sentry-react-native.api.md | 5 ++ packages/core/src/js/options.ts | 57 +++++++++++++++++++ packages/core/test/wrapper.test.ts | 40 +++++++++++++ 6 files changed, 164 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2c0ae7794..dad09f2ab4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Expose `enableNetworkBreadcrumbs` (iOS) to disable native HTTP request breadcrumbs ([#6764](https://github.com/getsentry/sentry-react-native/pull/6764)) - Expose `enableNetworkEventBreadcrumbs` (Android) to disable native network connectivity breadcrumbs ([#6764](https://github.com/getsentry/sentry-react-native/pull/6764)) +- Expose native breadcrumb off-switches: `enableAutoBreadcrumbTracking` (iOS); `enableActivityLifecycleBreadcrumbs`, `enableAppLifecycleBreadcrumbs`, `enableSystemEventBreadcrumbs`, `enableAppComponentBreadcrumbs` (Android) ([#XXXX](https://github.com/getsentry/sentry-react-native/pull/XXXX)) ### Fixes diff --git a/packages/core/android/src/main/java/io/sentry/react/RNSentryStart.java b/packages/core/android/src/main/java/io/sentry/react/RNSentryStart.java index ccc9740c24..de3ec607e0 100644 --- a/packages/core/android/src/main/java/io/sentry/react/RNSentryStart.java +++ b/packages/core/android/src/main/java/io/sentry/react/RNSentryStart.java @@ -217,6 +217,21 @@ static void getSentryAndroidOptions( options.setEnableNetworkEventBreadcrumbs( rnOptions.getBoolean("enableNetworkEventBreadcrumbs")); } + if (rnOptions.hasKey("enableActivityLifecycleBreadcrumbs")) { + options.setEnableActivityLifecycleBreadcrumbs( + rnOptions.getBoolean("enableActivityLifecycleBreadcrumbs")); + } + if (rnOptions.hasKey("enableAppLifecycleBreadcrumbs")) { + options.setEnableAppLifecycleBreadcrumbs( + rnOptions.getBoolean("enableAppLifecycleBreadcrumbs")); + } + if (rnOptions.hasKey("enableSystemEventBreadcrumbs")) { + options.setEnableSystemEventBreadcrumbs(rnOptions.getBoolean("enableSystemEventBreadcrumbs")); + } + if (rnOptions.hasKey("enableAppComponentBreadcrumbs")) { + options.setEnableAppComponentBreadcrumbs( + rnOptions.getBoolean("enableAppComponentBreadcrumbs")); + } if (rnOptions.hasKey("spotlight")) { if (rnOptions.getType("spotlight") == ReadableType.Boolean) { options.setEnableSpotlight(rnOptions.getBoolean("spotlight")); diff --git a/packages/core/android/src/test/java/io/sentry/react/RNSentryStartTest.java b/packages/core/android/src/test/java/io/sentry/react/RNSentryStartTest.java index 1c4c63ae66..9853414399 100644 --- a/packages/core/android/src/test/java/io/sentry/react/RNSentryStartTest.java +++ b/packages/core/android/src/test/java/io/sentry/react/RNSentryStartTest.java @@ -8,6 +8,7 @@ import com.facebook.react.bridge.ReadableMap; import io.sentry.ILogger; import io.sentry.android.core.SentryAndroidOptions; +import java.util.function.Predicate; import org.junit.Test; /** @@ -47,4 +48,49 @@ public void enableNetworkEventBreadcrumbsPreservesNativeDefaultWhenUnset() { // Native default is true; omitting the RN option must not change it. assertTrue(optionsFrom(rnOptions).isEnableNetworkEventBreadcrumbs()); } + + /** + * Asserts the on-by-default breadcrumb off-switch {@code key} forwards both values onto {@code + * getter} and preserves the native default (true) when omitted. + */ + private static void assertBreadcrumbOffSwitchForwarded( + String key, Predicate getter) { + final ReadableMap forwardsFalse = mock(ReadableMap.class); + when(forwardsFalse.hasKey(key)).thenReturn(true); + when(forwardsFalse.getBoolean(key)).thenReturn(false); + assertFalse(getter.test(optionsFrom(forwardsFalse))); + + final ReadableMap forwardsTrue = mock(ReadableMap.class); + when(forwardsTrue.hasKey(key)).thenReturn(true); + when(forwardsTrue.getBoolean(key)).thenReturn(true); + assertTrue(getter.test(optionsFrom(forwardsTrue))); + + // Native default is true; omitting the RN option must not change it. + assertTrue(getter.test(optionsFrom(mock(ReadableMap.class)))); + } + + @Test + public void enableActivityLifecycleBreadcrumbsForwarded() { + assertBreadcrumbOffSwitchForwarded( + "enableActivityLifecycleBreadcrumbs", + SentryAndroidOptions::isEnableActivityLifecycleBreadcrumbs); + } + + @Test + public void enableAppLifecycleBreadcrumbsForwarded() { + assertBreadcrumbOffSwitchForwarded( + "enableAppLifecycleBreadcrumbs", SentryAndroidOptions::isEnableAppLifecycleBreadcrumbs); + } + + @Test + public void enableSystemEventBreadcrumbsForwarded() { + assertBreadcrumbOffSwitchForwarded( + "enableSystemEventBreadcrumbs", SentryAndroidOptions::isEnableSystemEventBreadcrumbs); + } + + @Test + public void enableAppComponentBreadcrumbsForwarded() { + assertBreadcrumbOffSwitchForwarded( + "enableAppComponentBreadcrumbs", SentryAndroidOptions::isEnableAppComponentBreadcrumbs); + } } diff --git a/packages/core/etc/sentry-react-native.api.md b/packages/core/etc/sentry-react-native.api.md index d19ba75f15..81d56e48d9 100644 --- a/packages/core/etc/sentry-react-native.api.md +++ b/packages/core/etc/sentry-react-native.api.md @@ -159,9 +159,13 @@ export interface BaseReactNativeOptions { attachViewHierarchy?: boolean; autoInitializeNativeSdk?: boolean; beforeScreenshot?: (event: Event_2, hint: EventHint) => boolean; + enableActivityLifecycleBreadcrumbs?: boolean; enableAnrFingerprinting?: boolean; + enableAppComponentBreadcrumbs?: boolean; enableAppHangTracking?: boolean; + enableAppLifecycleBreadcrumbs?: boolean; enableAppStartTracking?: boolean; + enableAutoBreadcrumbTracking?: boolean; enableAutoConsoleLogs?: boolean; enableAutoPerformanceTracing?: boolean; enableAutoSessionTracking?: boolean; @@ -179,6 +183,7 @@ export interface BaseReactNativeOptions { enableNetworkBreadcrumbs?: boolean; enableNetworkEventBreadcrumbs?: boolean; enableStallTracking?: boolean; + enableSystemEventBreadcrumbs?: boolean; enableTombstone?: boolean; // @internal enableTurboModuleTracking?: boolean; diff --git a/packages/core/src/js/options.ts b/packages/core/src/js/options.ts index 5b6a291d4f..8b735588a0 100644 --- a/packages/core/src/js/options.ts +++ b/packages/core/src/js/options.ts @@ -261,6 +261,63 @@ export interface BaseReactNativeOptions { */ enableNetworkEventBreadcrumbs?: boolean; + /** + * When enabled, the native iOS SDK automatically records breadcrumbs for system events + * (such as memory warnings, orientation changes, keyboard show/hide and screenshots). + * + * Disable this to stop the native layer from adding these system-event breadcrumbs and + * reduce breadcrumb noise. + * + * @default true + * @platform ios + */ + enableAutoBreadcrumbTracking?: boolean; + + /** + * When enabled, the native Android SDK records breadcrumbs for activity lifecycle events + * (`created`, `started`, `resumed`, `paused`, `stopped`, `destroyed`). + * + * Disable this to stop the native layer from adding activity lifecycle breadcrumbs. + * + * @default true + * @platform android + */ + enableActivityLifecycleBreadcrumbs?: boolean; + + /** + * When enabled, the native Android SDK records breadcrumbs for app lifecycle events + * (the app entering the foreground or background). + * + * Disable this to stop the native layer from adding app lifecycle breadcrumbs. + * + * @default true + * @platform android + */ + enableAppLifecycleBreadcrumbs?: boolean; + + /** + * When enabled, the native Android SDK records breadcrumbs for system events + * (such as low battery, low storage, device charging, screen on/off, airplane mode and + * `ACTION_*` intents). + * + * Disable this to stop the native layer from adding system-event breadcrumbs. + * + * @default true + * @platform android + */ + enableSystemEventBreadcrumbs?: boolean; + + /** + * When enabled, the native Android SDK records breadcrumbs for app component events + * (such as low-memory `onTrimMemory` callbacks and configuration/orientation changes). + * + * Disable this to stop the native layer from adding app component breadcrumbs. + * + * @default true + * @platform android + */ + enableAppComponentBreadcrumbs?: boolean; + /** * Use this feature to enable the Sentry MetricKit integration. * diff --git a/packages/core/test/wrapper.test.ts b/packages/core/test/wrapper.test.ts index 6d10e3120b..d536db278f 100644 --- a/packages/core/test/wrapper.test.ts +++ b/packages/core/test/wrapper.test.ts @@ -234,6 +234,46 @@ describe('Tests Native Wrapper', () => { expect(initParameter.enableNetworkEventBreadcrumbs).toBe(false); }); + test('forwards enableAutoBreadcrumbTracking to the Native SDK', async () => { + await NATIVE.initNativeSdk({ + dsn: VALID_DSN, + enableNative: true, + autoInitializeNativeSdk: true, + enableAutoBreadcrumbTracking: false, + devServerUrl: undefined, + defaultSidecarUrl: undefined, + mobileReplayOptions: undefined, + }); + + expect(RNSentry.initNativeSdk).toHaveBeenCalled(); + // @ts-expect-error mock value + const initParameter = RNSentry.initNativeSdk.mock.calls[0][0]; + expect(initParameter.enableAutoBreadcrumbTracking).toBe(false); + }); + + test('forwards the Android breadcrumb off-switches to the Native SDK', async () => { + await NATIVE.initNativeSdk({ + dsn: VALID_DSN, + enableNative: true, + autoInitializeNativeSdk: true, + enableActivityLifecycleBreadcrumbs: false, + enableAppLifecycleBreadcrumbs: false, + enableSystemEventBreadcrumbs: false, + enableAppComponentBreadcrumbs: false, + devServerUrl: undefined, + defaultSidecarUrl: undefined, + mobileReplayOptions: undefined, + }); + + expect(RNSentry.initNativeSdk).toHaveBeenCalled(); + // @ts-expect-error mock value + const initParameter = RNSentry.initNativeSdk.mock.calls[0][0]; + expect(initParameter.enableActivityLifecycleBreadcrumbs).toBe(false); + expect(initParameter.enableAppLifecycleBreadcrumbs).toBe(false); + expect(initParameter.enableSystemEventBreadcrumbs).toBe(false); + expect(initParameter.enableAppComponentBreadcrumbs).toBe(false); + }); + test('filter beforeSend when initializing Native SDK', async () => { await NATIVE.initNativeSdk({ dsn: VALID_DSN, From 9ac2000b3b41552a860638a5faa8a203edbee3c5 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Wed, 23 Sep 2026 09:58:51 +0200 Subject: [PATCH 2/2] docs: Point CHANGELOG entry at PR #6768 Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dad09f2ab4..29b8df1fc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ - Expose `enableNetworkBreadcrumbs` (iOS) to disable native HTTP request breadcrumbs ([#6764](https://github.com/getsentry/sentry-react-native/pull/6764)) - Expose `enableNetworkEventBreadcrumbs` (Android) to disable native network connectivity breadcrumbs ([#6764](https://github.com/getsentry/sentry-react-native/pull/6764)) -- Expose native breadcrumb off-switches: `enableAutoBreadcrumbTracking` (iOS); `enableActivityLifecycleBreadcrumbs`, `enableAppLifecycleBreadcrumbs`, `enableSystemEventBreadcrumbs`, `enableAppComponentBreadcrumbs` (Android) ([#XXXX](https://github.com/getsentry/sentry-react-native/pull/XXXX)) +- Expose native breadcrumb off-switches: `enableAutoBreadcrumbTracking` (iOS); `enableActivityLifecycleBreadcrumbs`, `enableAppLifecycleBreadcrumbs`, `enableSystemEventBreadcrumbs`, `enableAppComponentBreadcrumbs` (Android) ([#6768](https://github.com/getsentry/sentry-react-native/pull/6768)) ### Fixes