diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e653069e2b..fb4c53d0c0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,6 +29,7 @@ otelInstrumentationAlpha = "2.26.0-alpha" otelSemanticConventions = "1.40.0" otelSemanticConventionsAlpha = "1.40.0-alpha" retrofit = "2.9.0" +sagp = "6.6.0" slf4j = "1.7.30" springboot2 = "2.7.18" springboot3 = "3.5.0" @@ -66,7 +67,7 @@ springboot4 = { id = "org.springframework.boot", version.ref = "springboot4" } spring-dependency-management = { id = "io.spring.dependency-management", version = "1.1.7" } gretty = { id = "org.gretty", version = "4.0.0" } animalsniffer = { id = "ru.vyarus.animalsniffer", version = "2.0.1" } -sentry = { id = "io.sentry.android.gradle", version = "6.6.0"} +sentry = { id = "io.sentry.android.gradle", version.ref = "sagp"} shadow = { id = "com.gradleup.shadow", version = "9.4.1" } [libraries] diff --git a/sentry-samples/sentry-samples-android/README.md b/sentry-samples/sentry-samples-android/README.md new file mode 100644 index 0000000000..5ce0a3ccbd --- /dev/null +++ b/sentry-samples/sentry-samples-android/README.md @@ -0,0 +1,77 @@ +# Sentry Sample Android App + +Sample application demonstrating how to use the Sentry Android SDK, including core functionality (error reporting, tracing, session replay, +profiling) and integrations (Compose, OkHttp, etc.). + +## How to run it? + +Install the app on your device or emulator: + +``` +./gradlew :sentry-samples:sentry-samples-android:installDebug +``` + +or simply open the project in Android Studio and run the `sentry-samples-android` configuration. + +You can also apply the [Sentry Android Gradle Plugin](https://github.com/getsentry/sentry-android-gradle-plugin) (SAGP) when building (not applied by default): + +``` +./gradlew :sentry-samples:sentry-samples-android:installDebug -PuseSagp=true +``` + +In Android Studio, add `useSagp=true` to `gradle.properties` or pass it as a Gradle project property. + +## Build modes + +### With or without SAGP + +The sample app can be built with or without the SAGP. + +| Gradle Property | Required | Purpose | +|-----------------|--------------------------|----------------------------------------------------------------------------------------------------------------| +| `useSagp` | No (defaults to `false`) | When `true`, apply SAGP when building the sample app. When false or absent, build the sample app without SAGP. | + +You can configure SAGP properties via the lambda passed to `extensions.configure("sentry")` in the sample app's +`build.gradle.kts` file. + +### Builds against your local sentry-java branch + +Regardless of `useSagp`, the sample always depends on sentry-java modules from this monorepo (e.g., `projects.sentryAndroid`). SAGP's SDK +auto-installation is disabled, so the sample never pulls a separate SDK version from Maven. Local SDK changes in your branch are picked up +directly. + +### Testing an unpublished SAGP build + +#### I. Publish to Maven Local: + +`-PuseSagp=true` builds check `mavenLocal()` first when resolving SAGP, so you can test a local SAGP branch by publishing it to your local +Maven repository: + +``` +# In your sentry-android-gradle-plugin checkout: +./gradlew publishToMavenLocal +``` + +Re-run `publishToMavenLocal` after each SAGP change; a previously published artifact stays in `~/.m2` and keeps winning until you republish +or remove it. + +#### II. Update `sagp` version in `libs.versions.toml` if needed + +The sample requests the SAGP version pinned in `gradle/libs.versions.toml` (`[versions].sagp`), so either publish your branch at that +version, or temporarily bump the pin to your branch's version (e.g., a `-SNAPSHOT`) without committing the change. + +## Viewing SDK output + +### Locally + +Debug builds enable SDK debug logging, so captured envelopes are printed to logcat (tag `Sentry`): + +``` +adb logcat -s Sentry +``` + +### On Sentry UI + +By default, SDK output produced by the sample app appears under the [sentry-sdk test project](https://sentry-sdks.sentry.io/issues/?project=5428559). +To redirect them to your own project, replace the test DSN (i.e., the `io.sentry.dsn` `meta-data` value in `src/main/AndroidManifest.xml` +with your own. diff --git a/sentry-samples/sentry-samples-android/build.gradle.kts b/sentry-samples/sentry-samples-android/build.gradle.kts index ed8cea2566..069cfaf8d7 100644 --- a/sentry-samples/sentry-samples-android/build.gradle.kts +++ b/sentry-samples/sentry-samples-android/build.gradle.kts @@ -1,5 +1,9 @@ import com.android.build.api.artifact.SingleArtifact import com.android.build.api.variant.impl.VariantImpl +import io.sentry.android.gradle.extensions.InstrumentationFeature +import io.sentry.android.gradle.extensions.SentryPluginExtension +import java.io.File +import java.time.Instant import org.apache.tools.ant.taskdefs.condition.Os import org.gradle.internal.extensions.stdlib.capitalized @@ -7,6 +11,38 @@ plugins { id("com.android.application") alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.compose) + alias(libs.plugins.sentry) apply false +} + +val useSagp = + providers.gradleProperty("useSagp").map { it.equals("true", ignoreCase = true) }.orElse(false) + +if (useSagp.get()) { + apply(plugin = "io.sentry.android.gradle") +} + +plugins.withId("io.sentry.android.gradle") { + logSagpOrigin() + + // Extension configs match non-SAGP builds. Update locally to test your feature. + extensions.configure("sentry") { + autoInstallation.enabled.set(false) + includeProguardMapping.set(false) + includeDependenciesReport.set(false) + telemetry.set(false) + tracingInstrumentation { + features.set( + setOf( + InstrumentationFeature.COMPOSE, + InstrumentationFeature.DATABASE, + InstrumentationFeature.FILE_IO, + InstrumentationFeature.OKHTTP, + ) + ) + logcat.enabled.set(false) + appStart.enabled.set(false) + } + } } android { @@ -198,3 +234,46 @@ abstract class ToggleNativeLoggingTask : Exec() { ) } } + +fun Project.logSagpOrigin() { + // A locally published SAGP in ~/.m2 silently shadows the released artifact (see README, + // "Testing an unpublished SAGP build"); we log so developers don't wonder what's going on. + val sagpVersion = + SentryPluginExtension::class + .java + .protectionDomain + .codeSource + ?.location + ?.toURI() + ?.let { File(it).name } + ?.removePrefix("sentry-android-gradle-plugin-") + ?.removeSuffix(".jar") + + val sagpLocalJar = + sagpVersion?.let { + File( + System.getProperty("user.home"), + ".m2/repository/io/sentry/sentry-android-gradle-plugin/$it/sentry-android-gradle-plugin-$it.jar", + ) + } + + val sagpOrigin = + when { + sagpVersion == null -> "unknown origin" + sagpLocalJar?.isFile == true -> + "mavenLocal (published ${Instant.ofEpochMilli(sagpLocalJar.lastModified())})" + else -> "remote repository" + } + + val colorize = + gradle.startParameter.consoleOutput != org.gradle.api.logging.configuration.ConsoleOutput.Plain + val (magenta, reset) = if (colorize) "\u001B[35m" to "\u001B[0m" else "" to "" + + logger.lifecycle( + "\n{}🧩 Applied Sentry Android Gradle Plugin {} from {}{}", + magenta, + sagpVersion ?: "", + sagpOrigin, + reset, + ) +} diff --git a/settings.gradle.kts b/settings.gradle.kts index c435c382b7..28bead1218 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,6 +2,15 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") pluginManagement { repositories { + // Prefer local SAGP artifact if one exists; otherwise fall back to libs.versions.toml. + if (providers.gradleProperty("useSagp").orNull.equals("true", ignoreCase = true)) { + mavenLocal { + content { + includeGroup("io.sentry") + includeGroup("io.sentry.android.gradle") + } + } + } mavenCentral() gradlePluginPortal() }