I have a problem with migrating my IntelliJ IDEA project to Android Studio using a gradle build. I have set up the AndroidAnnotations library like recommended in various other posts, and it works just fine. But, when compiling my project multiple times without executing the :clean
task in between, I get following error messages:
/project-dir/build/source/apt_generated/flavor1/release/com/example/app/MyActivity_.java:15: error: duplicate class: com.example.app.MyActivity_
[more errors here...]
I believe that multiple builds in series fail because AndroidAnnotations re-creates the *_.java
files always before the :compile
tasks (without checking whether it is necessary or not) and the :compile
task recognizes the new files (e.g using timestamp) but already finds those as pre-compiled *.class
files, thus throwing the error. Is this possible? How can I prevent this behavior? Can I add a necessity-check for AndroidAnnotations? Or is this some other problem?
UPDATE 1: It seems that the error is thrown from AndroidAnnotations itself, since :compile
works when I delete the *.java
files inside the apt_generated
folder manually.
UPDATE 2:
I removed following line from my build.gradle
:
// Automatically add the generated source code to the source set
android.sourceSets[getSourceSetName(variant)].java.srcDirs += aptOutput
I don't exactly know why it works without this line. Since I did not add the folder using Android Studio's Mark Directory as > Sources Root
. Probably this is some result of caching? Or does gradle somehow add my generated java files automatically to the classpath?
I would be thankful for any comments nonetheless.
UPDATE 3 / SOLUTION
After removing the line and synchronizing the gradle build file with Android Studio, the auto-generated source code was removed as Source Root, causing the IDE to show errors of missing classes.
Eventually, I found the solution on the Android Annotations github issues: https://github.com/excilys/androidannotations/issues/676
I re-added the statement for adding it to the source sets (allowing Android Studio to show it as source root). Furthermore, I removed the files from the variants source collection using this:
variant.javaCompile.source = variant.javaCompile.source.filter { p ->
return !p.getPath().startsWith(aptOutputDir.getPath())
}
Now the generated files are recognized, and the duplicate class error is gone.
Best regards, David
Here is my final build.gradle. I hope this helps some of you:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.5.+'
}
}
apply plugin: 'android'
repositories {
mavenCentral()
}
configurations {
// This is the annotations processor dependency configuration.
apt
}
def getSourceSetName(variant) {
return new File(variant.dirName).getName();
}
android {
compileSdkVersion 18
defaultConfig {
versionCode 10
versionName "1.0.2"
targetSdkVersion 17
minSdkVersion 10
}
buildToolsVersion "18.0.1"
buildTypes {
release {
zipAlign true
}
}
productFlavors {
flavor1 {}
flavor2 {}
}
// This has to go after the productFlavors command (otherwise moving the flavor source set root fails).
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
// We move the root of our flavors to support our legacy structure.
flavor1.setRoot('flavors/flavor1')
flavor2.setRoot('flavors/flavor2')
}
applicationVariants.all { variant ->
def aptOutputDir = project.file("${project.buildDir}/source/apt_generated")
def aptOutput = new File(aptOutputDir, variant.dirName)
println "****************************"
println "variant: ${variant.name}"
println "manifest: ${variant.processResources.manifestFile}"
println "aptOutput: ${aptOutput}"
println "****************************"
android.sourceSets[getSourceSetName(variant)].java.srcDirs+= aptOutput.getPath()
variant.javaCompile.doFirst {
println "*** Running AndroidAnnotations for ${variant.name}"
aptOutput.mkdirs()
variant.javaCompile.options.compilerArgs += [
'-processorpath', configurations.apt.getAsPath(),
'-AandroidManifestFile=' + variant.processResources.manifestFile,
'-s', aptOutput
]
}
variant.javaCompile.source = variant.javaCompile.source.filter { p ->
return !p.getPath().startsWith(aptOutputDir.getPath())
}
}
dependencies {
// Android-Annotations
apt 'com.googlecode.androidannotations:androidannotations:2.7.1'
compile 'com.googlecode.androidannotations:androidannotations-api:2.7.1'
// Include libraries only in flavor1
flavor1Compile fileTree(dir: 'libs', include: '*.jar')
}
Here is my (initial) build.gradle
(I stripped of non relevant parts):
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.5.+'
}
}
apply plugin: 'android'
repositories {
mavenCentral()
}
configurations {
// This is the annotations processor dependency configuration.
apt
}
def getSourceSetName(variant) {
return new File(variant.dirName).getName();
}
android {
compileSdkVersion 18
defaultConfig {
versionCode 10
versionName "1.0.2"
targetSdkVersion 17
minSdkVersion 10
}
buildToolsVersion "18.0.1"
buildTypes {
release {
zipAlign true
}
}
productFlavors {
flavor1 {}
}
// This has to go after the productFlavors command (otherwise moving the flavor source set root fails).
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
// We move the root of our flavor to support our legacy structure.
flavor1.setRoot('flavors/flavor1')
}
applicationVariants.all { variant ->
aptOutput = file("${project.buildDir}/source/apt_generated/${variant.dirName}")
println "****************************"
println "variant: ${variant.name}"
println "manifest: ${variant.processResources.manifestFile}"
println "aptOutput: ${aptOutput}"
println "****************************"
// Automatically add the generated source code to the source set
android.sourceSets[getSourceSetName(variant)].java.srcDirs += aptOutput
variant.javaCompile.doFirst {
println "*** Running AndroidAnnotations for ${variant.name}"
aptOutput.mkdirs()
variant.javaCompile.options.compilerArgs += [
'-processorpath', configurations.apt.getAsPath(),
'-AandroidManifestFile=' + variant.processResources.manifestFile,
'-s', aptOutput
]
}
}
}
dependencies {
// Android-Annotations
apt 'com.googlecode.androidannotations:androidannotations:2.7.1'
compile 'com.googlecode.androidannotations:androidannotations-api:2.7.1'
// Include libraries only in flavor1
flavor1Compile fileTree(dir: 'libs', include: '*.jar')
}
I would appreciate any help.
Thanks, David
If you export the build.gradle from Eclipse, it includes .apt_generated in the gradle file and it shouldn't. Take this out and these errors should go away.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With