I am struggling with writing a task which will unzip an apk. I have several Build Variants, and I want to dynamically create a task for each of them.
applicationVariants.all { variant -> variant.outputs.all { output ->
def assembleTaskName = 'assemble' + variant.getName().capitalize()
def outputDir = new File(output.packageApplication.outputDirectory.toString() + "\\tmp")
def apk = output.outputFile //there is some code which generates correct apk name based on Build Variant
tasks.getByName(assembleTaskName).finalizedBy(task("unzip" + apk.name, type: Zip) {
outputDir.mkdirs()
from zipTree(apk)
into outputDir
})
}}
While this code creates tmp folder where I need it, apk doesn't get extracted, and this code seems to run on every build variant I have, but I only need it to run on the one I build right now. How can I do that?
Related
I need to set up a custom task that I run after an APK is built when using Gradle for Android. Right now I actually have two tasks. One builds an XML file using the path to the APK as an input, and the other runs after the XML task (named packageConfig) and bundles the APK and the XML file into a ZIP.
Right now, I'm having trouble with my packageConfig task. It runs the python script for only the "fullRelease" product flavor, when I actually have multiple:
x86Debug
x86Release
armDebug
armRelease
fullDebug
fullRelease
My script is only executed once, and for the wrong APK. For example, I will invoke gradle like so:
$ gradlew :Applications:zApp:assemblex86debug packageConfig
I set up a print() call in my python script to output the APK path passed in, and it is:
build\outputs\apk\full\release\zApp.apk
The path I'm expecting (based on the product flavor I chose on the command line, as well as the APK I know that is there):
build\outputs\apk\x86\debug\zApp.apk
I'll paste my gradle task below. Can anyone help me understand what I'm doing wrong? What corrections can I make to my script to get it to run my script on the correct APK?
task packageConfig(type: Exec) {
def buildCommit = getBuildCommit()
def buildBranch = getVcsBranchName()
def buildDescription = buildBranch + '-' + buildCommit
def buildDate = getBuildDate()
workingDir buildscript.sourceFile.parent
android.applicationVariants.all { variant ->
variant.outputs.all { output ->
def apk = output.outputFile
def apkDir = apk.getParent();
def inputConfig = '' + project.projectDir + File.separator +
packageConfigXmlFile
def outputConfig = apkDir + File.separator + 'PackageConfig.xml'
commandLine 'python', 'setup-package-config.py', versions.version, inputConfig,
outputConfig, apk, buildDescription
}
}
}
I would like to change the APK output folder and this is what I used to do:
applicationVariants.all { variant ->
variant.outputs.all {
def filePath = "${rootProject.rootDir.absolutePath}/apks/${variant.name}"
println("My Path: " + filePath)
outputFileName = filePath
}
}
However, it didn't work in Gradle 4.1 (Android studio 3.0 preview). Instead of generating the folder as the path above, it generated the above path inside old debug folder like image below:
Does anyone have a solution for this? Thanks.
This is a workaround to keep the output path same after upgrade to gradle 4.x.
applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "../" + outputFileName
}
}
now apk is generated at platforms/android/build/outputs/apk/android-release.apk
From migration guide:
Using the Variant API to manipulate variant outputs is broken with the new plugin. It still works for simple tasks, such as changing the APK name during build time, as shown below:
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "${variant.name}-${variant.versionName}.apk"
}
}
However, more complicated tasks that involve accessing outputFile objects no longer work. That's because variant-specific tasks are no longer created during the configuration stage. This results in the plugin not knowing all of its outputs up front, but it also means faster configuration times.
I had a similar issue, because I needed the output apk in a known folder and not in a folder depending on the computer user name. So I have fixed like this:
applicationVariants.all { variant ->
variant.outputs.all {
def apk = output.outputFile;
def newName = apk.name.replace(".apk", "-v" + variant.versionName + "-RELEASE.apk");
newName = newName.replace("-" + variant.buildType.name, "");
outputFileName = "./" + newName
}
}
With this I get the apk in:
".../outputs/apk/flavorName/buildTypeName/xxx.apk"
Hope it helps you.
Prior to Android plugin version 3.0.0-alpha4, I have been using the following for publishing different variants of my APKs to a specific file path:
def publish = project.tasks.create("publishAll")
android.applicationVariants.all { variant ->
def task = project.tasks.create("publish${variant.name}Apk", Copy)
task.from(variant.outputs[0].outputFile)
task.into(buildDir)
task.dependsOn variant.assemble
publish.dependsOn task
}
I originally got it from this answer from Xavier Ducrohet: Copying APK file in Android Gradle project
As of the new updates to Android Studio Preview which uses version 3.0.0-alpha4, variant.outputFile is deprecated. What is the new suggested way to achieve something like this?
EDIT:
Looks like there is no way to currently access the variant output file as pointed out here: https://developer.android.com/studio/preview/features/new-android-plugin-migration.html#variant_api
Looks like we'll have to wait until they introduce those apis
If you don't use abi splits next snippet works
project.afterEvaluate {
android.applicationVariants.all { variant ->
// create file where to copy
def backupFolder = rootProject.file("backup")
def backupFile = new File(backupFolder, String.format("%s_v%s.%d.apk", variant.flavorName, variant.versionName, variant.versionCode))
variant.outputs.all { output ->
Task copyAndRenameAPKTask = project.task("copyAndRename${variant.name.capitalize()}APK", type: Copy) {
from output.outputFile.getParent()
into backupFolder
include output.outputFileName
rename(output.outputFileName, backupFile.getName())
}
// if copyAndRenameAPKTask needs to automatically execute assemble before
copyAndRenameAPKTask.dependsOn(variant.assemble)
copyAndRenameAPKTask.mustRunAfter(variant.assemble)
// if assemble needs to automatically execute copyAndRenameAPKTask after
variant.assemble.finalizedBy(copyAndRenameAPKTask)
}
}
}
I am trying to name my application's APK file based on the git branch, which is working by passing a parameter in with jenkins. However, I end up with two APKs, and this is undesirable because one of the Gradle tasks I have uploads the APK to a distributed list. The whole point of renaming this APK is so that people who receive it know exactly what branch they are seeing.
buildTypes {
...
feature {
signingConfig signingConfigs.debug
applicationVariants.all { variant ->
appendVersionNameVersionCode(variant, defaultConfig)
}
}
...
}
...
def appendVersionNameVersionCode(variant, defaultConfig) {
//check if staging variant
if(variant.name == android.buildTypes.feature.name){
def branch = hasProperty('branch') ? branch.replaceAll('origin/', '') : "UNKNOWN"
def file = variant.packageApplication.outputFile
def fileName = "myapp-FEATURE-" + branch + ".apk"
variant.packageApplication.outputFile = new File(file.parent, fileName)
}
}
Then the gradle command is invoked:
gradle assembleFeature --project-dir=/Path/To/myapp/ -Pbranch=origin/development
The two files that are generated from that are:
app-feature.apk
myapp-FEATURE-development.apk
File 1 is not desired, and I would ultimately want to rename that file, instead of generating a new file which is File 2.
Any thoughts?
Turns out, gradle always packages up 2 apks. One that is aligned, and one that isn't.
In order to rename the aligned apk file, I had to add this:
if (variant.zipAlign) {
newName = "myapp-FEATURE-" + branch + "-ALIGNED.apk"
variant.outputFile = new File(file.parentFile, newName);
}
I have gradle task that depends on assembleRelease
sendReleaseCandidate.dependsOn assembleRelease
And I want to get resulted apk file path. From my task I've wrote:
def apk = android.applicationVariants.release.outputFile
But it doesn't work. What i'm doing wrong?
Thanks!
ps: android plugin 0.11.1, for now I stick with uri('./build/outputs/apk/<app_name>-release.apk').path but it seems aweful.
You can loop through the variants to find the one you need:
def apk = null
android.applicationVariants.all { variant ->
if ( (variant.name).equals("release") ) {
variant.outputs.each { output ->
apk = output.outputFile
}
}
}
println "Found output file: " + apk