I need to copy some files to the Android App folder (data/data/...) after installing the app via Gradle. This has to be done at every debug build before the app gets started and thus I assumed I could find a gradle task that could be executed after the installation (but before the run command).
It works somewhat fine for other tasks when doing something like
tasks.whenTaskAdded { task ->
if (task.name == 'build') {
task.dependsOn taskXYZ
}
}
They then get executed before my build task is executed.
However, since I need that to happen after the install process (and before the running of the app) I was hoping for something like this:
tasks.whenTaskAdded { task ->
if (task.name.startsWith('install')){
println ">>>>>>>>> " + task.name
task.finalizedBy taskXYZ
}
But sadly, this does not work.
In the build output I can see that this executed pretty much at the start.
Executing tasks: [:app:assemblePlayStoreStagingDebug] in project /Users/...
> Configure project :app
###########################
TASK XYZ WAS EXECUTED HERE!
###########################
---> installPlayStoreStagingDebug
> Task :app:preBuild UP-TO-DATE
> Task :app:prePlayStoreStagingDebugBuild
> Task :app:compilePlayStoreStagingDebugAidl UP-TO-DATE
...
> Task :app:stripPlayStoreStagingDebugDebugSymbols UP-TO-DATE
> Task :app:packagePlayStoreStagingDebug
> Task :app:assemblePlayStoreStagingDebug
BUILD SUCCESSFUL in 6s
33 actionable tasks: 6 executed, 27 up-to-date
It looks like the task did not get executed at the expected time. What I need is something like this:
Task Build
Task Install
Task XYZ
Task run App
But how can I achieve this?
Solutions like this one
Android run Gradle task after app install
Don't seem to work for the install task.
----- EDIT -----
I tried it the other way around and - instead of using gradle tasks - I tried to change the run configuration of AS by adding an "external tool" call in the "before launch" settings.
https://developer.android.com/studio/run/rundebugconfig#definingbefore
However, when selecting for instance a shell script there, it won't get executed (for instance I was creating a file or directory in that script so I could see whether it was executed at all). It doesn't seem to be that error=13 permission problem. So if gradle tasks are not a solution, perhaps anyone knows a solution with this option!
In gradle you can use the mustRunAfter task, this does not create dependencies between the tasks but forces one task to be after a list of other tasks in the build sequence.
An example:
task taskY {
mustRunAfter "taskX"
}
https://gradle.github.io/kotlin-dsl-docs/api/org.gradle.api/-task/must-run-after.html
Related
Running one task in gradle (Android) - runs all tasks (clean, etc.) - how to make it run only one single task?
task testTask() {
dependsOn copyAssets, Debug1
}
Start this
PS Q:\AndroidProject\mark\android> ./gradlew copyAssets
Configure project :gg:android
:android: Q:\AndroidProject\mark\gg\android\build.gradle
Configure project :gg:awtold
gg:awt:android: Q:\AndroidProject\mark\gg\awtold\build.gradle
Configure project :gg:common
gg:common: Q:\AndroidProject\mark\gg\common\build.gradle
Configure project :
sdfasdf (this print in another task )
call in CAF ( and this )
call removed (and this )
Task :testTask NO-SOURCE
Assume that I have set of tasks executed from the cmd line and it works:
gradle processReleaseManifest compileReleaseSources run assembleRelease
Here run is the task which I Defined.
So My requirement is that I need to create a task which executes the above mentioned 4 tasks,
like say new task abc, runs the above mentioned tasks in the same order,
I know I cannot use dependsOn in this case because,processReleaseManifest compileReleaseSource when used in the build gradle it shows,
Could not get unknown property 'assembleRelease' for project ':app' of type org.gradle.api.Project.
So what is the solution?
You can, as #lu.koerfer's answer indicates use strings in the dependsOn list to refer to tasks that are defined further down in the build file.
In other words, this works:
task foo {}
task bar(dependsOn: [foo]) {}
and this also works:
task bar(dependsOn: ['foo']) {}
task foo {}
Now as for getting the tasks to run in the order you want things are not quite as straight forward. The dependsOn property only tells the task which tasks need to run before the task itself runs. It does not tell gradle to run the tasks in the order defined in the dependsOn clause.
An example:
task one {}
task two {}
task three {}
task run(dependsOn: [one, two, three]) {}
results in the following output when run:
~> gradle run
:one UP-TO-DATE
:three UP-TO-DATE
:two UP-TO-DATE
:run UP-TO-DATE
BUILD SUCCESSFUL
...note the fact that we are not running in the order one, two, three, run.
In other words, the command line invocation forces the tasks to run in the order defined whereas the dependsOn is a set and has no ordering.
There are a few ways you can get the tasks to run in the order you want. One is to define dependencies on the tasks (this is probably the common path):
task one {}
task two(dependsOn: ['one']) {}
task three(dependsOn: ['two']) {}
task run(dependsOn: [one, two, three]) {}
which results in:
~> gradle run
:one UP-TO-DATE
:two UP-TO-DATE
:three UP-TO-DATE
:run UP-TO-DATE
BUILD SUCCESSFUL
another is to use the task ordering constructs added in later versions of gradle.
Also, if you need to add a task dependency to a task which was defined somewhere earlier in the file, you can do so via:
task foo {}
someTaskDefinedFurtherUp.dependsOn 'foo'
which adds the task foo to the dependencies of someTaskDefinedFurtherUp.
You need to pass the task names as strings to the dependsOn method, because at the time you call it, the task objects haven't been created yet. However, if you pass strings, the task names will be evaluated later:
task abc {
dependsOn 'processReleaseManifest', 'compileReleaseSources', 'run', 'assembleRelease'
}
As it may be possible but very complicated to specify the task dependencies and ordering via dependsOn and mustRunAfter / shouldRunAfter, I'll propose another possible solution:
You can invoke Gradle from Gradle and specify the tasks in same way you would via command line:
task abc(type: GradleBuild) {
tasks = ['processReleaseManifest', 'compileReleaseSources', 'run', 'assembleRelease']
}
This will call Gradle again from the current build and execute the tasks in the specified order.
I can refer to connectedCheck task (which came from android plugin) from my build script:
connectedCheck.finalizedBy AndroidShowTestResults
But trying to use connectedDebugAndroidTest (which came from android plugin too)
connectedDebugAndroidTest.finalizedBy AndroidShowTestResults
gives me
Error:(48, 0) Could not find property 'connectedDebugAndroidTest' on project ':app'.
And if I try
task connectedDebugAndroidTest << {print '123'}
it curses me with
Error:Cannot add task ':app:connectedDebugAndroidTest' as a task with that name already exists.
I don't undestand why I cannot refer to connectedDebugAndroidTest?
Available gradle tasks are shown below:
The android plugin defers the addition of several tasks especially those that have buildType or flavor names in them till a very late stage of the configuration phase. Which in turn means if you try to refer to these yet-to-be-added-tasks by name, you're likely to see a "does not exist" type error messages. If you want to add dependencies around deferred-created tasks, you should wait until configuration is complete:
gradle.projectsEvaluated {
connectedDebugAndroidTest.finalizedBy AndroidShowTestResults
}
Alternatively, you can add a listener to task-graph events, so you can do stuff as soon as a certain task is added to task-graph:
tasks.whenTaskAdded { task ->
if (task.name == 'connectedDebugAndroidTest') {
task.finalizedBy AndroidShowTestResults
}
}
Try
task connectedTest(dependsOn: ["connectedDebugAndroidTest"]){
}
connectedTest.finalizedBy "AndroidShowTestResults"
I think you should try to open test and rebuild.
I wanted to remove the project makefile and write some nice gradle tasks.
I need to execute the following tasks, in this order:
Clean
Increment version
Build
Upload
#1, #3 and #4 are tasks from android and plugin (bintray) while #2 is a custom task. Here is what I have so far:
task releaseMajor {
doLast {
clean.execute()
build.execute()
incrementVersion.execute()
bintrayUpload.execute()
}
}
The run order was not so great as I think clean was run after build. And binrayUpload was running without flavor (release). I've also tried to use dependsOn without success (order not working).
I couldn't find in Gradle doc how to do this properly. When execute in the right order, from CLI, everything works perfectly.
Use mustRunAfter, or finalizedBy for finer order control:
task releaseMajor (dependsOn: ['clean', 'build', 'incrementVersion', 'bintrayUpload'])
build.mustRunAfter clean
incrementVersion.mustRunAfter build
bintrayUpload.mustRunAfter incrementVersion
Tried this
task clean {
println 'clean task executing'
}
task incrementVersion (dependsOn:"clean"){
println 'incrementVersion task executing'
}
task building (dependsOn:"incrementVersion"){
println 'build task executing'
}
task bintrayUpload (dependsOn:"building") {
println 'bintrayUpload task executing'
}
The output was
clean task executing
incrementVersion task executing
build task executing
bintrayUpload task executing
and executed ./gradlew bintryUpload
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