Подтвердить что ты не робот

Копирование файла 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 не может просто предполагать имя и местоположение по умолчанию.

4b9b3361

Ответ 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 и т.д.