83

I have two product flavors for my app:

productFlavors {
    europe {
        buildConfigField("Boolean", "BEACON_ENABLED", "false")
    }

    usa {
        buildConfigField("Boolean", "BEACON_ENABLED", "true")
    }
}

Now I want to get the current flavor name (which one I selected in Android Studio) inside a task to change the path:

task copyJar(type: Copy) {
    from('build/intermediates/bundles/' + FLAVOR_NAME + '/release/')
}

How can I obtain FLAVOR_NAME in Gradle?

Thanks

user1506104
  • 6,554
  • 4
  • 71
  • 89
Giulio Bider
  • 1,386
  • 2
  • 10
  • 20
  • There is no "current flavor". The Gradle build file is building an object model of the build process. It is not an interpreted script only being used once a build is underway and a "current flavor" is known. – CommonsWare Jun 03 '15 at 13:38
  • 2
    There must be a way to retrieve that value because it changes paths in buildDir. – Giulio Bider Jun 03 '15 at 14:02
  • You do what azertiti's answer shows: configure all the build variants. – CommonsWare Jun 03 '15 at 14:05
  • @CommonsWare : As you said "current flavor" is know . Is there a way to retrieve it ?? – Code_Life Dec 22 '15 at 10:51
  • @Code_Life: There is no "current flavor". The Gradle build file is building an object model of the build process. It is not an interpreted script. – CommonsWare Dec 22 '15 at 11:56
  • 12
    @CommonWare You keep telling people this. What about using android Studio with Gradle makes people think that their task should be able to know what value is currently selected and able to be used by a task AFTER Gradle has built its model up. The question is flawed yes, its not Gradle if you want to be pedantic seeing your responses to this is comical now, so take that vast Gradle knowledge and looking beyond the pedantic short comings of the question, how does a task, defined inside a .gradle file, know what variant is selected when the task/command is run? That is the question I believe.\o/ – Hunter-Orionnoir May 20 '16 at 18:43
  • 1
    @CommonsWare (I'm not saying your response is comical btw!!! In reread my comment comes off 'possibly' attackish. Which is not the intent. It's just such a common frustration in learning Gradle integration into Android Studio to be interpret/expect state since its 'got code in it' as such it has become comical to me now. :P I've read it a 100 times, but until I wrestled it head on and came to terms with it I don't know if most folks will understand until that wall is hit head on. – Hunter-Orionnoir May 20 '16 at 18:58

14 Answers14

106

How to get current flavor name

I have developed the following function, returning exactly the current flavor name:

def getCurrentFlavor() {
    Gradle gradle = getGradle()
    String  tskReqStr = gradle.getStartParameter().getTaskRequests().toString()

    Pattern pattern

    if( tskReqStr.contains( "assemble" ) ) // to run ./gradlew assembleRelease to build APK
        pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
    else if( tskReqStr.contains( "bundle" ) ) // to run ./gradlew bundleRelease to build .aab
        pattern = Pattern.compile("bundle(\\w+)(Release|Debug)")
    else
        pattern = Pattern.compile("generate(\\w+)(Release|Debug)")

    Matcher matcher = pattern.matcher( tskReqStr )

    if( matcher.find() )
        return matcher.group(1).toLowerCase()
    else
    {
        println "NO MATCH FOUND"
        return ""
    }
}

You need also

import java.util.regex.Matcher
import java.util.regex.Pattern

at the beginning or your script. In Android Studio this works by compiling with "Make Project" or "Debug App" button.

How to get current build variant

def getCurrentVariant() {
    Gradle gradle = getGradle()
    String tskReqStr = gradle.getStartParameter().getTaskRequests().toString()

    Pattern pattern

    if (tskReqStr.contains("assemble"))
        pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
    else
        pattern = Pattern.compile("generate(\\w+)(Release|Debug)")

    Matcher matcher = pattern.matcher(tskReqStr)

    if (matcher.find()){
        return matcher.group(2).toLowerCase()
    }else{
        println "NO MATCH FOUND"
        return ""
    }
}

How to get current flavor applicationId

A similar question could be: how to get the applicationId? Also in this case, there is no direct way to get the current flavor applicationId. Then I have developed a gradle function using the above defined getCurrentFlavor function as follows:

def getCurrentApplicationId() {
    def currFlavor = getCurrentFlavor()

    def outStr = ''
    android.productFlavors.all{ flavor ->

        if( flavor.name==currFlavor )
            outStr=flavor.applicationId
    }

    return outStr
}

Voilà.

Harry T.
  • 3,478
  • 2
  • 21
  • 41
Poiana Apuana
  • 1,406
  • 1
  • 10
  • 16
  • 3
    is there a possibility to get current flavor *applicationId*? – Volodymyr Jan 20 '17 at 12:46
  • @Igor: Here the purpose is to get the flavor name, and the script gives that, not the build type. I don't get your point. – Poiana Apuana May 21 '17 at 10:48
  • @PoianaApuana You are trying to pattern match on **Release|Debug** - which are build types. OP is looking to find **europe** or **usa** flavors. Do you see the difference between flavors and build types? If not, read this: https://developer.android.com/studio/build/build-variants.html#build-types – IgorGanapolsky May 21 '17 at 12:43
  • 2
    @Igor: I think you have not understood at all what the script does. Many developers use this script everyday to get the **current flavor**. There is no direct way to get the current flavor; the call _getGradle().getStartParameter().getTaskRequests()_ gives something like _generateEuropeDebugSources_ or _generateEuropeReleaseSources_ (if _europe_ is the current flavor) depending on the current build type; then the Pattern class **extracts the flavor name, not build type**. Before replying, please study what the Pattern class does in the script. – Poiana Apuana May 21 '17 at 18:32
  • @Volodymyr: there is no direct way to get the current flavor applicationId. However I have updated my answer including a function to get the current applicationId. Sorry if I am a bit late. – Poiana Apuana May 22 '17 at 17:39
  • @Patrick did you found solution for this problem? I am trying to handle it right now – Jakub Anioła May 23 '19 at 11:17
  • 2
    Where should I call this function in the file gradle.build? If I try to call it for selectively applying some plugin it doesn't work. – rraallvv May 29 '19 at 16:45
  • How to call getCurrentFlavor() in Activities? – Alireza Noorali Mar 04 '20 at 10:40
  • 1
    @AlirezaNoorali you can call getCurrentFlavor() in a task in build.gradle. See https://guides.gradle.org/writing-gradle-tasks/ to learn about gradle tasks. – Poiana Apuana Mar 07 '20 at 09:28
  • 1
    Can someone explain me why I am getting value of gradle.getStartParameter().getTaskRequests().toString() as empty i.e. [ ]. – gaurav24 Mar 08 '20 at 17:04
  • @gaurav24 that only happens during gradle sync because the sync has no flavor. Once you trigger a build, it will work. Except in my case I had to use the index 1 to get the flavor: `matcher.group(1).toLowerCase()` – WarrenFaith Mar 30 '20 at 10:01
  • 2
    This doesn't seem to work if "gradlew build" is run from the command line. tskReqStr is [DefaultTaskExecutionRequest{args=[build],projectPath='null'}]. Works fine if building from Android Studio – AlanKley Aug 08 '20 at 19:59
  • 1
    Same problem: tskReqStr = [DefaultTaskExecutionRequest{args=[],projectPath='null'}] – matdev May 06 '21 at 09:39
  • As noted above, this works on Android studio and on command line if you give variant, but it will not work if your give at command line './gradlew build' to build all variants at once. – diidu Sep 01 '22 at 13:31
  • For anyone using 1st script will get into trouble when building AAB because "assemble" not exist in "bundle" command. – Harry T. Oct 07 '22 at 14:29
  • @TruongHieu in first example "How to get current flavor name" there are 2 comments: "to run ./gradlew assembleRelease to build APK" and "to run ./gradlew bundleRelease to build .aab". Probably they should be worded as "if run as ...", bcz it looks like you have to run something after the script. – Ross Jan 26 '23 at 06:48
  • @Ross I understand the comments but the editor better edit executable lines. I have recorrected it, you can check the history. – Harry T. Jan 27 '23 at 07:44
  • With react native, for the command line to work I also had to add "install" as another pattern to check against. – dwxw Jan 27 '23 at 11:38
27

I use this

${variant.getFlavorName()}.apk

to format file name output

Matthias
  • 4,481
  • 12
  • 45
  • 84
Timtcng.sen
  • 363
  • 4
  • 3
13

you should use this,${variant.productFlavors[0].name},it will get productFlavors both IDE and command line.

Dartan Li
  • 217
  • 2
  • 5
  • 8
    How can I get `variant` variable in concrete flavor block? – mohax Jul 17 '17 at 19:45
  • 3
    This snippet depends on nesting inside a `applicationVariants.all { variant ->` loop. This returns the first flavor, which is only relevant when performing a single output build. – Abandoned Cart Apr 26 '18 at 04:41
7

This is what I used some time ago. I hope it's still working with the latest Gradle plugin. I was basically iterating through all flavours and setting a new output file which looks similar to what you are trying to achieve.

applicationVariants.all { com.android.build.gradle.api.ApplicationVariant variant ->
    for (flavor in variant.productFlavors) {
        variant.outputs[0].outputFile = file("$project.buildDir/${YourNewPath}/${YourNewApkName}.apk")
    }
}
azertiti
  • 3,150
  • 17
  • 19
6

my solution was in that to parse gradle input parameters.

Gradle gradle = getGradle()

Pattern pattern = Pattern.compile(":assemble(.*?)(Release|Debug)");
Matcher matcher = pattern.matcher(gradle.getStartParameter().getTaskRequests().toString());
println(matcher.group(1))
Nazar Ivanchuk
  • 127
  • 1
  • 7
5

I slightly changed Poiana Apuana's answer since my flavor has some capital character.

REASON
gradle.getStartParameter().getTaskRequests().toString() contains your current flavor name but the first character is capital.
However, usually flavor name starts with lowercase. So I forced to change first character to lowercase.

def getCurrentFlavor() {
    Gradle gradle = getGradle()
    String taskReqStr = gradle.getStartParameter().getTaskRequests().toString()
    Pattern pattern
    if (taskReqStr.contains("assemble")) {
        pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
    } else {
        pattern = Pattern.compile("generate(\\w+)(Release|Debug)")
    }
    Matcher matcher = pattern.matcher(taskReqStr)
    if (matcher.find()) {
        String flavor = matcher.group(1)
        // This makes first character to lowercase.
        char[] c = flavor.toCharArray()
        c[0] = Character.toLowerCase(c[0])
        flavor = new String(c)
        println "getCurrentFlavor:" + flavor
        return flavor
    } else {
        println "getCurrentFlavor:cannot_find_current_flavor"
        return ""
    }
}
wonsuc
  • 3,498
  • 1
  • 27
  • 30
  • 4
    Can you please tell me why I am getting value of gradle.getStartParameter().getTaskRequests().toString() as empty i.e. [ ] in my app's build.gradle ? – gaurav24 Mar 08 '20 at 17:05
4

get SELECTED_BUILD_VARIANT from the .iml file after gradle sync completes You can either load it using an xml parser, or less desireable, but probably faster to implement would be to use a regex to find it.

<facet type="android" name="Android">
  <configuration>
    <option name="SELECTED_BUILD_VARIANT" value="your_build_flavorDebug" />
        ...

(not tested, something like this:)

/(?=<name="SELECTED_BUILD_VARIANT".*value=")[^"]?/
Nick
  • 2,735
  • 1
  • 29
  • 36
4

Use:

${variant.baseName}.apk"

This return current flavor name

Full Answer

android.applicationVariants.all { variant ->
    variant.outputs.all {
        outputFileName = "${variant.baseName}.apk"
    }
}
Ali Asadi
  • 987
  • 10
  • 13
2

You can use gradle.startParameter.taskNames[0]

Floern
  • 33,559
  • 24
  • 104
  • 119
B3n
  • 536
  • 1
  • 3
  • 16
  • `gradle.startParameter.taskNames[0].contains("debug")` - Cannot invoke method contains() on null object – user924 Oct 06 '18 at 09:35
  • This fails on Sync, so must be wrapped in some `if`. – Alex Cohn Apr 15 '20 at 12:22
  • didn't work as expected, because you can call `./gradlew aD` for "flavor" `assembleDebug`, and in that case returned flavor is `aD` not `assembleDebug`. – mtrakal Apr 26 '23 at 11:58
2

Just add the following in your build.gradle (app level)

def getCurrentFlavour() {
  Gradle gradle = getGradle()
  String tskReqStr = gradle.getStartParameter().getTaskRequests().toString()
  print(tskReqStr.toString())

  Pattern pattern;
  if( tskReqStr.contains( "assemble" ))
    pattern = Pattern.compile("assemble(\\w+)(Release|Staging|Debug)")
  else
    pattern = Pattern.compile("generate(\\w+)(Release|Staging|Debug)")
  Matcher matcher = pattern.matcher( tskReqStr )
  if( matcher.find() ) {
    def value = matcher.group(1).toLowerCase()
    return value
  } else {
    return "";
  }
}

Now Inside android tag,

android {  
// android tag starts
 defaultConfig {
  - - - - - - - - 
  - - - - - - - - 
 }
 - - - - - - - - 
 - - - - - - - - 
 
 def flavourName = getCurrentFlavour()
  if (flavourName == "Dev") {
    println("This is Dev")
   } else if (flavourName == "Staging") {
    println("This is Staging")
   } else if (flavourName == "Production") {
    println("This is Production")
   } else {
    println("NA")
   }
// android tag ends
}

Now Sync & Build your project.

logoff
  • 3,347
  • 5
  • 41
  • 58
Nanda Gopal
  • 2,519
  • 1
  • 17
  • 25
1

A combination of aforementioned snippets was needed for me to get this to work.

My full answer to the original question would look like this:

android {
    ...
    applicationVariants.all { variant ->
        task "${variant.getName()}CopyJar"(type: Copy) {
            from("build/intermediates/bundles/${variant.getFlavorName()}/release/")
        }
    }
}

This creates a <variant>CopyJar task for each variant, which you can then run manually.

wamfous
  • 1,849
  • 1
  • 12
  • 11
0

How to get the flavor name or build variant from a prebuild task? This is what solved my issue. I added getCurrentFlavor() or getCurrentVariant() (from @Poiana Apuana answer) into my task's dependOn like so:

task getCurrentFlavor() {
    // paste Poiana Apuana's answer
}

// OR
//task getCurrentVariant() {
//  // paste Poiana Apuana's answer
//}

task myTask(type: Copy) {
    dependsOn getCurrentFlavor
    // or dependsOn getCurrentVariant
    println "flavor name is $projectName"
    ...
}
preBuild.dependsOn myTask

Check original problem here.

user1506104
  • 6,554
  • 4
  • 71
  • 89
0

Here is the "official" getFlavour() function you may find in react-native-config package. Probably it's most accurate.

def getCurrentFlavor() {
    Gradle gradle = getGradle()

    // match optional modules followed by the task
    // (?:.*:)* is a non-capturing group to skip any :foo:bar: if they exist
    // *[a-z]+([A-Za-z]+) will capture the flavor part of the task name onward (e.g., assembleRelease --> Release)
    def pattern = Pattern.compile("(?:.*:)*[a-z]+([A-Z][A-Za-z0-9]+)")
    def flavor = ""

    gradle.getStartParameter().getTaskNames().any { name ->
        Matcher matcher = pattern.matcher(name)
        if (matcher.find()) {
            flavor = matcher.group(1).toLowerCase()
            return true
        }
    }

    return flavor
}
Ross
  • 1,641
  • 3
  • 15
  • 16
  • didn't work as expected, because you can call `./gradlew aD` for "flavor" `assembleDebug`, and in that case returned flavor is `aD` not `assembleDebug`. – mtrakal Apr 26 '23 at 11:53
-2

You can make a check of flavours. Suppose your gradle is like

productFlavors {
        test{
            ...
            buildConfigField "String", "VARIANT", "\"test\""
        }
        prod{
            ...
            buildConfigField "String", "VARIANT", "\"prod\""
        }
}

Now by using the below code you can check your flavour.

if (BuildConfig.FLAVOR.equals("test")){
    // do what you need to do for the test version
} else {
    // do what you need to do for the prod version
}