Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ projects. That opt-out dies with AGP 10.
avoiding a self-referential `.map`. Fall back to a snapshot only if
read-then-set is impossible; record the outcome here.
- *Spike result:* _pending (P6)_.
6. **P3 pre-spike (afterEvaluate DSL mutation under newDsl).** The planned scratch-app
spike (AGP 9.1 + `newDsl=true` + custom build type, verifying that build-type
creation from `pluginProject.afterEvaluate` still works) could not run in the
implementation sandbox (no AGP artifact access). The `initWith` copy landed on the
primary approach; the `android_plugin_example_app_build` integration test and a
custom-build-type scratch build must confirm it in CI. Documented fallback if
`afterEvaluate` mutation is rejected under newDsl: perform the copy in
`androidComponents.finalizeDsl` on the plugin project instead.
5. **`buildModeFor` semantics.** Every variant-scope call uses the
`(name, debuggable)` overload with the public `Component.debuggable`.
Name-based inference is confined to the one DSL-scope case with no public
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package com.flutter.gradle.plugins

import com.android.build.api.dsl.ApplicationBuildType
import com.android.build.api.dsl.BuildType
import com.flutter.gradle.CompileSdkVersion
import com.flutter.gradle.FlutterExtension
Expand All @@ -12,15 +13,11 @@ import com.flutter.gradle.FlutterPluginUtils.addApiDependencies
import com.flutter.gradle.FlutterPluginUtils.buildModeFor
import com.flutter.gradle.FlutterPluginUtils.getAndroidExtension
import com.flutter.gradle.FlutterPluginUtils.getCompileSdkFromProject
import com.flutter.gradle.FlutterPluginUtils.getLegacyAndroidExtension
import com.flutter.gradle.FlutterPluginUtils.isBuiltAsApp
import com.flutter.gradle.FlutterPluginUtils.supportsBuildMode
import com.flutter.gradle.NativePluginLoaderReflectionBridge
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.plugin.extraProperties
import java.io.File
import com.android.build.gradle.internal.dsl.BuildType as dslBuildType

/**
* Handles interactions with the flutter plugins (not Gradle plugins) used by the Flutter project,
Expand Down Expand Up @@ -159,22 +156,19 @@ class PluginHandler(
return
}

// Copy build types from the app to the plugin.
// This allows to build apps with plugins and custom build types or flavors.
// However, only copy if the plugin is also an app project, since library projects
// cannot have applicationIdSuffix and other app-specific properties.
if (isBuiltAsApp(pluginProject)) {
(getLegacyAndroidExtension(pluginProject).buildTypes as NamedDomainObjectContainer<dslBuildType>)
.addAll(getLegacyAndroidExtension(project).buildTypes as NamedDomainObjectContainer<dslBuildType>)
} else {
// For library projects, create compatible build types without app-specific properties
getLegacyAndroidExtension(project).buildTypes.forEach { appBuildType ->
if (getLegacyAndroidExtension(pluginProject).buildTypes.findByName(appBuildType.name) == null) {
getLegacyAndroidExtension(pluginProject).buildTypes.create(appBuildType.name) {
// Copy library-compatible properties only
// Copy the app project's build types onto the plugin project so that its variants
// resolve. These are `initWith` copies, not live aliases: `initWith` copies the
// properties both build types understand (matchingFallbacks included), and
// app-specific properties are additionally copied when both sides are application
// build types. Library build types cannot receive app-specific properties (such
// as isDebuggable) through the public DSL.
val pluginProjectBuildTypes = getAndroidExtension(pluginProject).buildTypes
getAndroidExtension(project).buildTypes.forEach { appBuildType ->
if (pluginProjectBuildTypes.findByName(appBuildType.name) == null) {
pluginProjectBuildTypes.create(appBuildType.name) {
initWith(appBuildType)
if (this is ApplicationBuildType && appBuildType is ApplicationBuildType) {
isDebuggable = appBuildType.isDebuggable
isMinifyEnabled = appBuildType.isMinifyEnabled
// Note: applicationIdSuffix and other app-specific properties are intentionally not copied
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package com.flutter.gradle

import java.io.File
import kotlin.test.Test
import kotlin.test.assertTrue

/**
* Guards the AGP public-API migration (https://github.com/flutter/flutter/issues/180137):
* production sources must not use AGP internals. AGP 10 removes access to internals
* entirely, and the Flutter Gradle Plugin will compile against the `gradle-api` artifact,
* where they do not exist. Test sources may still reference internal types until the
* dependency swap.
*/
class InternalAgpApiImportTest {
@Test
fun `main sources do not import AGP internals`() {
// The Gradle test JVM runs with the project directory
// (packages/flutter_tools/gradle) as its working directory.
val mainSources = File("src/main")
assertTrue(
mainSources.isDirectory,
"Expected to find src/main relative to the test working directory " +
"(${File(".").absolutePath})."
)
val internalImport = Regex("""^\s*import\s+com\.android\.build\.gradle\.internal\.""")
val offendingLines =
mainSources
.walkTopDown()
.filter { it.isFile && it.extension in setOf("kt", "java", "groovy", "gradle") }
.flatMap { file ->
file.readLines().mapIndexedNotNull { index, line ->
if (internalImport.containsMatchIn(line)) {
"${file.path}:${index + 1}: ${line.trim()}"
} else {
null
}
}
}.toList()
assertTrue(
offendingLines.isEmpty(),
"AGP internal APIs must not be used in production sources; they are removed in " +
"AGP 10. Use the public com.android.build.api surface (see " +
"docs/platforms/android/Migrating-Flutter-Gradle-Plugin-to-AGP-public-API.md).\n" +
offendingLines.joinToString("\n")
)
}
}
Loading