diff --git a/CHANGELOG.md b/CHANGELOG.md index adc39a8519..f1f677ac53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,11 @@ ## Unreleased -### Internal +### Performance - Probe class availability without initializing the class during SDK init ([#5635](https://github.com/getsentry/sentry-java/pull/5635)) - Cache reflective class lookups and avoid double-probing during SDK init ([#5636](https://github.com/getsentry/sentry-java/pull/5636)) +- Only probe for Compose classes during init when user interaction tracking or view hierarchy capture is enabled ([#5637](https://github.com/getsentry/sentry-java/pull/5637)) ## 8.45.0 diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java index 5704cf7d7d..5bc91e10bd 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java @@ -211,15 +211,18 @@ static void initializeIntegrationsAndProcessors( final @NotNull LazyEvaluator isAndroidXScrollViewAvailable = loadClass.isClassAvailableLazy("androidx.core.view.ScrollingView", options); - final boolean isComposeUpstreamAvailable = - loadClass.isClassAvailable(COMPOSE_CLASS_NAME, options); - if (options.getGestureTargetLocators().isEmpty()) { + // Gated behind the features that actually consume these so the Compose class lookups only run + // when user interaction tracking or view hierarchy capture is enabled. Repeated COMPOSE_CLASS + // probes across both blocks are deduplicated by LoadClass's cache. + final boolean isUserInteractionEnabled = + options.isEnableUserInteractionBreadcrumbs() || options.isEnableUserInteractionTracing(); + if (isUserInteractionEnabled && options.getGestureTargetLocators().isEmpty()) { final List gestureTargetLocators = new ArrayList<>(2); gestureTargetLocators.add(new AndroidViewGestureTargetLocator(isAndroidXScrollViewAvailable)); final boolean isComposeAvailable = - (isComposeUpstreamAvailable + (loadClass.isClassAvailable(COMPOSE_CLASS_NAME, options) && loadClass.isClassAvailable( SENTRY_COMPOSE_GESTURE_INTEGRATION_CLASS_NAME, options)); @@ -229,8 +232,9 @@ static void initializeIntegrationsAndProcessors( options.setGestureTargetLocators(gestureTargetLocators); } - if (options.getViewHierarchyExporters().isEmpty() - && isComposeUpstreamAvailable + if (options.isAttachViewHierarchy() + && options.getViewHierarchyExporters().isEmpty() + && loadClass.isClassAvailable(COMPOSE_CLASS_NAME, options) && loadClass.isClassAvailable( SENTRY_COMPOSE_VIEW_HIERARCHY_INTEGRATION_CLASS_NAME, options)) { diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt index f8724d286f..65e0452cb9 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt @@ -806,6 +806,51 @@ class AndroidOptionsInitializerTest { assertTrue { fixture.sentryOptions.gestureTargetLocators[1] is ComposeGestureTargetLocator } } + @Test + fun `does not set gesture target locators when user interaction tracking is disabled`() { + fixture.sentryOptions.isEnableUserInteractionBreadcrumbs = false + fixture.sentryOptions.isEnableUserInteractionTracing = false + + fixture.initSutWithClassLoader( + classesToLoad = + listOf( + AndroidOptionsInitializer.COMPOSE_CLASS_NAME, + AndroidOptionsInitializer.SENTRY_COMPOSE_GESTURE_INTEGRATION_CLASS_NAME, + ) + ) + + assertTrue { fixture.sentryOptions.gestureTargetLocators.isEmpty() } + } + + @Test + fun `does not set compose view hierarchy exporter when attachViewHierarchy is disabled`() { + // attachViewHierarchy defaults to false + fixture.initSutWithClassLoader( + classesToLoad = + listOf( + AndroidOptionsInitializer.COMPOSE_CLASS_NAME, + AndroidOptionsInitializer.SENTRY_COMPOSE_VIEW_HIERARCHY_INTEGRATION_CLASS_NAME, + ) + ) + + assertTrue { fixture.sentryOptions.viewHierarchyExporters.isEmpty() } + } + + @Test + fun `sets compose view hierarchy exporter when attachViewHierarchy is enabled and compose is available`() { + fixture.sentryOptions.isAttachViewHierarchy = true + + fixture.initSutWithClassLoader( + classesToLoad = + listOf( + AndroidOptionsInitializer.COMPOSE_CLASS_NAME, + AndroidOptionsInitializer.SENTRY_COMPOSE_VIEW_HIERARCHY_INTEGRATION_CLASS_NAME, + ) + ) + + assertTrue { fixture.sentryOptions.viewHierarchyExporters.size == 1 } + } + @Test fun `AndroidMemoryCollector is set to options`() { fixture.initSut()