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.
Related
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?
I need to save each APK with a special name whenever I build one.
This is the desired name format: "buildType appName_version_Date_Time.apk"
Example: "debug myAppName_v1.0_20161009_0854.apk"
Example: "release myAppName_v1.0_20161009_0854.apk"
For this purpose I added this gradle script:
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
debug {
}
applicationVariants.all { variant ->
variant.outputs.each { output ->
def formattedDate = new Date().format('yyyyMMdd_HHmm')
println(output.outputFile)
def newName = variant.name + " myAppName_v" + defaultConfig.versionName + "_" + formattedDate + ".apk"
output.outputFile = new File(output.outputFile.parent, newName)
}
}
}
This script works, but android studio couldn't find the renamed APK. I also tried clean/rebuild project but it ocures again.
Android stuio error:
The APK file path\to\project\app\build\outputs\apk\debug myAppName_v1.0_[20161009_0854].apk does not exist on disk.
Error while Installing APK
When I check "build\outputs\apk" directory i see that an APK has been built and its name is "myAppName_v1.0_[20161009_0856].apk".
What's wrong here??
Instead of including the current time (with minutes, no less) in the APK filename, consider the following approaches:
Take the timestamp of the latest version control commit (that stays stable)
Instead of changing the apk filename, copy it from it's non-timestamped name - that Android Studio will easily find - to a timestamped apk.
Here's an example to try (haven't run it but should give the general idea). Choose either Files.copy or the copy task, not both.
applicationVariants.all { variant ->
variant.outputs.each { output ->
def copyApkTask = tasks.create(name: "copy" + variant.name + "Apk") {
def newName = ... // can include the timestamp with minutes
println(newName)
// Using java.nio.Files.copy
def targetPath = new File(output.outputFile.parent, newName).toPath()
Files.copy(output.outputFile.toPath(), targetPath)
// Using gradle's Copy logic (clunky for single-file copy and rename)
copy {
from output.outputFile
into output.outputFile.parent
rename { String fileName ->
newName
}
}
}
copyApkTask.mustRunAfter variant.assemble
}
}
you are telling gradle to include the minute in the name of your apk.
then it builds it with the name you want in the n minute, and when it wants to refer to it in the n+1 minute it cant find the file. so it encounters this error.
you better use the commit hash or the date in your apk name. (not including small units like minute or second or even hour)
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);
}
Is it possible to specify the filename of the generated *.apk through gradle? So that I automatically could get MyApp-1.0.0.apk instead of the default app-release.apk.
You can do this by adding the following line to your build.gradle file inside the android{...} part:
android.applicationVariants.all { variant ->
variant.outputFile = file("$project.buildDir/${defaultConfig.versionName}-${defaultConfig.versionCode}.apk")
}
Notes:
Everything inside the file(...) is arbitrary, of course
This code will output the *.apk to your project/module/build directory, no matter what path you've specified when Building the Signed APK.
The output-file will take the Name and Version-Code from your build.gradle file.
Android Studio may complain that it "cannot resolve symbol applicationVariants/defaultConfig" - ignore it. ;)
Got it working! Used this answer
android {
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFile = new File(
output.outputFile.parent,
output.outputFile.name.replace(".apk", "-${variant.versionName}.apk"))
}
}
}
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