Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gradle Android Plugin: Hook into post-compile task for all product flavors

I need to execute my own code (via javaexec), after my android project has been compiled by gradle but before it is packaged into an apk (and in fact, before the resources are moved to their final destination). So I used:

gradlew tasks --all

To get a list of available tasks. I am using product flavors, so almost all tasks have the name of a flavor somewhere in between like:

assembleFlavorA

or

installFlavorB

etc...

What I can do right now, is execute my own task before compiling starts by hooking into the preBuild task:

preBuild <<{
    //Do some stuff
}

The above gets called for every build variant which is exactly what I want. However when I try the same with the assemble task or the build task:

assemble <<{
    //Get's never executed
}

build <<{
    //Get's never executed
}

The above code is never executed, regardless of which product flavor I am building. Looking at the dependency list for releaseFlavorA:

myapp:assembleFlavorARelease - Assembles the Release build for flavor FlavorA [library:bundleRelease]
    myapp:checkFlavorAReleaseManifest
    myapp:compileFlavorAReleaseAidl
    myapp:compileFlavorAReleaseJava
    myapp:compileFlavorAReleaseNdk
    myapp:compileFlavorAReleaseRenderscript
    myapp:dexFlavorARelease
    myapp:generateFlavorAReleaseAssets
    myapp:generateFlavorAReleaseBuildConfig
    myapp:generateFlavorAReleaseResValues
    myapp:generateFlavorAReleaseResources
    myapp:generateFlavorAReleaseSources
    myapp:lintVitalFlavorARelease - Runs lint on just the fatal issues in the FlavorARelease build
    myapp:mergeFlavorAReleaseAssets
    myapp:mergeFlavorAReleaseResources
    myapp:packageFlavorARelease
    myapp:preFlavorADebugBuild
    myapp:preFlavorAReleaseBuild
    myapp:preAltdorfDebugBuild
    myapp:preAltdorfReleaseBuild
    myapp:preBerlinDebugBuild
    myapp:preBerlinReleaseBuild
    myapp:preBuild
    myapp:prepareFlavorAReleaseDependencies
    myapp:prepareComAndroidSupportAppcompatV71910Library - Prepare com.android.support:appcompat-v7:19.1.0
    myapp:prepareTrunkGradleLibraryUnspecifiedLibrary - Prepare trunk-gradle:library:unspecified
    myapp:processFlavorAReleaseJavaRes
    myapp:processFlavorAReleaseManifest
    myapp:processFlavorAReleaseResources
    myapp:validateReleaseSigning
    myapp:zipalignFlavorARelease

I only see preBuild but neither assemble nor build, which is odd, since it's shown when running

gradlew tasks 

But most methods in above list are flavor specific, and I don't want to have the same task 20 times, because I have 20 different flavors... So how can I execute my necessary tasks, once the compiling is done, but the APK hasn't been packaged yet for all flavors? Something like:

//I know there is no task called "postCompile" - so anything post compiling and pre-packaging would be fine
postCompile << {
    //Do something that needs to be done for all flavors
}

EDIT So I rechecked the command line output when building customerA for instance via:

gradlew assembleCustomerARelease

    C:\Users\user\workspace\android\trunk-gradle>gradlew assembleCustomerARelease
:library:compileLint
:library:copyReleaseLint UP-TO-DATE
:library:mergeReleaseProguardFiles UP-TO-DATE
:library:preBuild
:library:preReleaseBuild
:library:checkReleaseManifest
:library:preDebugBuild
:library:preDebugTestBuild
:library:prepareComAndroidSupportAppcompatV71910Library UP-TO-DATE
:library:prepareReleaseDependencies
:library:compileReleaseAidl UP-TO-DATE
:library:compileReleaseRenderscript UP-TO-DATE
:library:generateReleaseBuildConfig UP-TO-DATE
:library:generateReleaseAssets UP-TO-DATE
:library:mergeReleaseAssets UP-TO-DATE
:library:generateReleaseResValues UP-TO-DATE
:library:generateReleaseResources UP-TO-DATE
:library:mergeReleaseResources UP-TO-DATE
:library:processReleaseManifest UP-TO-DATE
:library:processReleaseResources UP-TO-DATE
:library:generateReleaseSources UP-TO-DATE
:library:compileReleaseJava UP-TO-DATE
:library:processReleaseJavaRes UP-TO-DATE
:library:packageReleaseJar UP-TO-DATE
:library:compileReleaseNdk UP-TO-DATE
:library:packageReleaseJniLibs UP-TO-DATE
:library:packageReleaseLocalJar UP-TO-DATE
:library:packageReleaseRenderscript UP-TO-DATE
:library:packageReleaseResources UP-TO-DATE
:library:bundleRelease UP-TO-DATE
:myapp:preBuild
Path to customer file: C:\Users\user\workspace\android\trunk-gradle\myapp\src\CustomerA\res\xml\customer.xml
Selected server: release
:myapp:preCustomerAReleaseBuild
:myapp:checkCustomerAReleaseManifest
:myapp:preCustomerADebugBuild
:myapp:preCustomerBDebugBuild
:myapp:preCustomerBReleaseBuild
:myapp:preCustomerCDebugBuild
:myapp:preCustomerCReleaseBuild
:myapp:prepareComAndroidSupportAppcompatV71910Library UP-TO-DATE
:myapp:prepareTrunkGradleLibraryUnspecifiedLibrary UP-TO-DATE
:myapp:prepareCustomerAReleaseDependencies
:myapp:compileCustomerAReleaseAidl UP-TO-DATE
:myapp:compileCustomerAReleaseRenderscript UP-TO-DATE
:myapp:generateCustomerAReleaseBuildConfig UP-TO-DATE
:myapp:generateCustomerAReleaseAssets UP-TO-DATE
:myapp:mergeCustomerAReleaseAssets UP-TO-DATE
:myapp:generateCustomerAReleaseResValues UP-TO-DATE
:myapp:generateCustomerAReleaseResources UP-TO-DATE
:myapp:mergeCustomerAReleaseResources UP-TO-DATE
:myapp:processCustomerAReleaseManifest UP-TO-DATE
:myapp:processCustomerAReleaseResources UP-TO-DATE
:myapp:generateCustomerAReleaseSources UP-TO-DATE
:myapp:compileCustomerAReleaseJava UP-TO-DATE
:myapp:lintVitalCustomerARelease
//Some logoutput from the dex-ing task not really relevant in this case
:myapp:dexCustomerARelease UP-TO-DATE
:myapp:processCustomerAReleaseJavaRes UP-TO-DATE
:myapp:validateReleaseSigning
:myapp:packageCustomerARelease UP-TO-DATE
:myapp:zipalignCustomerARelease UP-TO-DATE
:myapp:assembleCustomerARelease

BUILD SUCCESSFUL

Total time: 25.451 secs

So based on above build output, I'd assume that preBuild actually happens after the compile phase? As it's listed after compileReleaseJava and the other compile tasks. If this is the case, then "preBuild" would suffice for me requirements.

UPDATE 04.02.2015

The question remains open, but I have changed my code to no longer depend on it. Instead of trying to use a java class that would have to be compiled by my project first, I created another project for that class, which generates a jar file which in turn I think use - details can be found here:

https://stackoverflow.com/a/28303047/1041533

However - I think it might still be interesting to know the answer to this question.

like image 617
AgentKnopf Avatar asked Jan 30 '15 11:01

AgentKnopf


1 Answers

You can't extend the assemble and build tasks like that because they are replaced with the appropriate build variant related tasks right before Gradle's execution phase. For example: assemble becomes assembleRelease.

You can still hook into the build process when the builds graph is being put together, though. If you want to execute your own code right before the package task, you can use this snippet:

task doStuff << {
    // Do stuff
}

tasks.whenTaskAdded { theTask ->
    if (theTask.name.contains('package')) {
        theTask.dependsOn 'doStuff'
    }
}

This code will make no distinction between build variants; you can do that in the if condition, if necessary.

like image 103
kevinpelgrims Avatar answered Nov 15 '22 04:11

kevinpelgrims