curioushikhov curioushikhov - 6 months ago 75
Android Question

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

Answer

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.