Vlad
07/01/2024, 9:58 AMregister method.
flavorsExtension.config {
register("flavorA") {
variable = "variable1"
applicationId = "com.flavor.a"
},
register("flavorB") {
variable1 = "variable2"
applicationId = "com.flavor.b"
}
}
My plugin uses NamedDomainObjectContainer to get registered flavors when they are ready.
interface FlavorsExtension {
val config: NamedDomainObjectContainer<FlavorsConfig>
}
abstract class FlavorConfig(
private val name: String,
) : Named {
var variable1: String = "variable0"
var applicationId: String? = null
override fun getName(): String = name
}
And my plugin in the end looks like that:
class SetupFlavorsPlugin : Plugin<Project> {
override fun apply(target: Project) = with(target) {
val flavorsExtension = extensions.create("flavorsExtension", FlavorsExtension::class.java)
flavorsExtension.config.all { config ->
setupFlavor(config)
}
}
private fun Project.setupFlavor(config: FlavorConfig) {
val androidExtension = project.extensions.getByType(ApplicationExtension::class.java)
androidExtension.flavorDimensions("flavor1")
androidExtension.productFlavors.register(config.name) { flavor ->
flavor.dimension = "flavor1"
val appId = getApplicationId(config)
println("SetupFlavorsPlugin: $appId ${config.applicationId} ${config.marketing} ${config.ticketing}")
if (appId != null) {
flavor.applicationId = appId
flavor.resValue("string", "application_id", appId)
}
}
}
}
The issue is that name is there when .all { } is called, but not parameters.
afterEvaluate { } helps to get registered flavors with variables but it's too late for me to set up flavors in android extension.
The only thing that works for me is to use add { } instead of register { }
flavorsExtension.config {
add(
FlavorConfig(
name = "flavorA",
variable = "variable1"
applicationId = "com.flavor.a",
)
)
Do you know at what time in configuration phase these variables are set up?
Thanks in advance 🙂Vampire
07/01/2024, 10:31 AMcreate or register, the last parameter is the configure action that in your case sets variable and applicationid.
The problem is, that the configuration actions are run in the order they are added.
So your plugin adds its configuration action (that you registered with all or configureEach) first, then the consumer does the register call with another configuration action that comes second.
Because of that the values for the properties are not set yet when the action in the plugin is executed.
If the place where you want to use those property values accepts `Provider`s and properly treats them lazily, you could make your properties `Property`s and wire them to where they are needed.
If you need those values at configuration time to create some other objects (which probably is the case for product flavors, I'm not into Android development), then this would not help or work.
In that case this is the same problem that you always have when you register some extension and need to change other non-Provider configuration from the plugin based on those properties.
Using afterEvaluate is one band-aid "solution", but one that should be avoided as hell, besides that you said it does not work in your case anyway. The main effect of afterEvaluate is to introduce ordering problems, timing problems, and race conditions, and it should imho be avoided at almost any cost.
The solution I recommend in such cases is to instead use functions.
In you case your FlavorsExtension could for example instead have some createFlavor(name, variable, applicationId) function that then does the according configuration as it has all the necessary variables available as arguments right away.
If you for some reason nevertheless need a named domain object collection, that method could also do the register call to fill it.Vlad
07/01/2024, 12:33 PMVlad
07/01/2024, 12:34 PMVlad
07/01/2024, 12:36 PMVlad
07/01/2024, 12:36 PMVlad
07/02/2024, 7:46 AMclass SetupFlavorsPlugin : Plugin<Project> {
override fun apply(target: Project) {
val androidExtension = target.extensions.getByType(ApplicationExtension::class.java)
target.extensions.create(
"flavorsExtension",
FlavorsExtension::class.java,
target,
androidExtension,
)
}
}
abstract class FlavorsExtension(
private val project: Project,
private val androidExtension: ApplicationExtension,
) {
fun createFlavor(
name: String,
variable: String,
applicationId: String? = null,
) = with(project) {
val config = FlavorConfig(name, variable, applicationId)
setupProductFlavor(androidExtension, config)
}
}
fun Project.setupProductFlavor(...
In my root build.gradle.kts 👇
flavorsExtension {
createFlavor(
name = "test",
variable = "variable1,
applicationId = "com.flavor.a"
)
....
}
I guess, I got it right what you meant above 🙂
Thanks!Vampire
07/02/2024, 8:01 AMVlad
07/02/2024, 8:04 AMandroidExtension from FlavorsExtension, but it compiled and built the app with the flavor that was added 🤔
Am I missing something?Vampire
07/02/2024, 8:21 AMcreateFlavor but call createPartner :-DVlad
07/02/2024, 8:25 AM