我正在尝试向我的Android项目build.gradle
添加自定义任务,以将最终的APK和Proguard的mapping.txt
复制到另一个目录中。我的任务取决于assembleDevDebug
任务:
task publish(dependsOn: 'assembleDevDebug') << {
description 'Copies the final APK to the release directory.'
...
}
根据文档,我可以看到如何使用标准Copy
任务类型执行文件复制:
task(copy, type: Copy) {
from(file('srcDir'))
into(buildDir)
}
但是假设您知道要复制的文件的名称和位置。
如何找到作为assembleDevDebug
任务一部分构建的APK文件的确切名称和位置?这可以作为财产吗?感觉好像我应该能够将文件声明为我的任务的输入,并将它们声明为assemble
任务的输出,但我的Gradle-fu不够强大。
我有一些自定义逻辑可以将版本号注入APK文件名,因此我的publish
任务不能只假设默认名称和位置。
答案 0 :(得分:28)
如果您可以获取与devDebug关联的变体对象,则可以使用getOutputFile()查询它。
因此,如果您想要发布所有变体,您可以这样:
def publish = project.tasks.create("publishAll")
android.applicationVariants.all { variant ->
def task = project.tasks.create("publish${variant.name}Apk", Copy)
task.from(variant.outputFile)
task.into(buildDir)
task.dependsOn variant.assemble
publish.dependsOn task
}
现在您可以致电gradle publishAll
并发布所有变体。
映射文件的一个问题是Proguard任务没有为您提供文件位置的getter,因此您当前无法查询它。我希望能解决这个问题。
答案 1 :(得分:9)
以下代码是我用来将apk和proguard映射存档到zip文件中的每个变体的'release'构建类型:
def releasePath = file("${rootDir}/archive/${project.name}")
def releaseTask = tasks.create(name: 'release') {
group 'Build'
description "Assembles and archives all Release builds"
}
android.applicationVariants.all { variant ->
if (variant.buildType.name == 'release') {
def build = variant.name.capitalize()
def releaseBuildTask = tasks.create(name: "release${build}", type: Zip) {
group 'Build'
description "Assembles and archives apk and its proguard mapping for the $build build"
destinationDir releasePath
baseName variant.packageName
if (!variant.buildType.packageNameSuffix) {
appendix variant.buildType.name
}
if (variant.versionName) {
version "${variant.versionName}_${variant.versionCode}"
} else {
version "$variant.versionCode"
}
def archiveBaseName = archiveName.replaceFirst(/\.${extension}$/, '')
from(variant.outputFile.path) {
rename '.*', "${archiveBaseName}.apk"
}
if (variant.buildType.runProguard) {
from(variant.processResources.proguardOutputFile.parent) {
include 'mapping.txt'
rename '(.*)', "${archiveBaseName}-proguard_\$1"
}
}
}
releaseBuildTask.dependsOn variant.assemble
variant.productFlavors.each { flavor ->
def flavorName = flavor.name.capitalize()
def releaseFlavorTaskName = "release${flavorName}"
def releaseFlavorTask
if (tasks.findByName(releaseFlavorTaskName)) {
releaseFlavorTask = tasks[releaseFlavorTaskName]
} else {
releaseFlavorTask = tasks.create(name: releaseFlavorTaskName) {
group 'Build'
description "Assembles and archives all Release builds for flavor $flavorName"
}
releaseTask.dependsOn releaseFlavorTask
}
releaseFlavorTask.dependsOn releaseBuildTask
}
}
}
它创建如下任务:
archive / projectName / packageName-buildType-versionName_versionCode.zip的内容将是:
答案 2 :(得分:6)
这是我在proguard运行时复制mappings.txt的方式
tasks.whenTaskAdded { task ->
if (task.name.startsWith("proguard")) {//copy proguard mappings
task << {
copy {
from buildDir.getPath() + "/proguard"
into '../proguard'
include '**/mapping.txt'
}
println "PROGUARD FILES COPIED"
}
}
}
答案 3 :(得分:6)
我在这里有一些好的指示,但也很难按我的意愿完成。这是我的最终版本:
def archiveBuildTypes = ["distribute"];
def archiveFlavors = ["googleplay"]
android.applicationVariants.all { variant ->
if (variant.buildType.name in archiveBuildTypes) {
variant.productFlavors.each { flavor ->
if (flavor.name in archiveFlavors) {
def taskSuffix = variant.name.capitalize()
def version = "${android.defaultConfig.versionCode} (${android.defaultConfig.versionName})" // assumes that versionName was especified here instead of AndroidManifest.xml
def destination = "${rootDir}/${project.name}/archive/${version}"
def assembleTaskName = "assemble${taskSuffix}"
if (tasks.findByName(assembleTaskName)) {
def copyAPKTask = tasks.create(name: "archive${taskSuffix}", type:org.gradle.api.tasks.Copy) {
description "Archive/copy APK and mappings.txt to a versioned folder."
from ("${buildDir}") {
include "**/proguard/${flavor.name}/${variant.buildType.name}/mapping.txt"
include "**/apk/${variant.outputFile.name}"
}
into destination
eachFile { file->
file.path = file.name // so we have a "flat" copy
}
includeEmptyDirs = false
}
tasks[assembleTaskName].finalizedBy = [copyAPKTask]
}
}
}
}
}
答案 4 :(得分:4)
def publish = project.tasks.create("publishAll")// publish all task
applicationVariants.all { variant ->
if (variant.buildType.name.equals("release")) {// Only Release
File outDir = file("//192.168.4.11/Android/Release")
File apkFile = variant.outputs[0].outputFile
File mapFile = variant.mappingFile
def task = project.tasks.create("publish${variant.name.capitalize()}Apk", Copy)
task.from apkFile, mapFile
task.into outDir
task.rename "mapping.txt", "${apkFile.name.substring(0, apkFile.name.length() - 3)}mapping.txt"// Rename mapping.txt
task.doLast{
println ">>>publish ${variant.name} success!" +
"\ndir: ${outDir}" +
"\napk: ${apkFile.name}"
}
task.dependsOn variant.assemble
publish.dependsOn task
}
}
答案 5 :(得分:0)
通常android插件会将apks放在APP / build / apk目录中。
所以,运行assembleDebug
然后ls APP/build/apk
,您应该看到: