Build flavors for different version of same class

I've got a project, structured like this:

project/
   |
   |---src/
        |---flavorA2/
        |      |
        |      |---java/
        |      |     |---com.abc.flavorA.mk2
        |      |                 |-----classA.java
        |      |                 |-----classB.java
        |      |---res/
        |      |---AndroidManifest.xml
        |
        |---main
        |      |---java/
        |      |     |---com.abc.flavorA
        |      |                 |-----classA.java
        |      |                 |-----classB.java
        |      |                 |-----classC.java
        |      |                 |-----classD.java
        |      |---res/
        |      |    |---drawable/
        |      |    |---layout/
        |      |    |---values/
        |      |         
        |      |---AndroidManifest.xml
        |
        |---flavorA

flavorA will use the source and assets from main completely while flavorA2 has some small changes in classA and classB and the package name is also changed to com.abc.flavorA.mk2.

I had the build.gradle file like this:

...
buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
    productFlavors {
        flavorA2 {
            packageName "com.abc.flavorA.mk2"
            versionCode 2
            versionName "1.0.1"
        }

        flavorA {
            packageName "com.abc.flavorA"
        }
    }
...

I run the code by selecting the build variant to flavorA2. However the running results shows that the gradle still choose the classes (classA and classB) from main instead of using the changed version inside flavorA2.

Am I missing something here?


Since you have the classes under 2 different packages, these are totally different classes. So the classes aren't replacing each other.

With flavors, you can't override class files. So, one way to accomplish what you want is move these classes out of main, and into flavorA.

So you would have something like this:

project/
   |
   |---src/
        |---flavorA2/
        |      |
        |      |---java/
        |      |     |---com.abc
        |      |                 |-----classA.java
        |      |                 |-----classB.java
        |      |---res/
        |      |---AndroidManifest.xml
        |
        |---main/
        |      |---java/
        |      |     |---com.abc.flavorA
        |      |                 |-----classC.java
        |      |                 |-----classD.java
        |      |---res/
        |      |    |---drawable/
        |      |    |---layout/
        |      |    |---values/
        |      |         
        |      |---AndroidManifest.xml
        |
        |---flavorA/
        |      |---java/
        |      |     |---com.abc
        |      |                 |-----classA.java
        |      |                 |-----classB.java

This way, whenever you pick a flavor, only one version of ClassA and ClassB will be visible.


In the main build variant, Class A is com.abc.flavorA.classA, and in flavorA2 it's com.abc.flavorA.mk2.classA. These are two different fully-qualified class names and therefore two different classes.

You can't really override entire classes in a flavor. Depending on what you want to do, you might want to look into the BuildConfig mechanism -- in short, this is a class that's generated by the build system which can have values or statements that vary depending on the build type and flavor. You can have runtime code that looks at constants in that class and varies its behavior.

See Android Studio Update 0.4.0 could not find buildConfig() for more information on the syntax, but in brief, it looks like this:

productFlavors {
    flavor {
      buildConfigField "boolean", "MY_FLAG", "true"
    }
}

You need to specify sourceSets in your build file. You need to modify your directory structure to make it so that only the folder names are different, everything under the java directory should be the same, so remove the mk2 from the class name. I'm not sure if the syntax is entirely correct but it should look like this:

android {
    sourceSets {
        flavorA {
            java {
                srcDirs = ['src/flavorA/java']
            }
        }

        flavorA2 {
            java {
                srcDirs = ['src/flavorA2/java']
            }
        }
    }
}