I have the following script in build.gradle of an app project. All the println lines work fine meaning the task is run. However no files are copied. I am new to Gradle. I am probably missing something very simple. Any tip will be greatly appreciated.
assembleRelease.doLast {
android.applicationVariants.all { variant ->
if (variant.buildType.name == 'release') {
def releaseBuildTask = tasks.create(name: 'copy', type: Copy) {
println("Step A")
from 'build/outputs/apk/'
println("Step B")
into 'build/outputs/debug/'
println("Finished")
}
releaseBuildTask.mustRunAfter variant.assemble
}
}
println "copying task finished"
}
Update (2015-01-02)
I have noticed that I can do other file tasks such as deleting, renaming without any problem, but not copying.
Related
As in gradle 4.4 it is not possible to change path of APK output file and we can't use absolute path for the apk's output now from the docs - Modifying variant outputs at build time may not work so I searched on SO and found a solution that we can copy apk to our desired location after it gets build but I don't have much idea on gradle scripting and i am not able to call copy task. Can anyone help me.
code from my gradle :
android {
................
android.applicationVariants.all { variant ->
variant.outputs.all {
if (variant.name.contains("Release")) {
outputFileName = "${variant.name}-${variant.versionName}.apk"
}
}
assembleRelease {
dependsOn copyDocs
}
}// end of android brace
task copyApk(type: Copy) {
from outputFileName
into file("${project.buildDir}/outputs/apk")
}
}
From this way i am getting error :
Could not get unknown property 'outputFileName' for task
Any idea how to copy apk file to another path? Thanks.
android.applicationVariants.all { variant ->
variant.outputs.all {
println variant.name
if (variant.name.contains("release")) {
outputFileName = new File("../", "${variant.name}-${variant.versionName}.apk")
println outputFileName
}
}
}
and remove
task copyApk
I am able to do it by running copy script in gradle file like this :
android.applicationVariants.all { variant ->
variant.outputs.all {
copy {
from file("${project.buildDir}/outputs/apk/" + variant.name + "/release/${outputFileName}")
into file("${project.buildDir}/outputs/apk/")
}
delete file("${project.buildDir}/outputs/apk/" + variant.name) // i don't want apk on this location so after successful copy i am deleting it
}
}
After updating Android Studio to version 2.2 and the Gradle-plugin to 2.2.0, I get following error:
"Could not get unknown property 'assembleRelease' for project ':app' of type org.gradle.api.Project."
When I change the plugin version back to 2.1.3 the code still works, but that's no long-term option for me.
My code:
apply plugin: 'com.android.application'
dependencies {
...
}
android {
...
}
...
assembleRelease.doLast {
file('build/outputs/apk/app-release.apk').renameTo("AppName-1.0.0-${project.ext.androidVersionCode}.apk")
}
Hint:
project.ext.androidVersionCode is a variable defined otherwhere and contains a build number. The code in assembleRelease.doLast shall just move/rename the generated apk file.
Thank you for advices!
tangens
tasks.whenTaskAdded { task ->
if (task.name == 'assembleRelease') {
task.finalizedBy 'yourRenameTasks'
}
}
You may rewrite your task a bit and try like this:
task renameBuildTask() << {
file('build/outputs/apk/app-release.apk').renameTo("AppName-1.0.0-${project.ext.androidVersionCode}.apk")
dependsOn 'assembleRelease'
}
Also you can check this question to get better understanding.
EDIT
As #tangens said in a comment:
It works when I replace the call gradle assemble by e.g. gradle renameBuildTask. Thank you! The answer contains an error. Correct would be: task renameBuildTask() << { ... }
maybe wrap code in afterEvaluate{} will be work:
afterEvaluate {
assembleRelease.doLast {
file('build/outputs/apk/app-release.apk').renameTo("AppName-1.0.0-${project.ext.androidVersionCode}.apk")
}
}
gradle-2.14.1 and android gradle plugin 2.2.0
details:
Could not get unknown property 'assembleDebug' (2.2-beta)
I had the same problem after upgrading Android Studio to 2.2 and Gradle to 2.2.
I have task copyApk that needs to be run at the end of building. For brevity, let me skip what was working before, and post only what is working right now:
tasks.create(name: 'copyApk', type: Copy) {
from 'build/outputs/apk/myapp-official-release.apk'
into '.../mobile'
rename('myapp-official-release.apk', 'myapp.apk')
}
tasks.whenTaskAdded { task ->
if (task.name == 'assembleRelease') {
task.dependsOn 'copyApk'
}
}
Gradle console shows copyApk was run near the end after packageOfficialRelease, assembleOfficialRelease, right before the last task assembleRelease. "Official" is a flavor of the app.
I got the workaround from this SO post. I essentially copied the answer here for your convenience. All credits go to the author of that post.
inside buildTypes {} method, I put this code : worked like a charm
task setEnvRelease << {
ant.propertyfile(
file: "src/main/assets/build.properties") {
entry(key: "EO_WS_DEPLOY_ADDR", value: "http://PRODUCTION IP")
}
}
task setEnvDebug << {
ant.propertyfile(
file: "src/main/assets/build.properties") {
entry(key: "EO_WS_DEPLOY_ADDR", value: "http://DEBUG IP TEST")
}
}
tasks.whenTaskAdded { task ->
if (task.name == 'assembleDebug') {
task.dependsOn 'setEnvDebug'
} else if (task.name == 'assembleRelease') {
task.dependsOn 'setEnvRelease'
}
}
you can do this:
task copyApk(dependsOn: "assembleRelease") << {
file('build/outputs/apk/app-release.apk').renameTo("AppName-1.0.0-${project.ext.androidVersionCode}.apk")
}
I wrote a small task, which updates an Android library from the web. This should only be done on request. I know, that there is a '-x' option, but this seems to apply only on gradle itself. The task gets executed whenever I try to build my project with Android Studio. Is there a way to exclude specific task from being executed?
My gradle task look like:
task downloadSDK {
print 'Downloading SDK...'
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
ant.get(
src: 'http://example.com/SDK.zip',
username:properties.getProperty('USERNAME', null),
password:properties.getProperty('PASSWORD', null),
dest:"${buildDir}/sdk.zip",
verbose:true)
println 'done'
}
task updateSDK(type: Copy) {
print 'Copying SDK...'
delete "src/main/java/"
def zipFile = file("${buildDir}/sdk.zip")
def outputDir = file("src/main/java")
from zipTree(zipFile)
into outputDir
println 'done'
}
updateSDK.dependsOn downloadSDK
I thought that I just have to add << to my updateSDK, but it doesn't seem to work with the Copy task.
Reading the gradle spec more deeply, I found out, that Copy is actually not a task but rather a function. So, my gradle task has to look like:
task updateSDK << {
print 'Copying SDK...'
delete "src/main/java/"
def zipFile = file("${buildDir}/sdk.zip")
def outputDir = file("src/main/java")
copy {
from zipTree(zipFile)
into outputDir
}
println 'done'
}
The difference is that I call the copy function inside a task so that doLast will work correctly.
As of com.android.tools.build:gradle:1.3.0 you can run into Task with name 'testDebug' not found in project ':module'.
As in the earlier stage of the build environment it was not possible to test library modules properly using Robolectric & Java this workaround was created:
afterEvaluate { project ->
android.libraryVariants.each { variant ->
println variant.name
println tasks
tasks.getByName("test${variant.name.capitalize()}") {
dependsOn "assemble${variant.name.capitalize()}"
}
}
}
With version 1.3.0 this is broken.
They have changed the name from testDebug to testDebugUnitTest hence the code above needs to be changed to:
afterEvaluate { project ->
android.libraryVariants.each { variant ->
println variant.name
println tasks
tasks.getByName("test${variant.name.capitalize()}UnitTest") {
dependsOn "assemble${variant.name.capitalize()}"
}
}
}
I have searched a lot, but haven't seen an answer for this. I have source that's in different flavors. Something like:
App/src/flavorA/MyFlavor.java
App/src/flavorB/MyFlavor.java
App/src/flavorC/MyFlavor.java
And it works great, until I need to run my AOP step. I found it couldn't complete because it was unable to find this class, which is referenced from source in App/src/main/.
This doesn't find the MyFlavor class:
android.applicationVariants.all { variant ->
variant.javaCompile.doLast {
def androidSdk = android.adbExe.parent + "/../platforms/" + project.ext.android_version + "/android.jar"
def iajcClasspath = configurations.compile.asPath + ";" + androidSdk
// This add's project jars as well as support jars.
project.ext.tree = fileTree(dir: "${project.buildDir}/intermediates/exploded-aar", include: '**/*.jar')
project.ext.tree.each { jarFile ->
iajcClasspath += ":" + jarFile
}
ant.taskdef(resource: "org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties",
classpath: configurations.ajc.asPath)
ant.iajc(
source: "1.6",
target: "1.6",
destDir: "${project.buildDir}/intermediates/classes/${variant.dirName}",
fork: "true",
maxmem: "512m",
aspectPath: configurations.aspects.asPath,
inpath: configurations.ajInpath.asPath,
sourceRootCopyFilter: "**/.svn/*,**/*.java",
classpath: iajcClasspath
) {
sourceroots {
android.sourceSets.main.java.srcDirs.each {
pathelement(location: it.absolutePath)
}
pathelement(location: "${project.buildDir}/generated/source/r/${variant.dirName}")
pathelement(location: "${project.buildDir}/generated/source/buildConfig/${variant.dirName}")
}
}
}
}
I can get it working if I add in something like:
pathelement(location: "$`enter code here`{project.buildDir}/../src/flavorA/java")
But that's if I only want to build flavorA. Is there a better way of setting things up so that when the IAJC task runs, it can find the source that it needs for the particular variant that it's building? If I assembleFlavorARelease, my variant name is going to be something like flavorARelease and I can get the build type of "release" by doing variant.buildType.name but that's not going to help me. I need to point it to the source for the flavor I'm building.
I took the variant.name and subtracted the build type name off of it to be left with the "flavorA" part:
pathelement(location: "${project.buildDir}/../src/${variant.name.substring(0, variant.name.length() - variant.buildType.name.length())}/java")
Still seems wonky. What if I want to assembleRelease and build all flavors? There's got to be a better way of approaching this which I'm not seeing.
You can iterate over the available flavors for your particular variant using:
def currentFlavor;
variant.productFlavors.each { flavor ->
flavorToChoose = flavor
}
From here you can grab onto the flavor you want from the list and then add a path element similar to the "main" source set like:
android.sourceSets."${flavorToChoose}".java.srcDirs.each {
pathelement(location: it.absolutePath)
}
Make sure to stick this block in your sourceroots section.