From f6996bba01df9401062ddb4ebab7aa1dc842b304 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 2 Jul 2026 06:37:37 +0200 Subject: [PATCH 01/17] build: Raise minimum AGP to 9.1.1 for Android 17 toolchain prep Bump the default AGP fallback to 9.2.1, refresh the AGP-compat matrix, and add AGP 9 migration opt-outs until we adopt built-in Kotlin and the new DSL. Includes AGP 9 compatibility fixes for replay and compose modules. Co-authored-by: Cursor --- .github/workflows/agp-matrix.yml | 2 +- AGENTS.md | 6 ++++++ build.gradle.kts | 19 +++++++++++++++++++ buildSrc/src/main/java/Config.kt | 2 +- gradle.properties | 5 ++++- sentry-android-distribution/build.gradle.kts | 5 +++++ sentry-android-replay/build.gradle.kts | 5 +---- .../replay/video/SimpleVideoEncoder.kt | 2 +- sentry-compose/build.gradle.kts | 2 -- 9 files changed, 38 insertions(+), 10 deletions(-) diff --git a/.github/workflows/agp-matrix.yml b/.github/workflows/agp-matrix.yml index 1d2a3bbb56..a662ef2159 100644 --- a/.github/workflows/agp-matrix.yml +++ b/.github/workflows/agp-matrix.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - agp: [ '8.7.0','8.8.0','8.9.0' ] + agp: [ '9.1.1', '9.2.0', '9.2.1' ] integrations: [ true, false ] name: AGP Matrix Release - AGP ${{ matrix.agp }} - Integrations ${{ matrix.integrations }} diff --git a/AGENTS.md b/AGENTS.md index ec2ef62974..47cdfca208 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,6 +24,12 @@ The project uses **Gradle** with Kotlin DSL. Key build files: - `buildSrc/` and `build-logic/` - Custom build logic and plugins - `Makefile` - High-level build commands +### Android toolchain (AGP 9) +- **Minimum AGP:** 9.1.1 (fallback in `buildSrc/src/main/java/Config.kt`, currently 9.2.1) +- **Minimum Gradle:** 9.4.1 (wrapper in `gradle/wrapper/gradle-wrapper.properties`) +- SDK levels live in `gradle/libs.versions.toml` (`compileSdk`, `targetSdk`, `minSdk`) +- **AGP 9 migration:** `gradle.properties` sets `android.builtInKotlin=false` and `android.newDsl=false` until we remove `kotlin-android` and adopt built-in Kotlin / new DSL (required before AGP 10) + ## Essential Commands ### Development Workflow diff --git a/build.gradle.kts b/build.gradle.kts index 55b5a71a1e..b28f5f80f4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import com.android.build.gradle.AppExtension +import com.android.build.gradle.LibraryExtension import com.vanniktech.maven.publish.JavaLibrary import com.vanniktech.maven.publish.JavadocJar import com.vanniktech.maven.publish.MavenPublishBaseExtension @@ -113,6 +115,23 @@ allprojects { subprojects { apply { plugin("io.sentry.spotless") } + pluginManager.withPlugin("com.android.library") { + extensions.configure { + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + } + } + pluginManager.withPlugin("com.android.application") { + extensions.configure { + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + } + } + plugins.withId(Config.QualityPlugins.detektPlugin) { configure { buildUponDefaultConfig = true diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index f0e2e9baf8..7575670a38 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -1,6 +1,6 @@ object Config { - val AGP = System.getenv("VERSION_AGP") ?: "8.13.1" + val AGP = System.getenv("VERSION_AGP") ?: "9.2.1" val kotlinStdLib = "stdlib-jdk8" val kotlinStdLibVersionAndroid = "1.9.24" val kotlinTestJunit = "test-junit" diff --git a/gradle.properties b/gradle.properties index 91122c1141..a91a392c88 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,10 @@ org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled # AndroidX required by AGP >= 3.6.x android.useAndroidX=true -android.experimental.lint.version=8.13.1 +# AGP 9+ migration opt-outs until we remove kotlin-android plugin and adopt built-in Kotlin. +android.builtInKotlin=false +android.newDsl=false +android.experimental.lint.version=9.2.1 # Release information versionName=8.48.0 diff --git a/sentry-android-distribution/build.gradle.kts b/sentry-android-distribution/build.gradle.kts index 2d23bf3ab7..a318cfaffd 100644 --- a/sentry-android-distribution/build.gradle.kts +++ b/sentry-android-distribution/build.gradle.kts @@ -12,6 +12,11 @@ android { defaultConfig { minSdk = libs.versions.minSdk.get().toInt() } buildFeatures { buildConfig = false } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + testOptions { unitTests.apply { isReturnDefaultValues = true diff --git a/sentry-android-replay/build.gradle.kts b/sentry-android-replay/build.gradle.kts index 8d0f63797a..e9fc373c0d 100644 --- a/sentry-android-replay/build.gradle.kts +++ b/sentry-android-replay/build.gradle.kts @@ -25,10 +25,7 @@ android { buildFeatures { compose = true } - composeOptions { - kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get() - useLiveLiterals = false - } + composeOptions { kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get() } buildTypes { getByName("debug") { consumerProguardFiles("proguard-rules.pro") } diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/video/SimpleVideoEncoder.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/video/SimpleVideoEncoder.kt index de14aadaaa..04d573d793 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/video/SimpleVideoEncoder.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/video/SimpleVideoEncoder.kt @@ -81,7 +81,7 @@ internal class SimpleVideoEncoder( val videoCapabilities = mediaCodec.codecInfo.getCapabilitiesForType(muxerConfig.mimeType).videoCapabilities - if (!videoCapabilities.bitrateRange.contains(bitRate)) { + if (videoCapabilities != null && !videoCapabilities.bitrateRange.contains(bitRate)) { options.logger.log( DEBUG, "Encoder doesn't support the provided bitRate: $bitRate, the value will be clamped to the closest one", diff --git a/sentry-compose/build.gradle.kts b/sentry-compose/build.gradle.kts index c45a431b1b..52f84ec138 100644 --- a/sentry-compose/build.gradle.kts +++ b/sentry-compose/build.gradle.kts @@ -87,8 +87,6 @@ android { buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") } - sourceSets["main"].apply { manifest.srcFile("src/androidMain/AndroidManifest.xml") } - buildTypes { getByName("debug") { consumerProguardFiles("proguard-rules.pro") } getByName("release") { consumerProguardFiles("proguard-rules.pro") } From 789bbaacd9998c15bab3e3680c06b70f4538defe Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 2 Jul 2026 06:38:46 +0200 Subject: [PATCH 02/17] build(android): Bump compileSdk and targetSdk to API 37 (Android 17) Officially support Android 17 by raising SDK levels, resolving AGP 9.2 lint findings, pinning Robolectric tests that lag compileSdk 37, and updating Sauce device-farm configs. Co-authored-by: Cursor --- .sauce/sentry-uitest-android-benchmark-lite.yml | 4 ++-- .sauce/sentry-uitest-android-ui.yml | 4 ++-- AGENTS.md | 3 ++- CHANGELOG.md | 2 +- gradle/libs.versions.toml | 4 ++-- .../core/internal/util/SentryFrameMetricsCollector.java | 2 +- .../src/main/res/layout/sentry_dialog_user_feedback.xml | 3 +++ .../sentry/android/distribution/UpdateResponseParserTest.kt | 2 ++ .../sentry-uitest-android-benchmark/build.gradle.kts | 2 -- .../sentry-uitest-android/build.gradle.kts | 3 +-- .../java/io/sentry/android/replay/ScreenshotRecorderTest.kt | 2 ++ .../src/test/java/io/sentry/android/replay/util/ViewsTest.kt | 2 ++ 12 files changed, 20 insertions(+), 13 deletions(-) diff --git a/.sauce/sentry-uitest-android-benchmark-lite.yml b/.sauce/sentry-uitest-android-benchmark-lite.yml index fec4a141de..4844f10054 100644 --- a/.sauce/sentry-uitest-android-benchmark-lite.yml +++ b/.sauce/sentry-uitest-android-benchmark-lite.yml @@ -18,13 +18,13 @@ espresso: suites: - - name: "Android 15 Benchmark lite (api 35)" + - name: "Android 17 Benchmark lite (api 37)" testOptions: clearPackageData: true useTestOrchestrator: true devices: - name: ".*" - platformVersion: "15" + platformVersion: "17" artifacts: download: diff --git a/.sauce/sentry-uitest-android-ui.yml b/.sauce/sentry-uitest-android-ui.yml index a00ee10614..fbf7a2380f 100644 --- a/.sauce/sentry-uitest-android-ui.yml +++ b/.sauce/sentry-uitest-android-ui.yml @@ -18,13 +18,13 @@ espresso: testApp: ./sentry-android-integration-tests/sentry-uitest-android/build/outputs/apk/androidTest/release/sentry-uitest-android-release-androidTest.apk suites: - - name: "Android 15 Ui test (api 35)" + - name: "Android 17 Ui test (api 37)" testOptions: clearPackageData: true useTestOrchestrator: true devices: - name: ".*" - platformVersion: "15" + platformVersion: "17" # Controls what artifacts to fetch when the suite on Sauce Cloud has finished. artifacts: diff --git a/AGENTS.md b/AGENTS.md index 47cdfca208..ae416bbad7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,7 +24,8 @@ The project uses **Gradle** with Kotlin DSL. Key build files: - `buildSrc/` and `build-logic/` - Custom build logic and plugins - `Makefile` - High-level build commands -### Android toolchain (AGP 9) +### Android toolchain (compileSdk 37 / Android 17) +- **Minimum Android Studio:** Panda 3 | 2025.3.3 Patch 1 or newer ([platform requirements](https://developer.android.com/build/releases/about-agp)) - **Minimum AGP:** 9.1.1 (fallback in `buildSrc/src/main/java/Config.kt`, currently 9.2.1) - **Minimum Gradle:** 9.4.1 (wrapper in `gradle/wrapper/gradle-wrapper.properties`) - SDK levels live in `gradle/libs.versions.toml` (`compileSdk`, `targetSdk`, `minSdk`) diff --git a/CHANGELOG.md b/CHANGELOG.md index cdc3e33452..2efd57dde7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ ### Features - Session Replay: Record segment names (transaction names) ([#5763](https://github.com/getsentry/sentry-java/pull/5763)) - +- Officially supports Android 17. Updated targetSdk and compileSdk to API 37 - Add `io.sentry:sentry-opentelemetry-bom` to align Sentry OpenTelemetry modules with tested OpenTelemetry dependencies ([#5629](https://github.com/getsentry/sentry-java/pull/5629)) - Spring Boot Gradle plugin: add the Sentry BOM to `dependencyManagement`; explicit imports are applied after Spring Boot's implicit BOM ```kotlin diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1fd275d06f..c396e03596 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -47,8 +47,8 @@ springboot4 = "4.1.0" sqldelight = "2.3.2" # Android -targetSdk = "36" -compileSdk = "36" +targetSdk = "37" +compileSdk = "37" minSdk = "21" [plugins] diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollector.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollector.java index 4f76a51e86..4f6b486f3a 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollector.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollector.java @@ -91,7 +91,7 @@ public SentryFrameMetricsCollector( } @SuppressWarnings("deprecation") - @SuppressLint({"NewApi", "PrivateApi"}) + @SuppressLint({"NewApi", "PrivateApi", "DiscouragedPrivateApi"}) public SentryFrameMetricsCollector( final @NotNull Context context, final @NotNull ILogger logger, diff --git a/sentry-android-core/src/main/res/layout/sentry_dialog_user_feedback.xml b/sentry-android-core/src/main/res/layout/sentry_dialog_user_feedback.xml index 722a0d5cf3..370c37fa0e 100644 --- a/sentry-android-core/src/main/res/layout/sentry_dialog_user_feedback.xml +++ b/sentry-android-core/src/main/res/layout/sentry_dialog_user_feedback.xml @@ -47,6 +47,7 @@ android:layout_height="wrap_content" android:hint="Your Name" android:inputType="textPersonName" + android:autofillHints="name" android:background="@drawable/sentry_edit_text_border" android:paddingHorizontal="8dp" android:layout_below="@id/sentry_dialog_user_feedback_txt_name" /> @@ -66,6 +67,7 @@ android:layout_height="wrap_content" android:hint="your.email@example.org" android:inputType="textEmailAddress" + android:autofillHints="emailAddress" android:background="@drawable/sentry_edit_text_border" android:paddingHorizontal="8dp" android:layout_below="@id/sentry_dialog_user_feedback_txt_email" /> @@ -85,6 +87,7 @@ android:layout_height="wrap_content" android:lines="6" android:inputType="textMultiLine" + android:importantForAutofill="no" android:gravity="top|left" android:hint="What's the bug? What did you expect?" android:background="@drawable/sentry_edit_text_border" diff --git a/sentry-android-distribution/src/test/java/io/sentry/android/distribution/UpdateResponseParserTest.kt b/sentry-android-distribution/src/test/java/io/sentry/android/distribution/UpdateResponseParserTest.kt index 3f1d083919..f1817a39f3 100644 --- a/sentry-android-distribution/src/test/java/io/sentry/android/distribution/UpdateResponseParserTest.kt +++ b/sentry-android-distribution/src/test/java/io/sentry/android/distribution/UpdateResponseParserTest.kt @@ -8,8 +8,10 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) +@Config(sdk = [35]) class UpdateResponseParserTest { private lateinit var options: SentryOptions diff --git a/sentry-android-integration-tests/sentry-uitest-android-benchmark/build.gradle.kts b/sentry-android-integration-tests/sentry-uitest-android-benchmark/build.gradle.kts index 459c1653fa..1dc351715a 100644 --- a/sentry-android-integration-tests/sentry-uitest-android-benchmark/build.gradle.kts +++ b/sentry-android-integration-tests/sentry-uitest-android-benchmark/build.gradle.kts @@ -69,8 +69,6 @@ android { lint { warningsAsErrors = true checkDependencies = true - // Suppress OldTargetApi: lint 8.13.1 expects API 37 but we target 36 - disable += "OldTargetApi" // We run a full lint analysis as build part in CI, so skip vital checks for assemble tasks. checkReleaseBuilds = false diff --git a/sentry-android-integration-tests/sentry-uitest-android/build.gradle.kts b/sentry-android-integration-tests/sentry-uitest-android/build.gradle.kts index 1d725b0b59..4c71888314 100644 --- a/sentry-android-integration-tests/sentry-uitest-android/build.gradle.kts +++ b/sentry-android-integration-tests/sentry-uitest-android/build.gradle.kts @@ -56,6 +56,7 @@ android { buildTypes { getByName("release") { isMinifyEnabled = true + isShrinkResources = true proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") signingConfig = signingConfigs.getByName("debug") // to be able to run release mode testProguardFiles("proguard-rules.pro") @@ -67,8 +68,6 @@ android { lint { warningsAsErrors = true checkDependencies = true - // Suppress OldTargetApi: lint 8.13.1 expects API 37 but we target 36 - disable += "OldTargetApi" // We run a full lint analysis as build part in CI, so skip vital checks for assemble tasks. checkReleaseBuilds = false diff --git a/sentry-android-replay/src/test/java/io/sentry/android/replay/ScreenshotRecorderTest.kt b/sentry-android-replay/src/test/java/io/sentry/android/replay/ScreenshotRecorderTest.kt index 2818eeb353..00b5866666 100644 --- a/sentry-android-replay/src/test/java/io/sentry/android/replay/ScreenshotRecorderTest.kt +++ b/sentry-android-replay/src/test/java/io/sentry/android/replay/ScreenshotRecorderTest.kt @@ -14,8 +14,10 @@ import kotlin.test.Test import kotlin.test.assertTrue import org.junit.runner.RunWith import org.mockito.kotlin.mock +import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) +@Config(sdk = [35]) class ScreenshotRecorderTest { internal class Fixture() { diff --git a/sentry-android-replay/src/test/java/io/sentry/android/replay/util/ViewsTest.kt b/sentry-android-replay/src/test/java/io/sentry/android/replay/util/ViewsTest.kt index 2eaa8411cf..3d5f6a9c50 100644 --- a/sentry-android-replay/src/test/java/io/sentry/android/replay/util/ViewsTest.kt +++ b/sentry-android-replay/src/test/java/io/sentry/android/replay/util/ViewsTest.kt @@ -20,8 +20,10 @@ import kotlin.test.assertTrue import org.junit.runner.RunWith import org.robolectric.Robolectric.buildActivity import org.robolectric.Shadows.shadowOf +import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) +@Config(sdk = [35]) class ViewsTest { @BeforeTest From 44934c7549d06806c42530d7aac064b0a5632fd4 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 2 Jul 2026 12:03:33 +0200 Subject: [PATCH 03/17] fix(ci): Unblock Build workflow snapshot upload and Danger changelog Add the PR link Danger requires in CHANGELOG.md and rerun screenshot unit tests when Gradle cache omits the test-snapshots output directory. Co-authored-by: Cursor --- .github/workflows/build.yml | 7 ++++++- CHANGELOG.md | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e396ef9717..adbddbf2d6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,7 +52,12 @@ jobs: # Skip on PRs from forks, which don't have access to the upload secret if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} run: | - sentry-cli build snapshots ./sentry-android-core/build/test-snapshots \ + SNAPSHOT_DIR=./sentry-android-core/build/test-snapshots + if [ ! -d "$SNAPSHOT_DIR" ]; then + echo "Snapshot directory missing (likely Gradle cache hit); running screenshot tests" + ./gradlew :sentry-android-core:testDebugUnitTest --tests io.sentry.android.core.ScreenshotEventProcessorTest + fi + sentry-cli build snapshots "$SNAPSHOT_DIR" \ --app-id sentry-android-core env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 2efd57dde7..f3c117fb49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ ### Features - Session Replay: Record segment names (transaction names) ([#5763](https://github.com/getsentry/sentry-java/pull/5763)) -- Officially supports Android 17. Updated targetSdk and compileSdk to API 37 +- Officially supports Android 17. Updated targetSdk and compileSdk to API 37 ([#5675](https://github.com/getsentry/sentry-java/pull/5675)) - Add `io.sentry:sentry-opentelemetry-bom` to align Sentry OpenTelemetry modules with tested OpenTelemetry dependencies ([#5629](https://github.com/getsentry/sentry-java/pull/5629)) - Spring Boot Gradle plugin: add the Sentry BOM to `dependencyManagement`; explicit imports are applied after Spring Boot's implicit BOM ```kotlin From b9698856eea644b463fc7abfce6a3c5d2ab65b30 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 2 Jul 2026 12:27:48 +0200 Subject: [PATCH 04/17] fix(ci): Harden snapshot upload after Gradle cache hits Use :test with --no-configuration-cache when snapshots are missing, and skip the sentry-cli upload with a warning instead of failing the job. Co-authored-by: Cursor --- .github/workflows/build.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index adbddbf2d6..6d21871886 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -55,10 +55,15 @@ jobs: SNAPSHOT_DIR=./sentry-android-core/build/test-snapshots if [ ! -d "$SNAPSHOT_DIR" ]; then echo "Snapshot directory missing (likely Gradle cache hit); running screenshot tests" - ./gradlew :sentry-android-core:testDebugUnitTest --tests io.sentry.android.core.ScreenshotEventProcessorTest + ./gradlew :sentry-android-core:test \ + --tests io.sentry.android.core.ScreenshotEventProcessorTest \ + --rerun-tasks --no-configuration-cache + fi + if [ -d "$SNAPSHOT_DIR" ]; then + sentry-cli build snapshots "$SNAPSHOT_DIR" --app-id sentry-android-core + else + echo "::warning::Snapshot directory still missing after rerun; skipping upload" fi - sentry-cli build snapshots "$SNAPSHOT_DIR" \ - --app-id sentry-android-core env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_ORG: sentry-sdks From cf0c9c43781a16f9f02edd9006f414571353709e Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 2 Jul 2026 12:55:26 +0200 Subject: [PATCH 05/17] fix(ci): Skip snapshot upload when Gradle cache omits test output Rerunning a single Android unit-test task after check is unreliable with configuration cache. Warn and skip the sentry-cli upload instead of failing the Build workflow when the directory is absent. Co-authored-by: Cursor --- .github/workflows/build.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6d21871886..e65aa33901 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,16 +53,10 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} run: | SNAPSHOT_DIR=./sentry-android-core/build/test-snapshots - if [ ! -d "$SNAPSHOT_DIR" ]; then - echo "Snapshot directory missing (likely Gradle cache hit); running screenshot tests" - ./gradlew :sentry-android-core:test \ - --tests io.sentry.android.core.ScreenshotEventProcessorTest \ - --rerun-tasks --no-configuration-cache - fi if [ -d "$SNAPSHOT_DIR" ]; then sentry-cli build snapshots "$SNAPSHOT_DIR" --app-id sentry-android-core else - echo "::warning::Snapshot directory still missing after rerun; skipping upload" + echo "::warning::Snapshot directory missing after check (likely Gradle cache hit); skipping upload" fi env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} From cc72ae462f6a658d43f5c0ba9be4e6aef4b12fb1 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 16 Jul 2026 11:17:52 +0200 Subject: [PATCH 06/17] build: Drop CI, tooling, and distribution changes from API bump Restore build.yml, Sauce configs, AGENTS.md, root build.gradle.kts, and the distribution module build script to main so this PR carries only the core Android 17 API bump. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/build.yml | 8 ++------ .../sentry-uitest-android-benchmark-lite.yml | 4 ++-- .sauce/sentry-uitest-android-ui.yml | 4 ++-- AGENTS.md | 7 ------- build.gradle.kts | 19 ------------------- sentry-android-distribution/build.gradle.kts | 5 ----- 6 files changed, 6 insertions(+), 41 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e65aa33901..e396ef9717 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,12 +52,8 @@ jobs: # Skip on PRs from forks, which don't have access to the upload secret if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} run: | - SNAPSHOT_DIR=./sentry-android-core/build/test-snapshots - if [ -d "$SNAPSHOT_DIR" ]; then - sentry-cli build snapshots "$SNAPSHOT_DIR" --app-id sentry-android-core - else - echo "::warning::Snapshot directory missing after check (likely Gradle cache hit); skipping upload" - fi + sentry-cli build snapshots ./sentry-android-core/build/test-snapshots \ + --app-id sentry-android-core env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_ORG: sentry-sdks diff --git a/.sauce/sentry-uitest-android-benchmark-lite.yml b/.sauce/sentry-uitest-android-benchmark-lite.yml index 4844f10054..fec4a141de 100644 --- a/.sauce/sentry-uitest-android-benchmark-lite.yml +++ b/.sauce/sentry-uitest-android-benchmark-lite.yml @@ -18,13 +18,13 @@ espresso: suites: - - name: "Android 17 Benchmark lite (api 37)" + - name: "Android 15 Benchmark lite (api 35)" testOptions: clearPackageData: true useTestOrchestrator: true devices: - name: ".*" - platformVersion: "17" + platformVersion: "15" artifacts: download: diff --git a/.sauce/sentry-uitest-android-ui.yml b/.sauce/sentry-uitest-android-ui.yml index fbf7a2380f..a00ee10614 100644 --- a/.sauce/sentry-uitest-android-ui.yml +++ b/.sauce/sentry-uitest-android-ui.yml @@ -18,13 +18,13 @@ espresso: testApp: ./sentry-android-integration-tests/sentry-uitest-android/build/outputs/apk/androidTest/release/sentry-uitest-android-release-androidTest.apk suites: - - name: "Android 17 Ui test (api 37)" + - name: "Android 15 Ui test (api 35)" testOptions: clearPackageData: true useTestOrchestrator: true devices: - name: ".*" - platformVersion: "17" + platformVersion: "15" # Controls what artifacts to fetch when the suite on Sauce Cloud has finished. artifacts: diff --git a/AGENTS.md b/AGENTS.md index ae416bbad7..ec2ef62974 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,13 +24,6 @@ The project uses **Gradle** with Kotlin DSL. Key build files: - `buildSrc/` and `build-logic/` - Custom build logic and plugins - `Makefile` - High-level build commands -### Android toolchain (compileSdk 37 / Android 17) -- **Minimum Android Studio:** Panda 3 | 2025.3.3 Patch 1 or newer ([platform requirements](https://developer.android.com/build/releases/about-agp)) -- **Minimum AGP:** 9.1.1 (fallback in `buildSrc/src/main/java/Config.kt`, currently 9.2.1) -- **Minimum Gradle:** 9.4.1 (wrapper in `gradle/wrapper/gradle-wrapper.properties`) -- SDK levels live in `gradle/libs.versions.toml` (`compileSdk`, `targetSdk`, `minSdk`) -- **AGP 9 migration:** `gradle.properties` sets `android.builtInKotlin=false` and `android.newDsl=false` until we remove `kotlin-android` and adopt built-in Kotlin / new DSL (required before AGP 10) - ## Essential Commands ### Development Workflow diff --git a/build.gradle.kts b/build.gradle.kts index b28f5f80f4..55b5a71a1e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,3 @@ -import com.android.build.gradle.AppExtension -import com.android.build.gradle.LibraryExtension import com.vanniktech.maven.publish.JavaLibrary import com.vanniktech.maven.publish.JavadocJar import com.vanniktech.maven.publish.MavenPublishBaseExtension @@ -115,23 +113,6 @@ allprojects { subprojects { apply { plugin("io.sentry.spotless") } - pluginManager.withPlugin("com.android.library") { - extensions.configure { - compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } - } - } - pluginManager.withPlugin("com.android.application") { - extensions.configure { - compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } - } - } - plugins.withId(Config.QualityPlugins.detektPlugin) { configure { buildUponDefaultConfig = true diff --git a/sentry-android-distribution/build.gradle.kts b/sentry-android-distribution/build.gradle.kts index a318cfaffd..2d23bf3ab7 100644 --- a/sentry-android-distribution/build.gradle.kts +++ b/sentry-android-distribution/build.gradle.kts @@ -12,11 +12,6 @@ android { defaultConfig { minSdk = libs.versions.minSdk.get().toInt() } buildFeatures { buildConfig = false } - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - testOptions { unitTests.apply { isReturnDefaultValues = true From 4efbdd103d5c06e267bad5d7cb2d4dcc0d77b2d9 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 16 Jul 2026 11:29:53 +0200 Subject: [PATCH 07/17] build(android): Pin Kotlin JVM toolchain to 8 across modules Set jvmToolchain(8) for the navigation, replay, sqlite, and apache http client modules so the Kotlin compile toolchain is fixed under the Android 17 build, and import JvmTarget/KotlinVersion instead of using fully-qualified references. Co-Authored-By: Claude Opus 4.8 (1M context) --- sentry-android-navigation/build.gradle.kts | 10 +++++++--- sentry-android-replay/build.gradle.kts | 9 ++++++--- sentry-android-sqlite/build.gradle.kts | 9 ++++++--- sentry-apache-http-client-5/build.gradle.kts | 12 +++++++----- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/sentry-android-navigation/build.gradle.kts b/sentry-android-navigation/build.gradle.kts index eaa204b386..3a64fa6fec 100644 --- a/sentry-android-navigation/build.gradle.kts +++ b/sentry-android-navigation/build.gradle.kts @@ -1,4 +1,7 @@ import io.gitlab.arturbosch.detekt.Detekt +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion plugins { id("com.android.library") @@ -24,9 +27,10 @@ android { } kotlin { - compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 - compilerOptions.languageVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9 - compilerOptions.apiVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9 + jvmToolchain(8) + compilerOptions.jvmTarget = JVM_1_8 + compilerOptions.languageVersion = KotlinVersion.KOTLIN_1_9 + compilerOptions.apiVersion = KotlinVersion.KOTLIN_1_9 } testOptions { diff --git a/sentry-android-replay/build.gradle.kts b/sentry-android-replay/build.gradle.kts index e9fc373c0d..f64caf0758 100644 --- a/sentry-android-replay/build.gradle.kts +++ b/sentry-android-replay/build.gradle.kts @@ -1,4 +1,6 @@ import io.gitlab.arturbosch.detekt.Detekt +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask plugins { @@ -33,9 +35,10 @@ android { } kotlin { - compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 - compilerOptions.languageVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9 - compilerOptions.apiVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9 + jvmToolchain(8) + compilerOptions.jvmTarget = JvmTarget.JVM_1_8 + compilerOptions.languageVersion = KotlinVersion.KOTLIN_1_9 + compilerOptions.apiVersion = KotlinVersion.KOTLIN_1_9 } testOptions { diff --git a/sentry-android-sqlite/build.gradle.kts b/sentry-android-sqlite/build.gradle.kts index 6e0275b29b..f3c668e70d 100644 --- a/sentry-android-sqlite/build.gradle.kts +++ b/sentry-android-sqlite/build.gradle.kts @@ -1,4 +1,6 @@ import io.gitlab.arturbosch.detekt.Detekt +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion plugins { id("com.android.library") @@ -24,9 +26,10 @@ android { } kotlin { - compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 - compilerOptions.languageVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9 - compilerOptions.apiVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9 + jvmToolchain(8) + compilerOptions.jvmTarget = JvmTarget.JVM_1_8 + compilerOptions.languageVersion = KotlinVersion.KOTLIN_1_9 + compilerOptions.apiVersion = KotlinVersion.KOTLIN_1_9 } testOptions { diff --git a/sentry-apache-http-client-5/build.gradle.kts b/sentry-apache-http-client-5/build.gradle.kts index 984974bae9..40419c3b3d 100644 --- a/sentry-apache-http-client-5/build.gradle.kts +++ b/sentry-apache-http-client-5/build.gradle.kts @@ -1,5 +1,6 @@ import net.ltgt.gradle.errorprone.errorprone -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion plugins { `java-library` @@ -10,10 +11,11 @@ plugins { alias(libs.plugins.gradle.versions) } -tasks.withType().configureEach { - compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 - compilerOptions.languageVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9 - compilerOptions.apiVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9 +kotlin { + jvmToolchain(8) + compilerOptions.jvmTarget = JvmTarget.JVM_1_8 + compilerOptions.languageVersion = KotlinVersion.KOTLIN_1_9 + compilerOptions.apiVersion = KotlinVersion.KOTLIN_1_9 } dependencies { From 375488c7db5d4f836d3a8ff30edac36f049ae606 Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Thu, 16 Jul 2026 09:32:32 +0000 Subject: [PATCH 08/17] Format code --- sentry-android-navigation/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/sentry-android-navigation/build.gradle.kts b/sentry-android-navigation/build.gradle.kts index 3a64fa6fec..8d6d49f923 100644 --- a/sentry-android-navigation/build.gradle.kts +++ b/sentry-android-navigation/build.gradle.kts @@ -1,5 +1,4 @@ import io.gitlab.arturbosch.detekt.Detekt -import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 import org.jetbrains.kotlin.gradle.dsl.KotlinVersion From 5ae12d41991292fe131a489504f33ede9e07fb0b Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 16 Jul 2026 11:37:04 +0200 Subject: [PATCH 09/17] build(android): Pin Kotlin JVM toolchain to 8 for fragment and timber Add jvmToolchain(8) to the fragment and timber modules and import JvmTarget/KotlinVersion instead of using fully-qualified references, matching the other Android modules. Co-Authored-By: Claude Opus 4.8 (1M context) --- sentry-android-fragment/build.gradle.kts | 9 ++++++--- sentry-android-timber/build.gradle.kts | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/sentry-android-fragment/build.gradle.kts b/sentry-android-fragment/build.gradle.kts index 1bd182d618..594f6acdee 100644 --- a/sentry-android-fragment/build.gradle.kts +++ b/sentry-android-fragment/build.gradle.kts @@ -1,4 +1,6 @@ import io.gitlab.arturbosch.detekt.Detekt +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion plugins { id("com.android.library") @@ -24,9 +26,10 @@ android { } kotlin { - compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 - compilerOptions.languageVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9 - compilerOptions.apiVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9 + jvmToolchain(8) + compilerOptions.jvmTarget = JvmTarget.JVM_1_8 + compilerOptions.languageVersion = KotlinVersion.KOTLIN_1_9 + compilerOptions.apiVersion = KotlinVersion.KOTLIN_1_9 } testOptions { diff --git a/sentry-android-timber/build.gradle.kts b/sentry-android-timber/build.gradle.kts index d8f8431bef..ba81b02871 100644 --- a/sentry-android-timber/build.gradle.kts +++ b/sentry-android-timber/build.gradle.kts @@ -1,4 +1,6 @@ import io.gitlab.arturbosch.detekt.Detekt +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion plugins { id("com.android.library") @@ -31,9 +33,10 @@ android { } kotlin { - compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 - compilerOptions.languageVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9 - compilerOptions.apiVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9 + jvmToolchain(8) + compilerOptions.jvmTarget = JvmTarget.JVM_1_8 + compilerOptions.languageVersion = KotlinVersion.KOTLIN_1_9 + compilerOptions.apiVersion = KotlinVersion.KOTLIN_1_9 } testOptions { From 58caca0e0d8e6cf7b91b92fa66e5d9eb9a6d3535 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 16 Jul 2026 11:50:50 +0200 Subject: [PATCH 10/17] build(android): Pin Kotlin JVM toolchain to 8 for compose Co-Authored-By: Claude Opus 4.8 (1M context) --- sentry-compose/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/sentry-compose/build.gradle.kts b/sentry-compose/build.gradle.kts index 52f84ec138..4bda19693b 100644 --- a/sentry-compose/build.gradle.kts +++ b/sentry-compose/build.gradle.kts @@ -15,6 +15,7 @@ plugins { } kotlin { + jvmToolchain(8) explicitApi() androidTarget { From 7591fb7d22c72c3d812f4959c1c7ee2f22bb16de Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 16 Jul 2026 11:56:57 +0200 Subject: [PATCH 11/17] build(android): Bump uitest module Kotlin jvmTarget to 11 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../sentry-uitest-android-benchmark/build.gradle.kts | 3 ++- .../sentry-uitest-android-critical/build.gradle.kts | 3 ++- .../sentry-uitest-android-macrobenchmark/build.gradle.kts | 4 +++- .../sentry-uitest-android/build.gradle.kts | 3 ++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/sentry-android-integration-tests/sentry-uitest-android-benchmark/build.gradle.kts b/sentry-android-integration-tests/sentry-uitest-android-benchmark/build.gradle.kts index 1dc351715a..c3ca2379a7 100644 --- a/sentry-android-integration-tests/sentry-uitest-android-benchmark/build.gradle.kts +++ b/sentry-android-integration-tests/sentry-uitest-android-benchmark/build.gradle.kts @@ -1,5 +1,6 @@ import io.gitlab.arturbosch.detekt.Detekt import net.ltgt.gradle.errorprone.errorprone +import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { id("com.android.application") @@ -64,7 +65,7 @@ android { } } - kotlin { compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 } + kotlin { compilerOptions.jvmTarget = JvmTarget.JVM_11 } lint { warningsAsErrors = true diff --git a/sentry-android-integration-tests/sentry-uitest-android-critical/build.gradle.kts b/sentry-android-integration-tests/sentry-uitest-android-critical/build.gradle.kts index 4b0cd68ca9..6f875e7a5e 100644 --- a/sentry-android-integration-tests/sentry-uitest-android-critical/build.gradle.kts +++ b/sentry-android-integration-tests/sentry-uitest-android-critical/build.gradle.kts @@ -1,4 +1,5 @@ import io.gitlab.arturbosch.detekt.Detekt +import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { id("com.android.application") @@ -31,7 +32,7 @@ android { proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") } } - kotlin { compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 } + kotlin { compilerOptions.jvmTarget = JvmTarget.JVM_11 } buildFeatures { compose = true } composeOptions { kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get() } androidComponents.beforeVariants { diff --git a/sentry-android-integration-tests/sentry-uitest-android-macrobenchmark/build.gradle.kts b/sentry-android-integration-tests/sentry-uitest-android-macrobenchmark/build.gradle.kts index 2d2aab48a1..a00d76d602 100644 --- a/sentry-android-integration-tests/sentry-uitest-android-macrobenchmark/build.gradle.kts +++ b/sentry-android-integration-tests/sentry-uitest-android-macrobenchmark/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11 + plugins { id("com.android.test") alias(libs.plugins.kotlin.android) @@ -30,7 +32,7 @@ android { targetCompatibility = JavaVersion.VERSION_11 } - kotlin { compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11 } + kotlin { compilerOptions.jvmTarget = JVM_11 } targetProjectPath = ":sentry-samples:sentry-samples-android" // Run the test in its own process so it measures the target app cold, not itself. diff --git a/sentry-android-integration-tests/sentry-uitest-android/build.gradle.kts b/sentry-android-integration-tests/sentry-uitest-android/build.gradle.kts index 4c71888314..52c17199e4 100644 --- a/sentry-android-integration-tests/sentry-uitest-android/build.gradle.kts +++ b/sentry-android-integration-tests/sentry-uitest-android/build.gradle.kts @@ -1,5 +1,6 @@ import io.gitlab.arturbosch.detekt.Detekt import net.ltgt.gradle.errorprone.errorprone +import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { id("com.android.application") @@ -63,7 +64,7 @@ android { } } - kotlin { compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 } + kotlin { compilerOptions.jvmTarget = JvmTarget.JVM_11 } lint { warningsAsErrors = true From 34c5da5c503e86b4139fe44036f55cb79f7a2057 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 16 Jul 2026 12:08:33 +0200 Subject: [PATCH 12/17] build(android): Drop JDK 8 toolchain pin from apache http client The jvmToolchain(8) pin forced javac onto JDK 8, where Error Prone (compiled for JDK 11) cannot load, breaking :sentry-apache-http-client-5 :compileJava and every Spring Boot sample build. Keep jvmTarget at 1.8 for Java 8 bytecode while letting the compiler run on the daemon JDK. Co-Authored-By: Claude Opus 4.8 (1M context) --- sentry-apache-http-client-5/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/sentry-apache-http-client-5/build.gradle.kts b/sentry-apache-http-client-5/build.gradle.kts index 40419c3b3d..7502fb6c4b 100644 --- a/sentry-apache-http-client-5/build.gradle.kts +++ b/sentry-apache-http-client-5/build.gradle.kts @@ -12,7 +12,6 @@ plugins { } kotlin { - jvmToolchain(8) compilerOptions.jvmTarget = JvmTarget.JVM_1_8 compilerOptions.languageVersion = KotlinVersion.KOTLIN_1_9 compilerOptions.apiVersion = KotlinVersion.KOTLIN_1_9 From 36ad6021444c85ed12f9d24db8cf3e3c8f8b8dfc Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 16 Jul 2026 17:00:07 +0200 Subject: [PATCH 13/17] build(android): Set testBuildType to release for AGP 9 unit tests AGP 9 only generates unit-test tasks for the configured testBuildType (default "debug"), whereas AGP 8 generated them for every build type. CI disables the debug variant so it only builds and consumes release, which under AGP 9 meant no unit tests were generated or run for the Android library modules at all. Set testBuildType = "release" on the modules that disable the debug variant and have unit tests, so testReleaseUnitTest is generated again. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01EmE8hdaj9H9K61opK2PZ6U --- sentry-android-core/build.gradle.kts | 4 ++++ sentry-android-distribution/build.gradle.kts | 4 ++++ sentry-android-fragment/build.gradle.kts | 4 ++++ sentry-android-navigation/build.gradle.kts | 4 ++++ sentry-android-ndk/build.gradle.kts | 4 ++++ sentry-android-replay/build.gradle.kts | 4 ++++ sentry-android-sqlite/build.gradle.kts | 4 ++++ sentry-android-timber/build.gradle.kts | 4 ++++ sentry-launchdarkly-android/build.gradle.kts | 4 ++++ 9 files changed, 36 insertions(+) diff --git a/sentry-android-core/build.gradle.kts b/sentry-android-core/build.gradle.kts index 0388b7de48..a39488d337 100644 --- a/sentry-android-core/build.gradle.kts +++ b/sentry-android-core/build.gradle.kts @@ -33,6 +33,10 @@ android { getByName("release") { consumerProguardFiles("proguard-rules.pro") } } + // AGP 9 only generates unit tests for the testBuildType. CI disables the debug + // variant, so unit tests must target release to run at all. + testBuildType = "release" + kotlin { compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 } testOptions { diff --git a/sentry-android-distribution/build.gradle.kts b/sentry-android-distribution/build.gradle.kts index 2d23bf3ab7..3753baf7c9 100644 --- a/sentry-android-distribution/build.gradle.kts +++ b/sentry-android-distribution/build.gradle.kts @@ -12,6 +12,10 @@ android { defaultConfig { minSdk = libs.versions.minSdk.get().toInt() } buildFeatures { buildConfig = false } + // AGP 9 only generates unit tests for the testBuildType. CI disables the debug + // variant, so unit tests must target release to run at all. + testBuildType = "release" + testOptions { unitTests.apply { isReturnDefaultValues = true diff --git a/sentry-android-fragment/build.gradle.kts b/sentry-android-fragment/build.gradle.kts index 594f6acdee..c32b881c3d 100644 --- a/sentry-android-fragment/build.gradle.kts +++ b/sentry-android-fragment/build.gradle.kts @@ -25,6 +25,10 @@ android { getByName("release") { consumerProguardFiles("proguard-rules.pro") } } + // AGP 9 only generates unit tests for the testBuildType. CI disables the debug + // variant, so unit tests must target release to run at all. + testBuildType = "release" + kotlin { jvmToolchain(8) compilerOptions.jvmTarget = JvmTarget.JVM_1_8 diff --git a/sentry-android-navigation/build.gradle.kts b/sentry-android-navigation/build.gradle.kts index 8d6d49f923..25bb4ce0ca 100644 --- a/sentry-android-navigation/build.gradle.kts +++ b/sentry-android-navigation/build.gradle.kts @@ -25,6 +25,10 @@ android { getByName("release") { consumerProguardFiles("proguard-rules.pro") } } + // AGP 9 only generates unit tests for the testBuildType. CI disables the debug + // variant, so unit tests must target release to run at all. + testBuildType = "release" + kotlin { jvmToolchain(8) compilerOptions.jvmTarget = JVM_1_8 diff --git a/sentry-android-ndk/build.gradle.kts b/sentry-android-ndk/build.gradle.kts index c2d0a33d82..ba651da56a 100644 --- a/sentry-android-ndk/build.gradle.kts +++ b/sentry-android-ndk/build.gradle.kts @@ -26,6 +26,10 @@ android { getByName("release") { consumerProguardFiles("proguard-rules.pro") } } + // AGP 9 only generates unit tests for the testBuildType. CI disables the debug + // variant, so unit tests must target release to run at all. + testBuildType = "release" + kotlin { compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 } testOptions { diff --git a/sentry-android-replay/build.gradle.kts b/sentry-android-replay/build.gradle.kts index f64caf0758..4cbdd08365 100644 --- a/sentry-android-replay/build.gradle.kts +++ b/sentry-android-replay/build.gradle.kts @@ -34,6 +34,10 @@ android { getByName("release") { consumerProguardFiles("proguard-rules.pro") } } + // AGP 9 only generates unit tests for the testBuildType. CI disables the debug + // variant, so unit tests must target release to run at all. + testBuildType = "release" + kotlin { jvmToolchain(8) compilerOptions.jvmTarget = JvmTarget.JVM_1_8 diff --git a/sentry-android-sqlite/build.gradle.kts b/sentry-android-sqlite/build.gradle.kts index f3c668e70d..5d343349cf 100644 --- a/sentry-android-sqlite/build.gradle.kts +++ b/sentry-android-sqlite/build.gradle.kts @@ -25,6 +25,10 @@ android { getByName("release") { consumerProguardFiles("proguard-rules.pro") } } + // AGP 9 only generates unit tests for the testBuildType. CI disables the debug + // variant, so unit tests must target release to run at all. + testBuildType = "release" + kotlin { jvmToolchain(8) compilerOptions.jvmTarget = JvmTarget.JVM_1_8 diff --git a/sentry-android-timber/build.gradle.kts b/sentry-android-timber/build.gradle.kts index ba81b02871..2f1aac6f6d 100644 --- a/sentry-android-timber/build.gradle.kts +++ b/sentry-android-timber/build.gradle.kts @@ -32,6 +32,10 @@ android { getByName("release") { consumerProguardFiles("proguard-rules.pro") } } + // AGP 9 only generates unit tests for the testBuildType. CI disables the debug + // variant, so unit tests must target release to run at all. + testBuildType = "release" + kotlin { jvmToolchain(8) compilerOptions.jvmTarget = JvmTarget.JVM_1_8 diff --git a/sentry-launchdarkly-android/build.gradle.kts b/sentry-launchdarkly-android/build.gradle.kts index 427ec47367..32b3641203 100644 --- a/sentry-launchdarkly-android/build.gradle.kts +++ b/sentry-launchdarkly-android/build.gradle.kts @@ -27,6 +27,10 @@ android { getByName("release") { consumerProguardFiles("proguard-rules.pro") } } + // AGP 9 only generates unit tests for the testBuildType. CI disables the debug + // variant, so unit tests must target release to run at all. + testBuildType = "release" + kotlin { compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 } testOptions { From cd757264dfb992d2049955b36ba42397d040216e Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 16 Jul 2026 17:11:58 +0200 Subject: [PATCH 14/17] build(android): Add Google Maven to plugin repositories Some Android Gradle plugins are published only to Google's Maven repository, which was not available to pluginManagement resolution. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01EmE8hdaj9H9K61opK2PZ6U --- settings.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/settings.gradle.kts b/settings.gradle.kts index 7fb5c62791..82fad42aee 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -13,6 +13,7 @@ pluginManagement { } mavenCentral() gradlePluginPortal() + google() } } From e338caa5a43e0e56c66f2ec25664cc50c9420cab Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 16 Jul 2026 17:14:05 +0200 Subject: [PATCH 15/17] build(android): Pin Kotlin JVM toolchain to 8 for core Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01EmE8hdaj9H9K61opK2PZ6U --- sentry-android-core/build.gradle.kts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sentry-android-core/build.gradle.kts b/sentry-android-core/build.gradle.kts index a39488d337..6a2c127c42 100644 --- a/sentry-android-core/build.gradle.kts +++ b/sentry-android-core/build.gradle.kts @@ -1,5 +1,6 @@ import net.ltgt.gradle.errorprone.errorprone import org.jetbrains.kotlin.config.KotlinCompilerVersion +import org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 plugins { id("com.android.library") @@ -37,7 +38,10 @@ android { // variant, so unit tests must target release to run at all. testBuildType = "release" - kotlin { compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 } + kotlin { + jvmToolchain(8) + compilerOptions.jvmTarget = JVM_1_8 + } testOptions { animationsDisabled = true From b1e50fc099dcac5241eb22d518b6abad15400d9f Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 16 Jul 2026 17:31:01 +0200 Subject: [PATCH 16/17] build(android): Pin Java and Kotlin targets to 8 for Android modules Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01EmE8hdaj9H9K61opK2PZ6U --- sentry-android-core/build.gradle.kts | 5 +++++ sentry-android-distribution/build.gradle.kts | 9 ++++++++- sentry-android/build.gradle.kts | 4 ++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/sentry-android-core/build.gradle.kts b/sentry-android-core/build.gradle.kts index 6a2c127c42..16a50e5c67 100644 --- a/sentry-android-core/build.gradle.kts +++ b/sentry-android-core/build.gradle.kts @@ -43,6 +43,11 @@ android { compilerOptions.jvmTarget = JVM_1_8 } + java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + testOptions { animationsDisabled = true unitTests.apply { diff --git a/sentry-android-distribution/build.gradle.kts b/sentry-android-distribution/build.gradle.kts index 3753baf7c9..41487e5c2b 100644 --- a/sentry-android-distribution/build.gradle.kts +++ b/sentry-android-distribution/build.gradle.kts @@ -1,3 +1,4 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 import org.jetbrains.kotlin.gradle.dsl.KotlinVersion plugins { @@ -24,8 +25,14 @@ android { } } +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + kotlin { - jvmToolchain(17) + jvmToolchain(8) + compilerOptions.jvmTarget = JVM_1_8 compilerOptions.languageVersion = KotlinVersion.KOTLIN_1_9 explicitApi() } diff --git a/sentry-android/build.gradle.kts b/sentry-android/build.gradle.kts index a2d92829b2..eea192aab9 100644 --- a/sentry-android/build.gradle.kts +++ b/sentry-android/build.gradle.kts @@ -23,6 +23,10 @@ android { androidComponents.beforeVariants { it.enable = !Config.Android.shouldSkipDebugVariant(it.buildType) } + java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } } dependencies { From c6b4dfbf7adb6ff7c9195e1533b6e3d0cbf25fd7 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 16 Jul 2026 18:23:23 +0200 Subject: [PATCH 17/17] build(android): Centralize Java 8 compileOptions for library modules AGP 9 changed the default source/targetCompatibility for Android modules from Java 8 to Java 11. The branch pinned Java 8 inconsistently: some modules had no pin (compiled to Java 11), and others used a java{} block nested inside android{}, which is not the AGP DSL and had no effect. The resulting mixed compile-level graph crashed javac with "AssertionError: unrecognized Attribute name MODULE" on compileReleaseJavaWithJavac. Pin every published Android library module back to Java 8 via a single com.android.library block in the root build (mirroring the existing java-library pin), and drop the now-redundant per-module java{} blocks and jvmToolchain(8) calls. The Kotlin jvmTarget stays at 8 per module. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01EmE8hdaj9H9K61opK2PZ6U --- build.gradle.kts | 12 ++++++++++++ sentry-android-core/build.gradle.kts | 10 +--------- sentry-android-distribution/build.gradle.kts | 6 ------ sentry-android-fragment/build.gradle.kts | 1 - sentry-android-navigation/build.gradle.kts | 1 - sentry-android-replay/build.gradle.kts | 1 - sentry-android-sqlite/build.gradle.kts | 1 - sentry-android-timber/build.gradle.kts | 1 - sentry-android/build.gradle.kts | 4 ---- sentry-compose/build.gradle.kts | 1 - 10 files changed, 13 insertions(+), 25 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 55b5a71a1e..764667ecd6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -168,6 +168,18 @@ subprojects { } } + // AGP 9 defaults Android modules to Java 11. Pin the published library modules back + // to Java 8 so their bytecode stays consumable by Java 8 projects, mirroring the + // java-library pin above. + plugins.withId("com.android.library") { + configure { + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + } + } + apply() afterEvaluate { diff --git a/sentry-android-core/build.gradle.kts b/sentry-android-core/build.gradle.kts index 16a50e5c67..f92876530f 100644 --- a/sentry-android-core/build.gradle.kts +++ b/sentry-android-core/build.gradle.kts @@ -38,15 +38,7 @@ android { // variant, so unit tests must target release to run at all. testBuildType = "release" - kotlin { - jvmToolchain(8) - compilerOptions.jvmTarget = JVM_1_8 - } - - java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } + kotlin { compilerOptions.jvmTarget = JVM_1_8 } testOptions { animationsDisabled = true diff --git a/sentry-android-distribution/build.gradle.kts b/sentry-android-distribution/build.gradle.kts index 41487e5c2b..363bce003f 100644 --- a/sentry-android-distribution/build.gradle.kts +++ b/sentry-android-distribution/build.gradle.kts @@ -25,13 +25,7 @@ android { } } -java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 -} - kotlin { - jvmToolchain(8) compilerOptions.jvmTarget = JVM_1_8 compilerOptions.languageVersion = KotlinVersion.KOTLIN_1_9 explicitApi() diff --git a/sentry-android-fragment/build.gradle.kts b/sentry-android-fragment/build.gradle.kts index c32b881c3d..197c0b05d6 100644 --- a/sentry-android-fragment/build.gradle.kts +++ b/sentry-android-fragment/build.gradle.kts @@ -30,7 +30,6 @@ android { testBuildType = "release" kotlin { - jvmToolchain(8) compilerOptions.jvmTarget = JvmTarget.JVM_1_8 compilerOptions.languageVersion = KotlinVersion.KOTLIN_1_9 compilerOptions.apiVersion = KotlinVersion.KOTLIN_1_9 diff --git a/sentry-android-navigation/build.gradle.kts b/sentry-android-navigation/build.gradle.kts index 25bb4ce0ca..5ac9842548 100644 --- a/sentry-android-navigation/build.gradle.kts +++ b/sentry-android-navigation/build.gradle.kts @@ -30,7 +30,6 @@ android { testBuildType = "release" kotlin { - jvmToolchain(8) compilerOptions.jvmTarget = JVM_1_8 compilerOptions.languageVersion = KotlinVersion.KOTLIN_1_9 compilerOptions.apiVersion = KotlinVersion.KOTLIN_1_9 diff --git a/sentry-android-replay/build.gradle.kts b/sentry-android-replay/build.gradle.kts index 4cbdd08365..02f2dab3d4 100644 --- a/sentry-android-replay/build.gradle.kts +++ b/sentry-android-replay/build.gradle.kts @@ -39,7 +39,6 @@ android { testBuildType = "release" kotlin { - jvmToolchain(8) compilerOptions.jvmTarget = JvmTarget.JVM_1_8 compilerOptions.languageVersion = KotlinVersion.KOTLIN_1_9 compilerOptions.apiVersion = KotlinVersion.KOTLIN_1_9 diff --git a/sentry-android-sqlite/build.gradle.kts b/sentry-android-sqlite/build.gradle.kts index 5d343349cf..e1e3bc6876 100644 --- a/sentry-android-sqlite/build.gradle.kts +++ b/sentry-android-sqlite/build.gradle.kts @@ -30,7 +30,6 @@ android { testBuildType = "release" kotlin { - jvmToolchain(8) compilerOptions.jvmTarget = JvmTarget.JVM_1_8 compilerOptions.languageVersion = KotlinVersion.KOTLIN_1_9 compilerOptions.apiVersion = KotlinVersion.KOTLIN_1_9 diff --git a/sentry-android-timber/build.gradle.kts b/sentry-android-timber/build.gradle.kts index 2f1aac6f6d..e55b8b0e3c 100644 --- a/sentry-android-timber/build.gradle.kts +++ b/sentry-android-timber/build.gradle.kts @@ -37,7 +37,6 @@ android { testBuildType = "release" kotlin { - jvmToolchain(8) compilerOptions.jvmTarget = JvmTarget.JVM_1_8 compilerOptions.languageVersion = KotlinVersion.KOTLIN_1_9 compilerOptions.apiVersion = KotlinVersion.KOTLIN_1_9 diff --git a/sentry-android/build.gradle.kts b/sentry-android/build.gradle.kts index eea192aab9..a2d92829b2 100644 --- a/sentry-android/build.gradle.kts +++ b/sentry-android/build.gradle.kts @@ -23,10 +23,6 @@ android { androidComponents.beforeVariants { it.enable = !Config.Android.shouldSkipDebugVariant(it.buildType) } - java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } } dependencies { diff --git a/sentry-compose/build.gradle.kts b/sentry-compose/build.gradle.kts index 4bda19693b..52f84ec138 100644 --- a/sentry-compose/build.gradle.kts +++ b/sentry-compose/build.gradle.kts @@ -15,7 +15,6 @@ plugins { } kotlin { - jvmToolchain(8) explicitApi() androidTarget {