Daniele Segato
02/28/2025, 8:43 AMinterface EnvironmentPluginExtension : Named {
val applicationId: Property<String?>
val applicationIdSuffix: Property<String?>
val versionNameSuffix: Property<String?>
val disableDebugBuild: Property<Boolean>
val disableReleaseBuild: Property<Boolean>
}
Than I in the plugin I had
pluginManager.apply("com.android.application")
val extension = extensions.getByType<ApplicationExtension>()
val envContainer = objects.domainObjectContainer(EnvironmentPluginExtension::class.java)
(extension as ExtensionAware).extensions.add("environments", envContainer)
envContainer.whenObjectAdded {
val customSuffix = applicationIdSuffix.orNull // always null
// ...
}
and used it to configure environments in the android application
from the build.gradle.kts file I could do stuff like this
android {
environments {
create("dev")
create("stage") {
applicationIdSuffix = ".staging"
}
}
}
I remember it used to work - but I used defaults values since I set this up.
now that I needed it - several gradle versions laters - I noticed it doesn’t work anymore
apparently whenObjectAdded
is now running BEFORE the domain object is configured (which is absurd imho).
I cannot use afterEvaluate
can anyone give me some way of achieving what I need?Vampire
02/28/2025, 11:46 AMwhenObjectAdded { ... }
or configureEach { ... }
and so on always run in registration order "unfortunately".
So if you for example have
tasks.withType<Foo>().configureEach { /* do A */ }
val foo by tasks.registering(Foo::class) { /* do B */ }
then also A
runs before B
, as both are configuration actions and A
was registered before B
.
Basically any get()
you do on a Property
(including .orNull
which really is .getOrNull()
) at configuration time introduces race conditions, as you never know whether the value is maybe changed later, unless you lock it first using finalizeValue
or finalizeValueOnRead
.
Even using afterEvaluate
does not eliminate race conditions, but just makes things worse.
So if in any way possible, try to not read the applicationSuffix
at configuration time, but only at execution time.
If you really need the value at configuration time because you have to derive some domain object name from it or similar, then I usually recommend to not use a Property
but a function in the extension instead, getting the applicationIdSuffix
as argument.
Hard to say how to do it properly in this specific case from the top of my head.
``````Vampire
02/28/2025, 11:48 AMenvironments
not a domain object container directly, but some extension with a function to which you give the applicationIdSuffix
as argument and then do the create
call in that function or something like that.ephemient
02/28/2025, 12:25 PMDaniele Segato
02/28/2025, 7:36 PMVampire
02/28/2025, 11:45 PMHow do I read it at execution time? I'm just trying to configure the android Gradle plugin with my pluginIf the latter, then not the former 🙂
And for the function can I use getter/setters?I don't know, never tried. That's for me wrong semantics if you set a value, you set a value. If that directly causes other configurations to be done and maybe even only be callable once, then a property setter does not feel right to me.
Do you have an example?Nothing public at hand.
Daniele Segato
03/01/2025, 1:24 PMDaniele Segato
03/01/2025, 1:26 PMandroid {
environments {
create("dev")
create("stage") {
// specific stage conf here
}
}
}
this is just perfect it would be great if only I could get a callback right after the configuration runVampire
03/02/2025, 12:56 AMenvironments
an extension with a function called create
that gets a string and an optional Action
as arguments. 🙂