curioushikhov
curioushikhov

Reputation: 2838

How to setup flavors for android gradle project? Mysterious duplicate class error

I have created simple test project: the goal is to show the message 'hello' by pressing a button on the screen. The first flavor build should write the message to the system log. The second flavor build should show a toast with message. How can this be achieved using gradle please?

My build.gradle:

apply plugin: 'android'

android {
compileSdkVersion 19
buildToolsVersion "19.0.1"

defaultConfig {
    minSdkVersion 14
    targetSdkVersion 19
    versionCode 1
    versionName "1.0"
}

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_7
    targetCompatibility JavaVersion.VERSION_1_7
}

productFlavors {
    toast {

    }
    log {

    }
}

sourceSets {

    main {
        java.srcDirs = ['src/main/java', 'src/log/java']
    }

    toast {
        java.srcDirs = ['src/main/java', 'src/toast/java']
    }
}

buildTypes {
    release {
        runProguard false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
}

File structure: File structure

Flavor log contains single class Messenger with method showMessage(Context context, CharSequence text) and prints text using Log.i(tag, msg)

Flavor toast contains single class Messenger with method showMessage(Context context, CharSequence text) and shows toast with some text.

Main sources don't contain this class.

Why does the error duplicate class:com.test.flavortest.Messenger appear? Each flavor has a set of different non-crossing source paths?

Full sample project, zipped

Upvotes: 5

Views: 3476

Answers (3)

FengYi Ya
FengYi Ya

Reputation: 1

All source code in the java/ directories are compiled together to generate a single output.

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.

Upvotes: 0

antonyt
antonyt

Reputation: 21883

In your sourcesets definition, you seem to be adding the log sources to main:

sourceSets {

    main {
        java.srcDirs = ['src/main/java', 'src/log/java']
    }

    toast {
        java.srcDirs = ['src/main/java', 'src/toast/java']
    }
}

main is the default sourceset included in all flavors. This would cause a duplicate class (Messenger) being loaded when building the toast flavor.

Try specifying the log and toast sourcesets only:

sourceSets {

    log {
        java.srcDirs = ['src/main/java', 'src/log/java']
    }

    toast {
        java.srcDirs = ['src/main/java', 'src/toast/java']
    }
}

Your file structure seems to match the default, so an even better solution would be to remove the sourcesets block entirely. src/main/java is included by default, and then src/flavor/java is added afterwards automatically.

Upvotes: 3

Benjamin Stürmer
Benjamin Stürmer

Reputation: 545

Use assembleToast / assembleLog to Build an specific Flavour. Same for installToast e.g

The global assemble will use every File in the directory.

Upvotes: 0

Related Questions