100

I'm trying to work with build flavors. In my build.gradle I've defined 2 flavors, a normal flavor and an admin flavor.

Basicly, the admin flavor has an extra button on the main activity.

I understand that I can define different packages/classes for different flavors. But is there a way to make a sort of if case to add/remove a piece of code depending on the flavor?

Basicly, I would need two versions of an Activity. But I don't want two entire different versions of the activity and maintain them.

So in my activity I would like to do

=> gradle check if flavor is 'admin'

=> if yes, add this code of the button

Is this possible? Or would you need two different physical activities and thus maintain both of them when you add functionality afterwards.

auspicious99
  • 3,902
  • 1
  • 44
  • 58
Stephan Celis
  • 2,492
  • 5
  • 23
  • 38

4 Answers4

156

BuildConfig.FLAVOR gives you combined product flavor. So if you have only one flavor dimension:

productFlavors {
    normal {
    }

    admin {
    }
}

Then you can just check it:

if (BuildConfig.FLAVOR.equals("admin")) {
    ...
}

But if you have multiple flavor dimensions:

flavorDimensions "access", "color"

productFlavors {
    normal {
        dimension "access"
    }

    admin {
        dimension "access"
    }

    red {
        dimension "color"
    }

    blue {
        dimension "color"
    }
}

there are also BuildConfig.FLAVOR_access and BuildConfig.FLAVOR_color fields so you should check it like this:

if (BuildConfig.FLAVOR_access.equals("admin")) {
    ...
}

And BuildConfig.FLAVOR contains full flavor name. For example, adminBlue.

mixel
  • 25,177
  • 13
  • 126
  • 165
  • NOTE: `flavorDimension` was replaced by `dimension` in Gradle 2.0. – dermatthias Mar 24 '17 at 09:32
  • 1
    @mixel just out of curiosity, in this implementation, we need to include ALL logic into one single build. Any one can decompile the apk and rebuild if needed to simple change the boolean? Why not extract the logic and place the logic in different folder and use `souceSets` to decide which folder to fetch? in this way, there is no issue for exposing entire logic to the world. – bj4947 Oct 18 '17 at 17:11
  • @IHC_Applroid Yes. OP said: "I understand that I can define different packages/classes for different flavours", so I think it's not an option for him to place code in different `sourceSets`. – mixel Oct 18 '17 at 18:43
  • @IHC_Applroid the Idea was that if I need to build two separate Activities, and something needs to change, I would need to change it every time twice. This would decrease the maintainability of the application. Hence I was looking something like this. Although I agree with the potential security risk you mentioned. But in my personal case I was willing to take that risk. – Stephan Celis Aug 02 '18 at 08:53
  • better to code this way `if ("admin".equals(BuildConfig.FLAVOR))` in case BuildConfig is null – chrizonline Mar 22 '19 at 02:52
  • @nuttynibbles In most cases I agree with you, but here I prefer application to throw a `NullPointerException` if `BuildConfig.FLAVOR` is null. – mixel Mar 22 '19 at 10:26
  • i need to do the same thing but in another module, like my product falvors are defined in the main module's(app) build.gradle, but how can i get the flavour value in my other module(ex: library module)?? – Vishal Pandey Oct 03 '19 at 09:41
86

To avoid plain string in the condition, you can define a boolean property:

productFlavors {
    normal {
        flavorDimension "access"
        buildConfigField 'boolean', 'IS_ADMIN', 'false'
    }

    admin {
        flavorDimension "access"
        buildConfigField 'boolean', 'IS_ADMIN', 'true'
    }
}

Then you can use it like this:

if (BuildConfig.IS_ADMIN) {
    ...
}
user2878850
  • 2,446
  • 1
  • 18
  • 22
  • When writing it, it's marked with line-through, which is deprecation. What should be used instead, and how? – android developer May 24 '17 at 10:22
  • I have kept a few strings like this in the build.gradle file but it doesn't tell me deprecation. – Madhan Apr 16 '18 at 12:02
  • @androiddeveloper See https://stackoverflow.com/questions/24119557/android-using-gradle-build-flavors-in-the-code-like-an-if-case#comment73081757_30334392 (1st comment to the accepted answer) – Abandoned Cart Apr 26 '18 at 04:05
  • @LoungeKatt So use "dimension" instead. OK. – android developer Apr 26 '18 at 13:00
  • The rest should still be current, but I only use one dimension. It was easier to stick with `BuildConfig.FLAVOR.equals` in my code. – Abandoned Cart Apr 26 '18 at 14:31
  • If you have N flavors then each should have N `buildConfigField` boolean constants, one of each constants set should be true and overs false . So it can get really messy in that case. – Johnny Five Jun 14 '19 at 08:08
  • @user2878850 's answer is good. But if you want to avoid some warning like "Condition is always 'false'" , I prefer to write `buildConfigField 'boolean', 'IS_ADMIN', 'Boolean.parseBoolean("false")'` , this is also the compiler generate code of the `BuildConfig.DEBUG` – ininmm Aug 06 '19 at 05:52
0

You can define either different build configuration fields or different resource values (like string values) per flavor, e.g. (as per Google's gradle tips and recipes), e.g.,

android {
  ...
  buildTypes {
    release {
      // These values are defined only for the release build, which
      // is typically used for full builds and continuous builds.
      buildConfigField("String", "BUILD_TIME", "\"${minutesSinceEpoch}\"")
      resValue("string", "build_time", "${minutesSinceEpoch}")
      ...
    }
    debug {
      // Use static values for incremental builds to ensure that
      // resource files and BuildConfig aren't rebuilt with each run.
      // If they were dynamic, they would prevent certain benefits of
      // Instant Run as well as Gradle UP-TO-DATE checks.
      buildConfigField("String", "BUILD_TIME", "\"0\"")
      resValue("string", "build_time", "0")
    }
  }
}

So in this case, something like

productFlavors {
    normal {
        dimension "access"
        buildConfigField("boolean", "IS_ADMIN", "false")
    }

    admin {
        dimension "access"
        buildConfigField("boolean", "IS_ADMIN", "true")
    }
}

and then use it like

if (BuildConfig.IS_ADMIN) {
    ...
} else {
    ...
}

or if it is just to have different string values for different flavors, it can be done with different resValues and then you don't even need the if/then

auspicious99
  • 3,902
  • 1
  • 44
  • 58
0

You can try this way

   productFlavors {
    def app_name = "you app name"
    development {
        versionCode 1
        versionName "1.0.1"          
        buildConfigField 'String', 'varibalename', ""           
    }

    release {
        versionCode 1
        versionName "1.0.1"               
        buildConfigField 'String', 'varibalename', ""           
    }     
}

if(BuildConfig.varibalename){}

gpuser
  • 1,143
  • 1
  • 9
  • 6