How to make conditional build task on android build gradle - android

In android, we would like to make one app build with different application id depends on the pre-installed app package.
So it contains flavor in the build gradle with different applicationId set.
But we don't want all these flavors been build, we just want to only build the one based on pre-installed app package name to save sometime on build server.
If used
task prepareA(dependsOn:['assembleADebug']){}
task prepareB(dependsOn:['assembleBDebug']){}
task prepareTest(dependsOn:['prepareA', 'prepareB']) {}
Then when called prepareTest, both prepareA and prepareB would be executed with both assembleADebug and assembleBDebug executed.
I only want to build either prepareA or prepareB be executed based on one condition check (if ...).

The answer I found after some hours invesigation, it is that we can use afterEvaluate method, which would execute before dependsOn is running.
Remove the predefined dependsOn the the prepareA and prepareB.
Then
afterEvaluate {
if (isPackageInstalled(packageName)) {
tasks.findByName("prepareTest").dependsOn("prepareA")
} else {
tasks.findByName("prepareTest").dependsOn("prepareB")
}
}

Related

Is there any way to skip the assemble task and its dependencies in Android?

I am attempting to build a cache of APKs locally. The idea is that when you run any assemble type task, it will check locally for a previously built APK and move it into the build output folder.
I have made my own custom task that does this APK cache check. The signature is below:
tasks.register('apkCacheCheck') {
// checks for some criteria here
}
I have also made the assembleDebug task dependent on it:
tasks.whenTaskAdded{ task ->
if (task.name == "assembleDebug") {
task.dependsOn "apkCacheCheck"
task.enabled = foo // some output of apkCacheCheck
}
}
Problem:
When running assembleDebug to build an Android app, it will go up the graph and execute all its dependent tasks. However, I wanted to write a check that prevents the app from building anything until the check is finished. This way, we can save time by installing the cached APK rather than re-building it from scratch.
Questions:
Is there a way to stop all of the build tasks if said condition is met?
Is this a valid use case of Gradle or should I be looking towards running this as a Bash script?

Is there a way to make gradle task lintRelease do nothing when executed for a particular module?

Currently lintRelease, task depends on the compilation task, and for some modules (which I dont care about since its only used for testing purposes), I want lintRelease to do nothing, just print Not supported is that possible with gradle KTS?
Basically this question is about gradle task replacement, I want to replace the lintRelease gradle task with a task that does nothing.
If you are thinking
You can skip lint checking for debug/release builds
The lintRelease task is manually triggered at the moment by a shell script, so thats not an option, I need this task to not do anything for this particular module lets call it module X
Try this at the top of the Gradle file
tasks.whenTaskAdded { task ->
if (task.name.equals("lint")) {
task.enabled = false
}
}
Even this can also help
android {
lintOptions {
tasks.lint.enabled = false
}
}

How to add conditional afterEvaluate on buildType in Gradle

I have this code at the end of my build.gradle file:
project.afterEvaluate {
// If you add/change build types, you have to add to/change
// these task names.
mergeDebugAssets.dependsOn project.tasks.getByName('downloadLicenses')
mergeReleaseAssets.dependsOn project.tasks.getByName('downloadLicenses')
}
See: Copy generated third party licenses to assets for the full code
This used to work fine (regardless of which buildType was set) but if updating my dependencies to the latest version this triggers an exception (when building with buildType='debug'):
Could not get unknown property 'mergeReleaseAssets' for project ':application'
My thought was that maybe split this block in two and put them under the buildTypes configuration. This doesn't work though, as it tries to evaluate the code anyway and crashes.
Any ideas?
Update 1: Root cause?
https://code.google.com/p/android/issues/detail?id=219732
Update 2: A horrible workaround:
try {
mergeDebugAssets.dependsOn project.tasks.getByName('downloadLicenses')
} catch (Exception e) {
// Expected when building variant Release
}
try {
mergeReleaseAssets.dependsOn project.tasks.getByName('downloadLicenses')
} catch (Exception e) {
// Expected when building variant Debug
}
The reason that you get an error referencing a release task in afterEvaluate is probably because Android Studio's Instant Run feature uses a special Android Gradle plugin feature to only build the debug application variant. This means that only the debug tasks are created, hence why the release tasks can't be found when you reference them.
There are several ways to deal with this:
Search for the dependent task by name using a string. If the Android build system changes the task name in the future, your additional build rules won't run, but you might not even notice.
To determine if release tasks exist, check for the existence of a task whose name is unlikely to change in the future. Maybe assembleRelease fits this bill.
To determine if release tasks exist, check if the release application variant is built with something like:
project.afterEvaluate {
if (!android.applicationVariants.matching { it.buildType.name == 'release' }.isEmpty()) {
mergeReleaseAssets.dependsOn project.tasks.getByName('downloadLicenses')
}
}
The last option looks kind of gross, but hopefully it will fail-fast if the Android build system task names change in the future.
The reason you get exception in case of debug buildType is because mergeReleaseAssets task is not created. You can do the following instead:
project.tasks.findByName('mergeReleaseAssets')?.dependsOn project.tasks.getByName('downloadLicenses')
or even omit project:
tasks.findByName('mergeReleaseAssets')?.dependsOn tasks.getByName('downloadLicenses')
This uses safe navigation operator on nullable return type, so it's clearer than try/catch workaround.

Want to run a custom gradle task only when running Unit test

How to set up gradle to run a particular custom copy task, only when running unit tests?
EDIT
I want to run these tasks when i press build, i. e only in the flavor of the build with unit test execution included.
I've finally found the solution, with the help of this documentation which presents all the tasks that run during build, test, release etc. in a very concise manner. So by making tasks clean, preBuild depend on my copyTask I can ensure that the copy task is run every time the project is cleaned or built.
But since I don't want to run this during building or cleaning process but want to run it when I only run tests, I identified a task that compiles release unit test sources called the compileReleaseUnitTestSources but just mentioning it in build.gradle as
compileReleaseUnitTestSources.dependsOn(myCopyTask)
doesn't actually work, because gradle will give an error saying it cannot find the task compileReleaseUnitTestSources as for some reason that task is not available yet. Instead by enclosing it in a afterEvaluate block we can ensure that this block is executed after all tasks are evaluated, that way we have access to that task now, So finally I added this to my build.gradle
afterEvaluate {
compileReleaseUnitTestSources.dependsOn(copyResDirectoryToClasses)
}
All the answers here mention to use the dependsOn keyword to attach my task to another task that is run during general build/test execution, but none of them mentioned how to go around the problem where gradle is not able to find the tasks even though you know for sure that these tasks were available and run during build/test execution.
you have to set up a "customCopyTask" and make the "test-task" which does the unittests depend on the "customCopyTask" like this
task customCopyTask(type: Copy) {
from sourceSets.test.resources
into sourceSets.test.output.classesDir
}
test.dependsOn customCopyTask
You can make some task finalizing another, in that case this task will run only if another one was called, right after it. This could be done as:
task runUnitTest << {
println 'running tests'
}
task copyTestResults << {
println 'copying results'
}
//make copyTestResults finalize runUnitTest
runUnitTest.finalizedBy copyTestResults
You can read about it in the official user guide.
Additionally, if your unit test could be up-to-date and you don't want to run you copy task in that case, you can check the test task status and skip copy-task, as:
task copyTestResults {
doFirst {
//chtck anothe task status and skip this one if it didn't actually work
if (!tasks.getByName("runUnitTest").getState().didWork) {
throw new StopExecutionException();
}
}
doLast{
println 'copying results'
}
}
Or, if you just need to run copy-task before unit tests, make the test task depending on copy-task by setting it's dependsOn property, read about it with a number og examples here

gradle custom task order on Android

I have 2 gradle tasks that i want to run after assembleRelease task.
task copyRequiredFilesToVersionControl(type:Copy) {
...
}
task ('versionControl') << {
...
}
If I configure order for these tasks as below tasks get never called...
copyRequiredFilesToVersionControl.dependsOn(assembleRelease)
versionControl.dependsOn(copyRequiredFilesToVersionControl)
If i change order like;
assembleRelease.dependsOn(copyRequiredFilesToVersionControl)
versionControl.dependsOn(copyRequiredFilesToVersionControl)
Tasks are run at the beginning of document. So there is no file to copy and add to version control.
What is the best approach?
I have found method that called doLast. So i fixed my problem with it.
assembleRelease {
doLast {
tasks.versionControl.execute()
}
}
The best approach that I've found to date, has been to use the Ordering Tasks feature in Gradle : see http://www.gradle.org/docs/current/userguide/more_about_tasks.html for more documentation, currently section 15.5.
Basically, you have two rules available : MUST run after and SHOULD run after. I like the rule quite a bit, I use this to create zip archives of projects automatically. NOTE : you must still make use of the "dependsOn" to get proper execution if tasks that you need to have run in a particular order.

Categories

Resources