diff --git a/packages/core/sentry.gradle b/packages/core/sentry.gradle index 3ab9225241..cdb70e7d85 100644 --- a/packages/core/sentry.gradle +++ b/packages/core/sentry.gradle @@ -65,13 +65,37 @@ tasks.register("cleanupTemporarySentryJsonConfiguration") { plugins.withId('com.android.application') { def androidComponents = extensions.getByName("androidComponents") + // Collect ApplicationVariant objects in onVariants - do NOT access tasks here. + // Calling tasks.findAll or tasks.matching{}.each{} inside onVariants forces task realization + // during AGP's variant configuration phase, which disrupts the Artifacts API + // transform chain used by other plugins (e.g. those calling + // variant.artifacts.use(...).toTransform(SingleArtifact.APK)). The result is + // that those plugins' APK output ends up in build/intermediates/ instead of + // build/outputs/, causing downstream tooling to fail to locate the final APK. + def releaseVariants = [] androidComponents.onVariants(androidComponents.selector().all()) { v -> if (!v.name.toLowerCase().contains("debug")) { + releaseVariants << v + } + } + + // All task-level operations must happen in afterEvaluate, not inside onVariants. + // By the time afterEvaluate runs, all plugins have registered their onVariants + // callbacks and the AGP Artifacts API transform chain is fully established. + project.afterEvaluate { + if (releaseVariants.isEmpty()) { + project.logger.warn("[sentry] No release variants collected, onVariants may have run after afterEvaluate. Sourcemap upload tasks will not be registered.") + } + releaseVariants.each { v -> // separately we then hook into the bundle task of react native to inject // sourcemap generation parameters. In case for whatever reason no release // was found for the asset folder we just bail. - def bundleTasks = tasks.findAll { task -> (task.name.startsWith("createBundle") || task.name.startsWith("bundle")) && task.name.endsWith("JsAndAssets") && !task.name.contains("Debug") && task.enabled } - bundleTasks.each { bundleTask -> + tasks.matching { task -> + (task.name.startsWith("createBundle") || task.name.startsWith("bundle")) && + task.name.endsWith("JsAndAssets") && + !task.name.contains("Debug") + }.each { bundleTask -> + if (!bundleTask.enabled) return def shouldCleanUp def sourcemapOutput def bundleOutput @@ -95,7 +119,7 @@ plugins.withId('com.android.application') { // .join('\n') def currentVariants = extractCurrentVariants(bundleTask, v) - if (currentVariants == null) return + if (currentVariants == null || currentVariants.isEmpty()) return def previousCliTask = null def applicationVariant = null @@ -304,9 +328,10 @@ plugins.withId('com.android.application') { previousCliTask.configure { finalizedBy cliCleanUpTask } def packageTasks = tasks.matching { - task -> ("package${applicationVariant}".equalsIgnoreCase(task.name) || "package${applicationVariant}Bundle".equalsIgnoreCase(task.name)) && task.enabled + task -> ("package${applicationVariant}".equalsIgnoreCase(task.name) || "package${applicationVariant}Bundle".equalsIgnoreCase(task.name)) } packageTasks.configureEach { packageTask -> + if (!packageTask.enabled) return packageTask.dependsOn modulesTask packageTask.finalizedBy modulesCleanUpTask }