19

When I use Android Studio 3.0 and I use the next version of Android Gradle Plugin in project/build.gradle:

classpath 'com.android.tools.build:gradle:3.0.1'

And it's work fine. After I update to Android Studio 3.1 , as result I update Android Gradle Plugin :

classpath 'com.android.tools.build:gradle:3.1.0'

And now I get error in my app/build.gradle:

def releaseFileName = "${rootProject.name}_${defaultConfig.versionName}.apk"
outputFileName = new File(rootProject.projectDir.absolutePath + "/release", releaseFileName.toLowerCase())

Error:

Absolute path are not supported when setting an output file name

I need to put output apk (app-release.apk) in specific path in project. In folder MyProject/release/app-relese.apk. How I can do this?

shizhen
  • 12,251
  • 9
  • 52
  • 88
Alexei
  • 14,350
  • 37
  • 121
  • 240

9 Answers9

25

Just in case this helps, this error means that now it's not allowed to have absolute paths on anything related to the apk's file name. I can attach you my BEFORE and AFTER to achieve what I needed (to have the APK in the project/app/build/ folder:

BEFORE gradle 3.1.0

applicationVariants.all { variant ->
    variant.outputs.all { output ->
        outputFileName = new File(
                output.outputFile.parent,
                output.outputFile.name)
    }
}

IN or AFTER gradle 3.1.0

applicationVariants.all { variant ->
    variant.outputs.all { output ->
        outputFileName = new File(
                "./../../../../../build/",
                output.outputFile.name)
    }
}
16

I think using "./../../../" is bad solution... I use common gradle script for several projects and I want to make code to be independency from depth of output dir.

After some researching I found this solution for gradle plugin 3.1.2:

applicationVariants.all { variant ->
    variant.outputs.all { output ->
        def relativeRootDir = output.packageApplication.outputDirectory.toPath()
                 .relativize(rootDir.toPath()).toFile()
        output.outputFileName = new File( "$relativeRootDir/release", newOutputName)
    }
}
user3155340
  • 300
  • 2
  • 5
  • 1
    This does not work any more. This answer https://stackoverflow.com/a/55682025/8034839 is the simpler and working solution. – shizhen Jul 31 '19 at 01:25
14

The simplest solution for Android Gradle plugin 3.4.0+ is as below:

Assemble/concatenate your new file name:

def newFileName = "assemble-your-new-file-name"

Then, simply assign it back.

outputFileName = newFileName

More specifically is as following

android.applicationVariants.all { variant ->
    variant.outputs.each { output ->
        // Redirect your apks to new defined location to outputDirPath
        def outputDirPath = new File("${project.rootDir.absolutePath}/apks/${variant.flavorName}/${variant.buildType.name}")
        variant.packageApplicationProvider.get().outputDirectory = outputDirPath

        def apkFileName = "${rootProject.name}_${android.defaultConfig.versionName}.apk"
        output.outputFileName = apkFileName // directly assign the new name back to outputFileName
    }
}
shizhen
  • 12,251
  • 9
  • 52
  • 88
9

I experienced the same issue. I haven't put the effort in to figure out exactly what's happened but there's a simple fix.

Just remove the root from your new file and trust the framework, i.e. change your code to

outputFileName = new File("release", releaseFileName.toLowerCase())

That was sufficient for us. We don't care about where the apk goes, only the name of the apk for a particular flavour.

Andrew Parker
  • 1,425
  • 2
  • 20
  • 28
  • I need to put output apk (app-release.apk) in specific path in project. In folder MyProject/release/app-relese.apk. How I can do this? – Alexei Mar 28 '18 at 10:13
  • Sorry, I don't have enough depth here. I'd need to set up gradle debugging and/or get into the sources to figure this out. My guess is there's some way to convert your path to a path relative to the project root. Quite why this change has been enforced and seemingly undocumented I don't know. Looks like you have a workaround for yourself at least :) – Andrew Parker Mar 29 '18 at 01:20
2

I found solution:

def releaseFileName = "${rootProject.name}_${defaultConfig.versionName}.apk"
outputFileName = "/../../../../../release/" + releaseFileName.toLowerCase()

And now output file app-release.apk success created in MyProject/release/app-relese.apk

Alexei
  • 14,350
  • 37
  • 121
  • 240
1

Use variant.packageApplicationProvider.get().outputDirectory to avoid warning "variantOutput.getPackageApplication() is obsolete"

applicationVariants.all { variant ->
    variant.outputs.each { output ->
        variant.packageApplicationProvider.get().outputDirectory = new File(
            project.rootDir.absolutePath + "/release")

        def releaseFileName = "${rootProject.name}_${defaultConfig.versionName}.apk"
        output.outputFileName = releaseFileName.toLowerCase()
    }
}
V-SHY
  • 3,925
  • 4
  • 31
  • 47
1

For gradle-6.5.1:

applicationVariants.all { variant ->
          variant.outputs.all { output ->
                  outputFileName = new File("ApkName.apk")
          }
 }
vkozhemi
  • 371
  • 2
  • 7
1

I just upgraded our project to Gradle 7.6 from 4.1.2, which removed the ability to set outputFileName to a relative dir.

This code below worked for me. It copies the build output from the expected directories to the directory of your choice. In my case, this was 2 levels up (../../.).

The key to this working is binding the copy task to the assemble tasks completion, with finalizedBy so it only runs after the Apk's have been created.

android.applicationVariants.all { variant ->
    variant.outputs.all { output ->
        File outDir = file("${project.buildDir}/outputs/apk")
        File apkDir = file("${project.buildDir}/outputs/apk/${variant.flavorName}/${variant.buildType.name}")

        def task = project.tasks.create("publish${variant.name.capitalize()}Apk", Copy)
        task.from apkDir
        task.into outDir
        task.include "**/*"
        task.doLast {
            println ">>>publish ${variant.name} success!" +
                    "\nfrom: ${apkDir}" +
                    "\ninto: ${outDir}"
        }
        output.assemble.finalizedBy task
    }
}
Rots
  • 5,506
  • 3
  • 43
  • 51
0

If you want to append the version name and version code do it like:

applicationVariants.all { variant ->
        variant.outputs.all {
            def versionName = variant.versionName
            def versionCode = variant.versionCode
            def variantName = variant.name
            outputFileName = "${rootProject.name}" + '_' + variantName + '_' + versionName + '_' + versionCode + '.apk'
        }
    }
Shailendra Madda
  • 20,649
  • 15
  • 100
  • 138