49

I have a question, but I'm sitting here in front of my app since hours but I can't understand what the problem is.

I have an android app (written in kotlin) and I want to make two product flavors and override a class / file in the product flavor:

So my gradle script is that:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'


android {
  ...
  productFlavors {
    foo {
      applicationId "com.foo"
    }
  }
}

My files are structured as follows:

 - src
    - androidTest
    - foo
      - java
        - com
          - example
            - Bar.kt
    - main
      - java
        - com
          - example
            - Bar.kt
    - test

So basically I would like to override Bar.kt file in foo product flavor, but somehow it doesn't work: It says class Bar is duplicated.

Any hint?

Augusto Carmo
  • 3,291
  • 1
  • 16
  • 39
sockeqwe
  • 14,614
  • 22
  • 78
  • 136
  • 5
    Shouldn't flavor-specific sources exist only in the falvors you've defined (i.e. not in main)? So you'd define at least two flavors, and only have Bar.kt in the source sets for those flavors. – Michael May 25 '16 at 14:23
  • Hm, maybe you are right ... actually I am trying to override a dagger module ... so `Bar.kt` is actually a Dagger 2 module – sockeqwe May 25 '16 at 14:29
  • Possible duplicate of [Android gradle buildTypes: Duplicate class](http://stackoverflow.com/questions/18782368/android-gradle-buildtypes-duplicate-class) – miensol May 25 '16 at 14:51
  • You can check out my answer: https://stackoverflow.com/questions/28563632/common-code-for-different-android-flavors/66141092#66141092 – matdev Feb 12 '21 at 10:52

3 Answers3

62

The documentation for variants states (emphasis mine):

Note: For a given build variant, Gradle throws a build error if it encounters two or more source set directories that have defined the same Java class. For example, when building a debug APK, you cannot define both src/debug/Utility.java and src/main/Utility.java. This is because Gradle looks at both these directories during the build process and throws a 'duplicate class' error. If you want different versions of Utility.java for different build types, you can have each build type define its own version of the file and not include it in the main/ source set.

So the solution is to have it's own version of Bar.kt per variant and exclude it from main source set.

miensol
  • 32,791
  • 6
  • 103
  • 105
  • 15
    If I have say 4-5 flavours, and 3 of them use the same class and the set use specific code, do I need to duplicate it everywhere or sourceSets can do it? Not able to do with source sets – Akhil Dad Jan 09 '17 at 09:05
  • 4
    @AkhilDad I guess you could create a separate module to share the code across flavours. – miensol Jan 28 '17 at 09:59
  • Or add another flavour dimension for that. – plaisthos May 27 '20 at 11:31
28

As stated by miensol you cannot put your file to main and flavor specific folders and expect gradle to work the same way android resource system works. But I found a way to do this without code duplication so you don't have to copy your Bar.kt to every flavor folder you have.

So let's say you have three flavors dev, prod and mock. You want your special mocked Bar.kt in mock but the normal implementation in dev and prod flavors. You put your mocked file to the mock flavor specific folder mock/java/com/something/ and you put your "default" implementation to new folder with some random name like non-mock/java/com/something/ naming it something like "common" would also make sense. Now you have to tell gradle where should those flavors look for their Bar.kt class.

Put this in to your build.gradle:

android {
    ...
    sourceSets {
        prod {
            java.srcDirs('src/non-mock/java')
        }
        dev {
            java.srcDirs('src/non-mock/java')
        }
    }

}
Semanticer
  • 1,823
  • 1
  • 16
  • 26
16

If you have multiple flavors, Like A, B and C

and your main code contains all activities, and for A and C flavor you want to change some functionality of some activity ex- ShoppingCartActivity

then you need to make some changes as below, put ShoppingCartActivity in all three flavors (including B as well) and remove from main and declare the file into all manifest file other than main manifest

for more details check Build with source sets

- A
  - java
    - com
      - example
        - ShoppingCartActivity.kt(some changes)

- B
  - java
    - com
      - example
        - ShoppingCartActivity.kt

- C
  - java
    - com
      - example
        - ShoppingCartActivity.kt(new changes added)

- main
  - java
    - com
      - example
        **(remove from here)**
Vivek Hande
  • 539
  • 4
  • 8
  • is there any way to use a base of ShoppingCartActivity on main and in case I have another one inside other flavor so I use the flavor one instead? – Igor Romcy Oct 09 '20 at 16:57