Run task before compilation using Android Gradle plugin

38,943

Solution 1

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)
  }
}

Solution 2

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.

Solution 3

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.

Solution 4

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

Share:
38,943
Michael
Author by

Michael

Updated on July 09, 2022

Comments

  • Michael
    Michael almost 2 years

    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.

  • Peter Niederwieser
    Peter Niederwieser about 11 years
    What is it that doesn't work, and what's the exact error message?
  • Michael
    Michael about 11 years
    The problem is the same as before: Could not find property 'compileDebug' on root project 'Android'.
  • Peter Niederwieser
    Peter Niederwieser about 11 years
    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.
  • Michael
    Michael about 11 years
    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.
  • Peter Niederwieser
    Peter Niederwieser about 11 years
    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.
  • Michael
    Michael about 11 years
    Yeah, seems it works! Could you please add it to the answer and explain what it means?
  • slott
    slott over 10 years
    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.
  • Dhrupal
    Dhrupal over 10 years
    Hello Peter Niederwieser, it giving me below error. Could not find property 'compileJava' on com.android.build.gradle.AppExtension_Decorated@44b35022.
  • ento
    ento about 10 years
    The task name seems to have changed to compileDebugJava.
  • treesAreEverywhere
    treesAreEverywhere almost 10 years
    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
    treesAreEverywhere almost 10 years
    @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)
  • Peter Niederwieser
    Peter Niederwieser almost 10 years
    Why is it out of date?
  • Greg Ennis
    Greg Ennis almost 10 years
    Well, your answer still says "compileJava.dependsOn(...)" which doesnt work, as discussed in comments.
  • IgorGanapolsky
    IgorGanapolsky almost 8 years
    Where are you calling your custom task here?
  • Michael
    Michael almost 8 years
    generateSources is the custom task. And javaCompiler tasks becomes dependent on generateSources.
  • Martin Zeitler
    Martin Zeitler almost 8 years
    ./gradlew tasks --all in the project directory also shows the task's description.
  • IgorGanapolsky
    IgorGanapolsky almost 8 years
    What? I get an error: Could not find property 'preBuild' on root project
  • IgorGanapolsky
    IgorGanapolsky almost 8 years
    I get an error: Could not find property 'android' on root project
  • IgorGanapolsky
    IgorGanapolsky almost 8 years
    I get an error: Could not find property 'preBuild' on project ':app'
  • Michael
    Michael almost 8 years
    You have to apply the Android plugin before this code.
  • Henadzi Rabkin
    Henadzi Rabkin almost 8 years
    So, probably it doesn't exists now on newer versions of Gradle
  • IgorGanapolsky
    IgorGanapolsky almost 8 years
    Did it ever exist in Android Studio? Or were you generally speaking about Gradle...
  • Henadzi Rabkin
    Henadzi Rabkin almost 8 years
    It was used in one of my projects Igor
  • Merk
    Merk over 7 years
    @IgorGanapolsky just put prebuild.dependsOn('someTask') within the android { } block, works like a charm. No need to invoke projectsEvaluated.
  • Compaq LE2202x
    Compaq LE2202x almost 7 years
    @Michael how do you do that? I'm using Android Studio
  • Michael
    Michael almost 7 years
    You just have to put this code into your build.gradle file.
  • Compaq LE2202x
    Compaq LE2202x almost 7 years
    @Michael How do I do this for multiple tasks?
  • Michael
    Michael almost 7 years
    You can call variant.javaCompiler.dependsOn(taskName) for every task. Another approach is to have a chain of task and call variant.javaCompiler.dependsOn(taskName) for the root one.
  • ottago
    ottago about 6 years
    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.
  • Shubham AgaRwal
    Shubham AgaRwal over 5 years
    Any suggestion who can get build type related info in Gradle task 'generateSources'
  • Khongor Bayarsaikhan
    Khongor Bayarsaikhan over 4 years
    variant.javaCompiler is now obsolete, you should use variant.javaCompileProvider.get()
  • lasec0203
    lasec0203 about 4 years
    tsk...tsk..spent hours struggling with getting a task to run because I was putting related code ouside of the android {} block
  • Henadzi Rabkin
    Henadzi Rabkin about 4 years
    @lasec0203 thanks for pointing this out. I have made an appropriate edit,