42

I have a very simple build.gradle file with the following content:

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:0.4.1'
    }
}

apply plugin: 'android'

android {
    buildToolsVersion "17.0.0"
    compileSdkVersion 17

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }
    }
}

task generateSources {
    doFirst {
        def script = "python GenerateSources.py".execute()
        script.in.eachLine {line -> println line}
        script.err.eachLine {line -> println "ERROR: " + line}
        script.waitFor()
    }
}

What I want is to run generateSources task before java compilation is started. I found several solutions how to do that, like compileJava.dependsOn("generateSources"), but unfortunately they give an error:

A problem occurred evaluating root project 'Android'.
> Could not find property 'compileJava' on root project 'Android'.

I don't know Gradle and can't understand what's wrong with this code. So I would like to know how I can fix this error.

Michael
  • 53,859
  • 22
  • 133
  • 139
  • I thinks in this thread you will find solution [assembleRelease task dependency - Ask for keystore password][1] [1]: http://stackoverflow.com/questions/17144878/assemblerelease-task-dependency-ask-for-keystore-password – skyrylyuk Sep 15 '13 at 11:37

5 Answers5

30

Apparently, the android plugin doesn't add a compileJava task (like the java plugin would). You can check which tasks are available with gradle tasks --all, and pick the right one for your (otherwise correct) dependency declaration.

EDIT:

Apparently, the android plugin defers creation of tasks in such a way that they can't be accessed eagerly as usual. One way to overcome this problem is to defer access until the end of the configuration phase:

gradle.projectsEvaluated {
    compileJava.dependsOn(generateSources)
}

Chances are that there is a more idiomatic way to solve your use case, but quickly browsing the Android plugin docs I couldn't find one.

Peter Niederwieser
  • 121,412
  • 21
  • 324
  • 259
  • What is it that doesn't work, and what's the exact error message? – Peter Niederwieser May 31 '13 at 09:21
  • 2
    The problem is the same as before: `Could not find property 'compileDebug' on root project 'Android'.` – Michael May 31 '13 at 09:25
  • And you verified that `compileDebug` exists? Does `gradle compileDebug` work? Did you add the dependency declaration at the bottom of the build script? You can also try `tasks.compileDebug`, but it shouldn't make a difference. – Peter Niederwieser May 31 '13 at 09:34
  • `gradle compileDebug` works fine. At the bottom of the file I added `compileDebug.dependsOn("generateSources")`. When I write `tasks.compileDebug` instead of `compileDebug` gradle gives me an error `Could not find property 'compileDebug' on task set.` – Michael May 31 '13 at 09:41
  • Browsing the Android plugin docs, I realized that it works quite differently from most other plugins. Does `gradle.projectsEvaluated { tasks.compileDebug.dependsOn(generateSources) }` work? Probably there's a more idiomatic way though. – Peter Niederwieser May 31 '13 at 09:49
  • Yeah, seems it works! Could you please add it to the answer and explain what it means? – Michael May 31 '13 at 09:58
  • Awesome - have been at this for days now not understanding why the usual dependsOn failed for the pre defined tasks. Now I can finally add a dependency to the connectedCheck. – slott Dec 18 '13 at 12:53
  • Hello Peter Niederwieser, it giving me below error. Could not find property 'compileJava' on com.android.build.gradle.AppExtension_Decorated@44b35022. – Dhrupal Mar 04 '14 at 10:38
  • 1
    The task name seems to have changed to [`compileDebugJava`](https://android.googlesource.com/platform/tools/base/+/master/build-system/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy#1076). – ento Jun 17 '14 at 13:24
  • I've got a task that needs to run before the Android build. Task copies a jar file into the libs directory. Somehow, this happends too late for the Android build. My android build always fails the first time after a clean. Then the second time it works ( since the jar file is there then). How do run the task that copies the jar file soon enough? – treesAreEverywhere Aug 07 '14 at 13:29
  • @PeterNiederwieser any chance you can update your answer? It's seems to be quite out of date. (Sorry if this sounds a bit rude, it's not meant that way) – treesAreEverywhere Aug 07 '14 at 13:45
  • Why is it out of date? – Peter Niederwieser Aug 07 '14 at 13:48
  • Well, your answer still says "compileJava.dependsOn(...)" which doesnt work, as discussed in comments. – Greg Ennis Sep 11 '14 at 12:48
  • `./gradlew tasks --all` in the project directory also shows the task's description. – Martin Zeitler Aug 10 '16 at 15:29
28

The proper way to run a task before Java compilation on Android is to make a compilation task for each variant depend on your task.

afterEvaluate {
  android.applicationVariants.all { variant ->
    variant.javaCompiler.dependsOn(generateSources)
  }
}
Michael
  • 53,859
  • 22
  • 133
  • 139
15

You can see task execution in terminal running task for example gradle assemble. Try this one, it is started practically before anything.

android {
    ...
    gradle.projectsEvaluated {
         preBuild.dependsOn(generateSources)
    }
    ...
}

Edit, this may not work in Android Studio, as the Android Gradle DSL does not have a projectsEvaluated method.

Henadzi Rabkin
  • 6,834
  • 3
  • 32
  • 39
7

Try this:

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:0.4.1'
    }
}

apply plugin: 'android'

android {
    buildToolsVersion "17.0.0"
    compileSdkVersion 17

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }
    }
}

task generateSources {
    def script = "python GenerateSources.py".execute()
    script.in.eachLine {line -> println line}
    script.err.eachLine {line -> println "ERROR: " + line}
    script.waitFor()
}

project.afterEvaluate {
    preBuild.dependsOn generateSources
}

clean.dependsOn generateSources
clean.mustRunAfter generateSources

The last two lines are optional - they will invoke the "generateSources" task when executing a gradle clean

Phileo99
  • 5,581
  • 2
  • 46
  • 54
0

For those having a multi-project build and needing to run a task for each project before they're built (but it should also be ok if you have only the app project), you can write the task in the root build configuration script inside the allprojects closure and executing the task right there.

In root project build.gradle:

allprojects {
    repositories {
        // ...
    }
    // ...
    task mytask {
        doFirst {
            println project.projectDir.name
        }
    }
    mytask.execute()
}

It will be executed for every build variant as well.

Gradle 4.1

devrocca
  • 2,497
  • 2
  • 19
  • 27
  • 1
    This is bad since it will run for every invocation. Including things like clean which probably isn't what you want. Depending on what it does it could trigger uptodate checks to do more things. – ottago May 04 '18 at 05:33