is there a better way in 2025 to get flavor value ...
# community-support
m
is there a better way in 2025 to get flavor value in build script than parsing
Copy code
gradle.startParameter.taskRequests.toString()
?
н
Probably depends what for and when you need it. It can be as simple as using productFlavors.all
m
I need it as early as preBuild
based on the current flavor, I'd run some code during build
н
You can run code in custom task, configure task for each flavor using productFlavors.all. And you can make preBuild task to depend on your custom task.
m
interesting, for starters, where do I get productFlavors from? it's not globally available AFAIK
н
I assume you work with android project, it available in android { } section of your build script.
m
good assumption - yes, android and gradle kotlin
ok, I think I understand you now - you are suggesting that I create my task within productFlavors configuration, correct?
like
Copy code
productFlavors {
        create("stage") {
          tasks.regsiter("stage_flavor_custom") { ...
or better, with a generic name "my custom task" so I can easily depend prebuild on it
if that is what you meant, it won't work because then I have a problem with flavor combinations
н
I probably would do it after you configured your flavors. Next section would be something like. productFlavors.all { // There you create and configure your task for each flavor } Or even better I would do it for variants instead as it combines buildType and various dimensions of flavors. https://github.com/android/gradle-recipes/tree/agp-8.13/onVariants
m
is there a sample on how to use onVariants as it looks promising - or do I have to copy source files and insert it into my project?
н
I’ve sent a link to gradle-receipes, it has a sample for onVariants for plugin in build-logic, but similar code could be written in your app/build.gradle.kts
v
Btw. just in case you get the idea to parse the requested tasks of the start parameters again in the future, the caller can use abbreviations, not necessarily full task names.
m
Nick: yes, thanks, I was just wondering whether there was a prebuild plugin out there - I'll certainly use that code
Vampire: FFS - can we just have a property, possibly a map(dimension, value) of the active variant
н
And he may also run multiple tasks in one gradle launch for different variants for i.e.
gradle assembleFlavor1Debug assembleFlavor1Release assmebleFlavor2Debug
m
luckily my app is a relatively simple one - shared module and two frontend modules
н
The thing is, as far as, I understand there is no such thing as one active variant
m
isn't there one per module?
v
Vampire: FFS - can we just have a property, possibly a map(dimension, value) of the active variant
I have no idea, I don't do Android
m
doesn't intellij have the same feature?
н
You idea of active variant is related to UI of IDEA IDE and it’s just indicates what variant of tasks will be launched if you press run button for i.e., but gradle itself doesn’t know anything about “active variant”
m
sure
v
I did not say I don't use Android Studio (even if that is true), I said I don't do Android 🙂
m
🙂
Nick: you are telling me that gradle doesn't know about the flavor because Android Studio starts a task (named with flavor) and that's it, right?
н
Let’s put it like this: It doesn’t know about “active flavor”, but it “knows” about all flavors
m
agreed
makes sense
based on that it really seems the only way to create tasks for all variants - like customDebug and customRelease
but how would I bind them so they execute based on active variant - I really need to understand onVariants plugin
am I correct that onVariants plugin sample does not bind tasks whatsoever - it just creates them. If so, then I can't run it before 'preBuild' task, perhaps I could run it before 'preDebug' task somehow
н
preBuild tasks also have variants, you just attach your custom task to the same variant of prebuild task using dependsOn for example.
m
will dependsOn make my custom task run right after the task it dependsOn and before others?
Let's say there are: preBuild preDebugBuild mergeDebugMetadata
v
No
m
that's what I feared
I guess I should make preDebugBuild dependsOn my custom task
(that's what Nick probably meant)
v
If two tasks have no ordering constraint, their order is not determined. So if you have A depending on C and B depending on C, you don't know whether A or B runs after C if it runs at all. And with configuration cache they can even run in parallel
m
yep, but if make preDebugBuild dependent on my custom task, then my custom task will run before it
v
I start to think that you might have an XY problem. What do you try to achieve with your custom task / what does it do? Because the requirement that it runs after a given task but before other tasks that might come after that sounds a bit fishy 🙂
yep, but if make preDebugBuild dependent on my custom task, then my custom task will run before it
Of course
m
my idea is this - sometime before build I'd fetch keystore, passwords and other sensitive config files from secure store to disk, do the build and then I'd delete them
so it'd make sense to fetch only active variant ones
argh, can't find flavor specific tasks 😞 in project.tasks - how can I find one? are they built on the fly?
if you look at onVariants CustomPlugin - there I try to
Copy code
project.tasks.findByName("preDebugBuild")
but only build is there
v
findByName
is not a good idea
m
could it be because project means onVariants module only?
probably not
I tried to println all project.tasks but there is no task with flavor in the name
v
If you do
findByName
you only get tasks that are already registered at the time you call that method. And at the same time you break task-configuration avoidance for that task if it is found.
If you want to configure the
preDebugBuild
task, you do
tasks.named { it == "preDebugBuild" }.configureEach { ... }
Unless you are in Kotlin DSL and
tasks.preDebugBuild
exists, but then the
findByName
would also have found it
m
Copy code
project.tasks.named { it == "preDebugBuild" }.configureEach { println("found one") }
val preDebugBuild = project.tasks.findByName("preDebugBuild")
first one finds it, second does not
I assume named runs later on when task is in fact registered?
v
named { ... }
finds the task immediately if it is already registered, but also finds the task as soon as it is registered and gives you a domain object collection with that task. With
configureEach
you register a configuration action that is executed iff the task is realized, usually because it needs to be executed.
m
thanks both a ton - I might be just able to pull it off
otherwise I'll come here again 😄
👌 1
hehe, if task is registered it also doesn't appear in findByName, ugh
is there a way to force task configuration?
because I register my custom task and then do the named { } thing, but when I try to find my registered task within configureEach, it is not there
aha, because register() returns TaskProvider
to get the instance I have to call get()
v
hehe, if task is registered it also doesn't appear in findByName, ugh
Of course it is. But still, do not use it. You break task-configuration avoidance even if you know the task is registered already.
is there a way to force task configuration?
Yes, but don't do it, you just waste the time of everyone running that build and not wanting to run that task
to get the instance I have to call get()
Don't do this either. Practically any
Provider.get()
at configuration time breaks laziness and wastes time on every build invocation.
m
ok, but then how do I associate preDebugBuild and my customDebug ?
v
Like I said
Copy code
val customDebug by tasks.registering
tasks.named { it == "preDebugBuild" }.configureEach { dependOn(customDebug) }
Besides that
dependsOn
is usually only appropriate if
preDebugBuild
is a lifecycle task, which I don't know as I don't do Android, but given the naming that could be the case.
m
aah, you can dependOn TaskProvider, even better
this is output from build for me (simple app)
Copy code
> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild
> Task :app:mergeDebugNativeDebugMetadata NO-SOURCE
> Task :app:checkKotlinGradlePluginConfigurationErrors SKIPPED
> Task :app:checkDebugAarMetadata UP-TO-DATE
> Task :app:processDebugNavigationResources UP-TO-DATE
> Task :app:compileDebugNavigationResources UP-TO-DATE
> Task :app:generateDebugResValues UP-TO-DATE
> Task :app:mapDebugSourceSetPaths UP-TO-DATE
> Task :app:generateDebugResources UP-TO-DATE
> Task :app:mergeDebugResources UP-TO-DATE
> Task :app:packageDebugResources UP-TO-DATE
> Task :app:parseDebugLocalResources UP-TO-DATE
> Task :app:createDebugCompatibleScreenManifests UP-TO-DATE
> Task :app:extractDeepLinksDebug UP-TO-DATE
> Task :app:processDebugMainManifest UP-TO-DATE
> Task :app:processDebugManifest UP-TO-DATE
> Task :app:processDebugManifestForPackage UP-TO-DATE
> Task :app:processDebugResources UP-TO-DATE
> Task :app:compileDebugKotlin UP-TO-DATE
> Task :app:javaPreCompileDebug UP-TO-DATE
> Task :app:compileDebugJavaWithJavac NO-SOURCE
> Task :app:mergeDebugShaders UP-TO-DATE
> Task :app:compileDebugShaders NO-SOURCE
> Task :app:generateDebugAssets UP-TO-DATE
> Task :app:mergeDebugAssets UP-TO-DATE
> Task :app:compressDebugAssets UP-TO-DATE
> Task :app:processDebugJavaRes UP-TO-DATE
> Task :app:mergeDebugJavaResource UP-TO-DATE
> Task :app:checkDebugDuplicateClasses UP-TO-DATE
> Task :app:desugarDebugFileDependencies UP-TO-DATE
> Task :app:mergeExtDexDebug UP-TO-DATE
> Task :app:mergeLibDexDebug UP-TO-DATE
> Task :app:dexBuilderDebug UP-TO-DATE
> Task :app:mergeProjectDexDebug UP-TO-DATE
> Task :app:mergeDebugJniLibFolders UP-TO-DATE
> Task :app:mergeDebugNativeLibs UP-TO-DATE
> Task :app:stripDebugDebugSymbols UP-TO-DATE
> Task :app:validateSigningDebug UP-TO-DATE
> Task :app:writeDebugAppMetadata UP-TO-DATE
> Task :app:writeDebugSigningConfigVersions UP-TO-DATE
> Task :app:packageDebug UP-TO-DATE
> Task :app:createDebugApkListingFileRedirect UP-TO-DATE
> Task :app:assembleDebug UP-TO-DATE
preDebugBuild looks like the best option for my case (probably) and hopefully Android Studio/gradle won't mangle its name