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)
}
}
}
Related
I want to upload NDK symbols on every build i do,
Under my Android inside gradle i use to have:
applicationVariants.all { variant ->
def variantName = variant.name.capitalize()
println("symbols will be added on varinat ${variantName}")
def task = project.task("ndkBuild${variantName}")
task.finalizedBy project.("uploadCrashlyticsSymbolFile${variantName}")
}
this does not compile anymore since i moved to FireBase :
Could not get unknown property 'uploadCrashlyticsSymbolFile
I don't see this task running.
I basiclly need this task to run on every build:
./gradlew app:assembleBUILD_VARIANT\
app:uploadCrashlyticsSymbolFileBUILD_VARIANT
Add this at the bottom of app's build.gradle outside android { ... } block.
afterEvaluate {
android.applicationVariants.all { variant ->
def variantName = variant.name.capitalize()
println("symbols will be added on variant ${variantName}")
def task = tasks.findByName("assemble${variantName}")
def uploader = "uploadCrashlyticsSymbolFile${variantName}"
// This triggers after task completion
task?.finalizedBy(uploader)
// This ensures ordering
task?.mustRunAfter(uploader)
}
}
You can try without afterEvaluate block. It should still work.
Likely you'd need to use Firebase App Distribution, which permits automatic upload of release build artifacts - and if you have the artifact with the matching debug symbols, they could actually be used - without the matching assembly, the symbols are somewhat irrelevant.
Number 1 is obviously a wrongful assumption, because the documentation clearly states:
./gradlew app:assembleBUILD_VARIANT app:uploadCrashlyticsSymbolFileBUILD_VARIANT
And this is already answered here.
In order to always upload, one can create a task dependency:
assembleRelease.finalizedBy uploadCrashlyticsSymbolFileRelease
This may require setting unstrippedNativeLibsDir and strippedNativeLibsDir.
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 am trying to use android build tools "com.android.tools.build:gradle:3.0.0-alpha4" in my project. In my build script I rename the output apk which worked fine in the past but does not seem to be supported any more.
android {
productFlavors {
flavorUnsigned {
applicationVariants.all { variant ->
variant.outputs.all { output ->
output.outputFile = new File(
output.outputFile.parent,
output.outputFile.name.replace("app-flavorUnsigned-release-unsigned.apk", "DemoApp-${variant.versionName}($variant.versionCode).apk"))
def mappingFile = "${rootDir}/app/build/outputs/mapping/${getCurrentFlavor()}/release/mapping.txt"
if (variant.getBuildType().isMinifyEnabled()) {
variant.assemble.doLast {
copy {
from "${mappingFile}"
into "${rootDir}/app/build/outputs/apk"
}
}
}
}
}
}
}
}
But now I am getting this error while building my project
Error:Cannot set the value of read-only property 'outputFile' for ApkVariantOutputImpl_Decorated{apkData=Main{type=MAIN, fullName=flavorUnsignedDebug, filters=[]}} of type com.android.build.gradle.internal.api.ApkVariantOutputImpl.
If you want to migrate your project to Android plugin 3.0.0-alpha1 or higher you should be doing the following :
API change in variant output:
// If you use each() to iterate through the variant objects,
// you need to start using all(). That's because each() iterates
// through only the objects that already exist during configuration time—
// but those object don't exist at configuration time with the new model.
// However, all() adapts to the new model by picking up object as they are
// added during execution.
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "${variant.name}-${variant.versionName}.apk"
}
}
Read this page to learn how to apply the plugin and adapt your project to some breaking changes.
I solved this problem with this method. Create a new project and copy the contents of build.gradle to the existing project.
I have a task that generates a metadata file based off the compiled classes in an Android Gradle build. I can get it to run by executing it after the compile task:
android.applicationVariants.all { variant ->
def variantName = variant.name.capitalize()
def compileSourcesTaskName = "compile${variantName}Sources"
def compileSourcesTask = project.tasks.findByName(compileSourcesTaskName)
compileSourcesTask.finalizedBy "myTaskThatGeneratesAssets"
}
Unfortunately, Android has already processed the assets at this point. The new file won't get included in the assembled APK.
An answer to a similar question suggests calling aapt add to add the file to the APK before alignment/signing. This seems like it could work, but the post doesn't go into implementation details. The code to call aapt in the Android Gradle plugin looks fairly complicated for a build script, and I'm not sure how to get access to the IAndroidTarget it references.
I'd appreciate suggestions on how to implement this, or any other solutions!
Okay, here's what I ended up with. It makes two assumptions that may break on later versions of the android gradle plugin (I'm using 1.3.0):
The path to the platform tools is ${android.getSdkDirectory().getAbsolutePath()}/build-tools/${android.buildToolsVersion}/
The path to the intermediate (resources) APK is ${buildDir}/intermediates/res/resources-${variant.baseName}.ap_
So long as those are true, this should generate a task to add the new asset file using aapt after the resources APK has already been built:
def overlayDir = ... // path to a resources overlay directory that contains "assets/my.json"
def addMyAssetTaskName = "add${variantName}MyAsset"
task "${addMyAssetTaskName}" (type: Exec) {
dependsOn myTaskThatGeneratesAssets
workingDir overlayDir
def aaptCommand = "${android.getSdkDirectory().getAbsolutePath()}/build-tools/${android.buildToolsVersion}/aapt"
def apkPath = "${buildDir}/intermediates/res/resources-${variant.baseName}.ap_"
commandLine aaptCommand, 'add', apkPath, "assets/my.json"
}
Then I use finalizedBy like in the question above to addMyAssetTaskName.
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