I want to create a gradle task in Android Studio that will do something with the output of the build task of another project
task foo {
dependsOn ':someApp:build'
...
copy results of :someApp:build to another location
...
}
I can't just hardcode a path as I won't know if someApp was built as debug or release and the output paths will vary based on the type of build.
dynamic copy task without using hardcoded path.
applicationVariants.all {
variant->
variant.outputs.each { output ->
println("..a")
task "copy${variant.buildType.name}"(type:Copy){
println("${variant.buildType.name}")
dependsOn app:assembleDebug
copy {
from "$buildDir\\outputs\\apk\\${variant.buildType.name}\\app-${variant.buildType.name}.apk"
into "C:\\Users\\rkumar8\\AndroidStudioProjects\\MyApplication\\app\\build\\outputs\\apk\\"
}
// you can add multiple copy if required, i am doing it here release build was named app-release-unsigned.apk
copy {
from "$buildDir\\outputs\\apk\\${variant.buildType.name}\\app-${variant.buildType.name}-unsigned.apk"
into "C:\\Users\\rkumar8\\AndroidStudioProjects\\MyApplication\\app\\build\\outputs\\apk\\"
}
}
}
}
I added a task in android block of build.gradle of app module.
applicationVariants.all {
variant->
variant.outputs.each { output ->
println("..a")
task "copy${variant.buildType.name}"(type:Copy){
println("${variant.buildType.name}")
dependsOn app:assembleDebug
copy {
from "$buildDir\\outputs\\apk\\${variant.buildType.name}\\app-${variant.buildType.name}.apk"
into "C:\\Users\\rkumar8\\AndroidStudioProjects\\MyApplication\\app\\build\\outputs\\apk\\"
}
// you can add multiple copy if required, i am doing it here release build was named app-release-unsigned.apk
copy {
from "$buildDir\\outputs\\apk\\${variant.buildType.name}\\app-${variant.buildType.name}-unsigned.apk"
into "C:\\Users\\rkumar8\\AndroidStudioProjects\\MyApplication\\app\\build\\outputs\\apk\\"
}
}
}
}
There is another post for adding our task in android build path.
https://discuss.gradle.org/t/how-to-insert-my-task-into-a-pre-defined-build-android-build/29685/3
Related
I have a generic Artifatory repo that contains some zip files that I need to download and extract in an Android Studio project. I am new to Gradle but found that using an Ivy repository object maybe the best way to do this instead of just downloading the files using a Gradle task which calls curl.
I have managed to get a single zip file downloaded and extracted but soon as I try to add another dependency it overwrites my configuration. See the dependencies block in the code below.
Why is it not adding another dependency and is there a better way to do this?
app:build.gradle:
repositories {
ivy {
url property("artifactoryUrl")
credentials {
username property("artifactoryUser")
password property("artifactoryPassword")
}
authentication {
basic(BasicAuthentication)
}
patternLayout {
artifact '/[organisation]/[module]/third-party/[revision](.[ext])'
}
metadataSources {
artifact()
}
}
}
configurations {
thirdPartyDependencies
}
dependencies {
thirdPartyDependencies "artifactory:test-generic:FreeImage#zip"
thirdPartyDependencies "artifactory:test-generic:GLEW#zip" // thirdPartyDependencies has been overwritten
}
task CopyThirdPartyDependencies(type: Copy) {
def thirdPartyDirectory = getProject().getRootDir().toString() + "/third-party/"
println(configurations.thirdPartyDependencies.resolvedConfiguration.resolvedArtifacts)
configurations.thirdPartyDependencies.resolvedConfiguration.resolvedArtifacts.each { artifact ->
copy {
from zipTree(artifact.getFile())
into thirdPartyDirectory
}
}
}
preBuild.dependsOn(CopyThirdPartyDependencies)
I have simple assets processing gradle task prepare_assets in Android Studio 3.1.3. It is linked to preBuild task:
preBuild.dependsOn(prepare_assets)
Now I have several flavors for different resolution versions and I want to let prepare_assets know what assets to process. Maybe I don't get the idea of Gradle, but I can't understand how to achieve this: I tried to set variable in config phase
applicationVariants.all { variant ->
buildType = variant.buildType.name // sets the current build type
}
but when I read variable in my task it always the same.
In flavours section declaration:
all { flavor ->
task("${flavor.name.capitalize()}_prepare_assets") {
println "*** conf TEST for ${flavor.name.capitalize()}***"
doLast {
println "*** action TEST ${flavor.name.capitalize()}***"
if (flavor.name.equals("fullhd"))
{
//WARNING: to call copy, javaexec closures here use project.copy and project.javaexec!
}
else
{
...
}
}
}
}
In the bottom of file adding dependenses for runtime created android tasks for all flavors:
tasks.whenTaskAdded { theTask ->
if (theTask.class.name.contains("AppPreBuildTask_Decorated"))
{
for (Iterator iterator = android.productFlavors.iterator(); iterator.hasNext();) {
String flv_name = iterator.next().name.capitalize();
if (theTask.name.contains(flv_name+"Debug") || theTask.name.contains(flv_name+"Release"))
theTask.dependsOn "${flv_name}_prepare_assets";
}
}
}
I'm trying to generate identical assets for each of the subprojects in a project. Since exactly the same thing has to happen for each subproject, I'm trying to avoid having to add the generation code to each subproject.
What I've got so far is:
// in my outer build.gradle
allprojects { proj ->
gradle.projectsEvaluated {
def configTemplate = project.file('src/main/templates/configuration.json')
def android = proj.getProperties()['android']
if (configTemplate.exists() && android != null) {
task generateConfigFiles(type: ConfigureTask) {
template configTemplate
environments proj.rootProject.file('scripts/environments.json')
environmentName host
destination new File(project.buildDir, 'templates/configuration.json')
}
android.applicationVariants.all { variant ->
variant.mergeAssets.dependsOn generateConfigFiles
}
}
}
}
// each application build.gradle
android {
sourceSets {
main {
assets.srcDir 'build/templates'
}
}
}
This seems to work exactly as expected when I run gradle from the command line ./gradlew mergeQaDebugAssets runs the generateConfigFiles task before running mergeQaDebugAssets
If I attempt to run this from Android Studio using the gradle window, it never runs generateConfigFiles
I've also gotten it to work by just including the projectsEvaluated step in each of the project build.gradle files, but, as noted, I'm trying to avoid the code duplication and maintenance headaches that brings.
I'm currently struggling with a build process in gradle. My goal is to not have a specific java class in the final .apk for a specific flavor.
The logic goes like this:
1.) before compiling my project delete MyClass.java and copy it to a temp folder
2.) after assembling the apk copy back MyClass.java to my original folder
3.) delete the temp folder
This happens only if I build a specific flavor, so it doesn't happen for all build variants. My code works perfectly when I build only one flavor and one build variant e.g. assembleFlavorRelease, but if I wan't to make my code work for multiple build types; if I run assembleFlavor it should build flavorDebug the same way it does flavorRelease.
However my logic goes trough only the first time and after that it stops, so flavorDebug is build with MyClass and it shouldn't be, while flavorRelease doesn't include MyClass in the .apk because my code runs the first time.
Here is what the code looks like:
task copyResource << {
copy {
from 'src/main/java/MyClass.java'
into 'src/temp'
}
}
task deleteResource << {
delete {
'src/main/java/MyClass.java'
}
}
task deleteTemp << {
delete {
'src/temp'
}
}
task copyBackToSource << {
copy {
from 'src/temp/MyClass.java'
into 'src/main/java'
}
deleteTemp.execute()
}
android.applicationVariants.all { variant ->
if (variant.name.contains('flavor')) {
deleteResource.dependsOn copyResource
variant.javaCompile.dependsOn deleteResource
variant.assemble.doLast {
copyBackToSource.execute()
}
}
}
I think that the directories which I use in my code are somehow locked when trying to execute the whole process the second time?
I feel that you are approaching the problem in the wrong way. Instead of thinking
Put the java file in src/main/java and remove it from flavorX
You should instead be approaching it as
Add an extra source directory to the source sets for flavorY and flavorZ
Once you approach the problem like this it becomes much easier
If you only want the file in one flavor, you can put the file in the flavor specific source folder using the built in conventions (ie src/flavorX/java)
If you want the file in more than one flavor you could put MyClass.java in src/common/java and do something like
android {
productFlavors {
flavor1 {
}
flavor2 {
}
flavor3 {
}
}
}
sourceSets {
flavor1.java = ['src/flavor1/java','src/common/java']
flavor2.java = ['src/flavor2/java','src/common/java']
}
Ok so I got the right solution from here: https://discuss.gradle.org/t/android-gradle-assemble-tasks/10711
If you want to avoid compiling a specific class then use this:
variant.javaCompile.exclude '**/SourceFileToExclude.java'
First off, this is my first foray into Gradle/Groovy (using Gradle 1.10). I'm setting up a multi-project environment where I'm creating a jar artifact in one project and then want to define an Exec task, in another project, which depends on the created jar. I'm setting it up something like this:
// This is from the jar building project
jar {
...
}
configurations {
loaderJar
}
dependencies {
loaderJar files(jar.archivePath)
...
}
// From the project which consumes the built jar
configurations {
loaderJar
}
dependencies {
loaderJar project(path: ":gfxd-demo-loader", configuration: "loaderJar")
}
// This is my test task
task foo << {
configurations.loaderJar.each { println it }
println configurations.loaderJar.collect { it }[0]
// The following line breaks!!!
println configurations.loaderJar[0]
}
When executing the foo task it fails with:
> Could not find method getAt() for arguments [0] on configuration ':loaderJar'.
In my foo task I'm just testing to see how to access the jar. So the question is, why does the very last println fail? if a Configuration object is a Collection/Iterable then surely I should be able to index into it?
Configuration is-a java.util.Iterable, but not a java.util.Collection. As can be seen in the Groovy GDK docs, the getAt method (which corresponds to the [] operator) is defined on Collection, but not on Iterable. Hence, you can't index into a Configuration.