Copying APK file in Android Gradle project

▼魔方 西西 提交于 2019-11-28 03:27:49

If you can get the variant object associated with devDebug you could query it with getOutputFile().

So if you wanted to publish all variants you'd something like this:

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
}

Now you can call gradle publishAll and it'll publish all you variants.

One issue with the mapping file is that the Proguard task doesn't give you a getter to the file location, so you cannot currently query it. I'm hoping to get this fixed.

The following code is what I'm using to archive apk and proguard mapping into a zip file for each variant with 'release' build type:

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
        }
    }
}

It creates tasks like the following:

  • release - Assembles and archives all Release builds
  • releaseFree - Assembles and archives all Release builds for flavor Free
  • releaseFreeRelease - Assembles and archives apk and its proguard mapping for the FreeRelease build
  • releasePaid - Assembles and archives all Release builds for flavor Paid
  • releasePaidRelease - Assembles and archives apk and its proguard mapping for the PaidRelease build

Content of archive/projectName/packageName-buildType-versionName_versionCode.zip would be:

  • packageName-buildType-versionName_versionCode.apk
  • packageName-buildType-versionName_versionCode-proguard_mapping.txt

This is how I copy mappings.txt whenever proguard runs

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"
        }

    } 
}

I've got some good pointers here but also had a hard time to get done as I wanted. Here's my final version:

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]
                }
            }
        }
    }
}
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
    }
}

Usually the android plugin will put the apks in the APP/build/apk directory.

So, run assembleDebug then ls APP/build/apk and you should see:

  • APP-debug-unaligned.apk
  • APP-release-unaligned.apk
  • APP-release-unsigned.apk
  • APP-release.apk etc
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!