Gradle + Annotations + Flavors = won't run annotations processor
Asked Answered
S

1

14

I have a Gradle build script that is using an annotations processor (Android Annotations) to generate code. Building was fine until I added a new Pro Flavor. I can build the Free flavor but when I build the Pro flavor the annotations processor isn't run. This causes missing code and the build fails.

Here is my script:

buildscript {
    repositories {
        maven { url 'http://repo1.maven.org/maven2' }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.5.+'
    }
}
apply plugin: 'android'

repositories {
    mavenCentral()
    maven {
        url 'https://oss.sonatype.org/content/repositories/snapshots/'
    }
}


ext.androidAnnotationsVersion = '3.0-SNAPSHOT';

configurations {
    apt
}


dependencies {
    compile files('libs/android-support-v13.jar')
    compile fileTree(dir: 'libs', include: '*.jar')
    apt "org.androidannotations:androidannotations:${androidAnnotationsVersion}"
    compile "org.androidannotations:androidannotations-api:${androidAnnotationsVersion}"
}

android {
    compileSdkVersion 17
    buildToolsVersion "17.0.0"


    defaultConfig {
        minSdkVersion 7
        targetSdkVersion 17

        versionCode 29
        versionName "2.0.3"
        packageName "com.MyCompany.MyApp"

    }

    productFlavors {
        free {
            buildConfig "final public static boolean PRO_VERSION = false;"
        }
        pro {
            packageName "com.MyCompany.MyApp.Pro"
            versionName (versionName + ".Pro")
            buildConfig "final public static boolean PRO_VERSION = true;"
        }
    }

    buildTypes {
        release {
            buildConfig "final public static String BASE_URL = \"http://data.MyCompany.com/\";", \
                        "final public static String APP_NAME = \"com.MyCompany.MyApp\";"
        }
        debug {
            buildConfig "final public static String BASE_URL = \"http://192.168.1.15/GDM/\";", \
                        "final public static String APP_NAME = \"com.MyCompany.MyApp\";"
        }
    }

}

def getSourceSetName(variant) {
    return new File(variant.dirName).getName();
}

android.applicationVariants.all { variant ->
    def aptOutputDir = project.file("build/source/apt")
    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.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())
    }

    variant.javaCompile.doFirst {
        aptOutput.mkdirs()
    }
}

When building the free variants, the annotations processor is run as indicated by the following in the gradle output:

Note: Starting AndroidAnnotations annotation processing

When building the Pro variants, the annotations processor doesn't run, so the references to the generated code fails.

The curious thing about this is, I found (truly by accident) that if I remove the packageName "com.MyCompany.MyApp.Pro" from the script....the annotations processor runs and it will build correctly. I need to update the the package name for Google Play.

When looking in android studio, you can see that the apt (the Annotation Processing Tool) is showing the Pro version as being active even when I have the FreeDebug build variant selected. I am not sure this is indicative of a problem or if this is just a problem with the beta android studio (Android Studio version: 0.2.13). So take that with a grain of salt.

Build Folders in Android Studio

I'm new to the gradle build system but I thought I was getting the hang of it. I have looked at the script over and over again and I don't see why the annotations processor is not running for the pro variant. And aside from running the wrapper with the --info and --debug arguments, I don't know yet how to debug these problems.

I've run the gradle wrapper with the -info and -debug to get extended output but there is nothing there that indicates any other error (or missing item) until it reaches the error caused by the missing generated code. So this leads me to believe it's just the fact that the androidannotations are not being run with that variant that is the root problem. (i.e. I don't think this is an error caused by something upstream and being misreported later on. I could be wrong though)

I'm really at a loss and have been stuck with this for 2 days now.

Secretariat answered 13/10, 2013 at 22:43 Comment(0)
S
13

I was able to solve the problem. After looking a little closer at the -info output of the gradle wrapper, I found that androidAnnotations was attempting to run. The error output was NOT in the correct order as the annotations processing message came AFTER the errors that were caused by referencing the non-existent code (that didn't exist because annotations processing failed).

Here is the log:

:MyCompany:compileProDebug
....\src\main\java\com\MyCompany\MyApp\Activities\activityMain.java:14: error: cannot find symbol
import com.MyCompany.MyApp.Notifications.NotificationSetupActivity_;
                                                ^
  symbol:   class NotificationSetupActivity_
  location: package com.MyCompany.MyApp.Notifications
....\src\main\java\com\MyCompany\MyApp\Activities\activityMain.java:24: error: cannot find symbol
import com.MyCompany.MyApp.FantasyScores.ActivityScores_;
                                                ^
  symbol:   class ActivityScores_
  location: package com.MyCompany.MyApp.Scores
....\src\main\java\com\MyCompany\MyApp\Activities\activityMain.java:32: error: cannot find symbol
import com.MyCompany.MyApp.Team.activityTeamSelect_;
                                       ^
  symbol:   class activityTeamSelect_
  location: package com.MyCompany.MyApp.Team
Note: Starting AndroidAnnotations annotation processing
Note: AndroidManifest.xml file found: ....\build\manifests\pro\debug\AndroidManifest.xml
error: The generated com.MyCompany.MyAppPro.R class cannot be found
Note: Time measurements: [Whole Processing = 190 ms], [Extract Manifest = 129 ms], [Extract Annotations = 49 ms],
....\src\main\java\com\MyCompany\MyApp\Activities\activityMain.java:14: error: cannot find symbol
import com.MyCompany.MyApp.Notifications.NotificationSetupActivity_;

The important lines are these:

Note: Starting AndroidAnnotations annotation processing

Note: AndroidManifest.xml file found: ....\build\manifests\pro\debug\AndroidManifest.xml

error: The generated com.MyCompany.MyAppPro.R class cannot be found

These should have been first in the error log as the annotations processor runs before the full compile step, but for some reason they were buried deep (maybe a flush problem in the androidannotations processor??)

At any rate, the third line where it can't find the com.MyCompany.MyAppPro.R is the key. The resources are actually in com.MyCompany.MyApp.R (no Pro). After digging a bit, I found this post which indicates this is a known issue with AndroidAnnotations.

I was able to resolve that problem by adding the '-AresourcePackageName=MyBasePackageName', parameter to the build script. NOTE: this only works if you are using the 3.0 snapshot. The latest released version of AndroidAnnotations does not support the -AresourcePackageName option.

After adding the parameter, all variants build correctly.

The compilerArgs section of the build script now looks like this:

variant.javaCompile.options.compilerArgs += [
        '-processorpath', configurations.apt.getAsPath(),
        '-AandroidManifestFile=' + variant.processResources.manifestFile,
        '-AresourcePackageName=MyBasePackageName',
        '-s', aptOutput
]

Hopefully this will help others avoid this problem in the future.

Secretariat answered 14/10, 2013 at 4:30 Comment(2)
Great! Thanks you! Is there any way to pull in the base package name programmatically?Wistful
Back in October I looked briefly to see if I could do it. It wasn't a completely obvious things and I didn't pursue it very thoroughly as I had a tight timeline. It should theoretically be possible to pull it in, but I don't know off hand how to do it.Secretariat

© 2022 - 2024 — McMap. All rights reserved.