【问题标题】:Copying APK file in Android Gradle project在 Android Gradle 项目中复制 APK 文件
【发布时间】:2014-01-29 14:51:57
【问题描述】:

我正在尝试向我的 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 任务不能只假设默认名称和位置。

【问题讨论】:

  • 您是否尝试过使用 variant.packageApplication.outputFile 像这里描述的 stackoverflow.com/questions/18534313/…
  • 如果将 from 行替换为“from assembleDevDebug”会发生什么
  • 这个“将版本号注入 APK 文件名的自定义逻辑”,你介意分享一下吗?我想要它,但我的 Gradle-fu 也很弱:)

标签: android gradle android-gradle-plugin


【解决方案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 任务没有为您提供文件位置的 getter,因此您目前无法查询它。我希望能解决这个问题。

【讨论】:

  • 我收到Error:(270, 0) Could not find property 'outputFile' on com.android.build.gradle.internal.api.ApplicationVariantImpl_Decorated@4be85d24.
  • relpace :variant.outputs[0].outputFile
  • 这不再有效,因为从 gradle 3.0.0-alpha3 开始不推荐使用 variant.outputFile - gradle 控制台中的输出是:“原因:不再支持 getMainOutputFile。”你知道解决办法吗?
  • 获取输出文件工作 wrap additionalnaly applicationVariants.all { variant -&gt; variant.outputs.all { output -&gt;
【解决方案2】:

以下代码是我用于将 apk 和 proguard 映射归档到 zip 文件中的代码,用于每个具有“发布”构建类型的变体:

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 - 组装和归档所有 Release 版本
  • releaseFree - 组装和归档所有 Release 版本以免费获得风味
  • releaseFreeRelease - 组装和归档 apk 及其用于 FreeRelease 构建的 proguard 映射
  • releasePaid - 组装和归档所有发行版本以用于支付风味
  • releasePaidRelease - 组装和归档 apk 及其用于 PaidRelease 构建的 proguard 映射

archive/projectName/packageName-buildType-versionName_versionCode.zip 的内容为:

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

【讨论】:

  • 在将映射文件复制到 zip 时,这似乎不起作用。 variant.processResources.proguardOutputFile.parent 返回不包含 mapping.txt 文件的中间体/proguard 文件夹。
  • @Pete variant.mappingFile.parent 是你所需要的
  • 我稍微修改了代码,以便在构建期间输出存档名称。但奇怪的是,当我单击 Build -> Generate Signed APK 时,在 Gradle 控制台中我可以看到存档的文件名,但没有创建存档之类的。更重要的是 apk 没有添加到存档中。在这里检查我的 build.gradle:pastebin.com/Y8berupv。谢谢!
  • 我喜欢这里的概念,但许多字段(例如 packageName,例如)似乎不存在于最新的 AS 测试版中。
【解决方案3】:

我在这里得到了一些很好的指导,但也很难按照我的意愿完成。这是我的最终版本:

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

【讨论】:

  • 这对我来说有点用,当我单击 Android Studio 中的运行图标时,它会执行任务并实际复制一些内容。当我单击 Generate Signed apk 时,执行任务,但没有复制任何内容。
  • '.finalizedBy' 为我做了,'.dependsOn' 没有(没有解释 ATOW)
【解决方案4】:

这就是我在 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"
        }

    } 
}

【讨论】:

    【解决方案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
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-12-13
      • 2016-10-01
      • 2017-10-07
      • 2017-04-13
      • 1970-01-01
      • 1970-01-01
      • 2018-05-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多