Копирование файла APK в Android-проекте Gradle
Я пытаюсь добавить пользовательскую задачу в свой проект 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)
}
но предполагается, что вы знаете имя и расположение файла, который хотите скопировать.
Как найти точное имя и расположение файла APK, который был создан как часть задачи assembleDevDebug
? Является ли это доступным как собственность? Мне кажется, что я могу объявить файлы в качестве исходных данных для моей задачи и объявить их как выходы из задачи assemble
, но мой Gradle -fu недостаточно силен.
У меня есть специальная логика для ввода номера версии в имя файла APK, поэтому моя задача publish
не может просто предполагать имя и местоположение по умолчанию.
Ответы
Ответ 1
Если вы можете получить объект-вариант, связанный с 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 не дает вам геттер для местоположения файла, поэтому вы не можете его запросить. Я надеюсь, что это исправлено.
Ответ 2
Следующий код - это то, что я использую для архивирования сопоставления 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
}
}
}
Он создает такие задачи, как:
- release - собирает и архивирует все сборки релиза
- releaseFree - собирает и архивирует все сборки релизов для аромата Бесплатно
- releaseFreeRelease - собирает и архивирует apk и его отображение proguard для сборки FreeRelease
- releasePaid - собирает и архивирует все версии релизов для аромата Paid
- releasePaidRelease - собирает и архивирует apk и его сопоставление proguard для сборки PaidRelease
Содержимое архива /projectName/packageName -buildType-versionName_versionCode.zip будет:
- PACKAGENAME-buildType-versionName_versionCode.apk
- PACKAGENAME-buildType-versionName_versionCode-proguard_mapping.txt
Ответ 3
Вот как я копирую файл mappings.txt всякий раз, когда proguard запускает
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"
}
}
}
Ответ 4
У меня есть несколько хороших указателей здесь, но мне также было трудно сделать то, что я хотел. Вот моя окончательная версия:
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]
}
}
}
}
}
Ответ 5
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
}
}
Ответ 6
Обычно плагин android помещает apks в каталог APP/build/apk.
Итак, запустите assembleDebug
, затем ls APP/build/apk
, и вы увидите:
- APP-отладки unaligned.apk
- APP-релиз-unaligned.apk
- APP-релиз-unsigned.apk
- APP-release.apk
и т.д.