33

with Gradle 4.10.1 and the Android Gradle plugin updated to 3.3.0, I get the following warning:

WARNING: API 'variantOutput.getPackageApplication()' is obsolete and has been replaced with 'variant.getPackageApplicationProvider()'.

the line, with the surrounding context (which is assigning output file-names by build variant):

applicationVariants.all { variant ->
    variant.outputs.all { output ->

        if (variant.getBuildType().getName() in rootProject.archiveBuildTypes) {

            def buildType = variant.getBuildType().getName()
            if (variant.versionName != null) {

                def baseName = output.baseName.toLowerCase()
                String fileName = "${rootProject.name}_${variant.versionName}-${baseName}.apk"

                // this is the line:
                outputFileName = new File(output.outputFile.parent, fileName).getName()
            }
        }
    }
}

the migration guide isn't too helpful; while the variant.outputs.all might be at fault - just have no clue with what to replace that - and the migration guide refers to tasks and not to build variants. when disabling File → Settings → Experimental → Gradle → Only sync the active variant, I get even more deprecation warnings (the point is, that none of these methods are being called directly):

WARNING: API 'variant.getAssemble()' is obsolete and has been replaced with 'variant.getAssembleProvider()'.
WARNING: API 'variantOutput.getProcessResources()' is obsolete and has been replaced with 'variantOutput.getProcessResourcesProvider()'.
WARNING: API 'variantOutput.getProcessManifest()' is obsolete and has been replaced with 'variantOutput.getProcessManifestProvider()'.
WARNING: API 'variant.getMergeResources()' is obsolete and has been replaced with 'variant.getMergeResourcesProvider()'.
WARNING: API 'variant.getMergeAssets()' is obsolete and has been replaced with 'variant.getMergeAssetsProvider()'.
WARNING: API 'variant.getPackageApplication()' is obsolete and has been replaced with 'variant.getPackageApplicationProvider()'.
WARNING: API 'variant.getExternalNativeBuildTasks()' is obsolete and has been replaced with 'variant.getExternalNativeBuildProviders()'.
WARNING: API 'variantOutput.getPackageApplication()' is obsolete and has been replaced with 'variant.getPackageApplicationProvider()'.

Q: how can these deprecation warnings be avoided by migration to the new API?

Martin Zeitler
  • 1
  • 19
  • 155
  • 216
  • `output.outputFile.parent` => `variant.getPackageApplicationProvider().get().outputs.files[1]` .... google should fix it because the problem is `output.outputFile` it's internally calling `getPackageApplication()` – Selvin Jan 17 '19 at 17:00
  • @Selvin this at least fixes the one warning; while then it complains: `variant.getExternalNativeBuildTasks()` is obsolete... which would need to be replaced with `variant.getExternalNativeBuildProviders()` – Martin Zeitler Jan 17 '19 at 17:08
  • hehe `variant.getExternalNativeBuildProviders()` this comes from .... let me guess ... io.fabric plugin ... – Selvin Jan 17 '19 at 17:11
  • @Selvin you are correct; with debug enabled this hints for: `com.crashlytics.tools.gradle.ProjectVariantState.resolveDebugNativeLibsPath(ProjectVariantState.groovy:130)`. add the comment as an answer and I'd accept it, because it answers the primary question. – Martin Zeitler Jan 17 '19 at 17:15
  • So ... it's all Google's fault ... same as `registerResGeneratingTask is deprecated, use registerGeneratedResFolders(FileCollection)` from `com.google.gms.google-services` ... I give up with this ... I spent 2 days analyzing those warnings – Selvin Jan 17 '19 at 17:18
  • @Selvin I got used to ignore this one warning. but when the warnings get too many, at some point it becomes unclear, within who's responsibility they would be. – Martin Zeitler Jan 17 '19 at 17:21
  • I'm not sure if it's a good answer `variant.getPackageApplicationProvider().get().outputs.files[1]` doesnt looks good ... also `variant.getPackageApplicationProvider().get().outputs.files[0]` points to `build\intermediates\incremental\packageVariant1Varian2...` ... what if Google change 0 with 1 in next release? ... there should be easy way to get path to apk from either assemble or package task – Selvin Jan 17 '19 at 17:21
  • once Gradle 5.x will become the default, a whole lot more will break. most workarounds might only be temporary solutions. just found out that `android.enableSeparateAnnotationProcessing = true` fixes one incremental annotation processor warning for `Room`. – Martin Zeitler Jan 17 '19 at 17:30
  • https://developer.android.com/studio/known-issues ... "tasks that involve accessing `outputFile` objects no longer work. That's because variant-specific tasks are no longer created during the configuration stage. This results in the plugin not knowing all of its outputs up front, but it also means faster configuration times." – Martin Zeitler Jan 17 '19 at 17:38
  • @Selvin I've just found a workaround for the `registerResGeneratingTask()`. – Martin Zeitler Apr 11 '19 at 18:09

10 Answers10

15

variantOutput.getPackageApplication() is being caused by a changed variant API.

changing output.outputFile.parent to variant.getPackageApplicationProvider().get().outputs.files[1] is at least a temporary workaround.

source: @Selvin.


variant.getExternalNativeBuildTasks() is being caused by the io.fabric plugin.

the next version of the io.fabric plugin will use variant.getExternalNativeBuildProviders().

source: 116408637; the confirmation for a promised fix (1.28.1).


These are caused by com.google.gms.google-services:

  • registerResGeneratingTask is deprecated, use registerGeneratedResFolders(FileCollection)

  • 'variant.getMergeResources()' is obsolete and has been replaced with 'variant.getMergeResourcesProvider()'

This blog post explains how to get rid of the com.google.gms.google-services plugin altogether, by adding the XML resources, which that plugin generates, eg. from build/generated/res/google-services/debug/values/values.xml into the regular debug/values/values.xml.


The most easy and the least effort might be:

buildscript {
    repositories {
        google()
        maven { url "https://maven.fabric.io/public" }
    }
    dependencies {
        //noinspection GradleDependency
        classpath "com.android.tools.build:gradle:3.2.1"
        classpath "io.fabric.tools:gradle:1.28.1"
    }
}

For debug information: ./gradlew -Pandroid.debug.obsoleteApi=true mobile:assembleDebug

None of these warnings changes the behavior in any way.

Martin Zeitler
  • 1
  • 19
  • 155
  • 216
9

Update Fabric gradle plugin to 1.28.1

dependencies {
   classpath 'io.fabric.tools:gradle:1.28.1'
}

Changelog: https://docs.fabric.io/android/changelog.html#march-15-2019

Eliminated obsolete API warnings by switching to Gradle’s task configuration avoidance APIs, when available.

Aracem
  • 7,227
  • 4
  • 35
  • 72
Vladyslav Panchenko
  • 1,517
  • 1
  • 19
  • 23
2

You could use the simpler one, similar to this example:

applicationVariants.all { variant ->
            variant.outputs.all { output ->
                outputFileName = "${globalScope.project.name}-${variant.versionName}_${output.baseName}.apk"
            }
        }

and the result would be my_app-1.9.8_flavor1-release.apk.

In your code the problematic part (that generate the warning) is output.outputFile:

..
outputFileName = new File(output.outputFile.parent, fileName).getName()
..
ivan.panasiuk
  • 1,239
  • 16
  • 20
2

The problem is that output.outputFile is internally calling getPackageApplication()

I solved this problem by setting the directory and name of the output file myself.

applicationVariants.all { variant ->
    variant.outputs.each { output ->
        def outputDir = new File("${project.buildDir.absolutePath}/outputs/apk/${variant.flavorName}/${variant.buildType.name}")
        def outputFileName = "app-${variant.flavorName}-${variant.buildType.name}.apk"
        // def outputFile = new File("$outputDir/$outputFileName")

        variant.packageApplicationProvider.get().outputDirectory = new File("$outputDir")
        output.outputFileName = outputFileName
    }
}
Chris Parker
  • 336
  • 3
  • 13
2

So I was getting the same issue (as of this date, running Gradle 5.4.1). Furthermore, I didn't see an answer that effectively covered both application projects as well as library projects.

Thus, I wanted to make something that could theoretically be used on any project to make a single build.gradle for the whole project, if desired. Because it turned out quite well, I figured I'd add it in case someone wants something that will work for both application and library projects.

Edit:

I have updated/optimized this method since originally posting it. I am now using gradle 6.3 with Kotlin DSL and the following works swimmingly.

Edit2:

It seems somewhere in Android Gradle build tools 4.1.0 (beta) that they disabled build config generation for library projects by default, so I had to change one line to accept a null value with a backup, updated below.

/**
 * Configures the output file names for all outputs of the provided variant. That is, for
 * the provided application or library.
 *
 * @param variant Passed in with {android.defaultConfig.applicationVariants.all.this}
 * @param project The project from which to grab the filename. Tip: Use rootProject
 * @param formatString Format string for the filename, which will be called with three 
 * arguments: (1) Project Name, (2) Version Name, (3) Build Type. ".apk" or ".aar" is 
 * automatically appended. If not provided, defaults to "%1$s-%2$s_%3$s"
 */
@SuppressWarnings("UnnecessaryQualifiedReference")
fun configureOutputFileName(
    variant: com.android.build.gradle.api.BaseVariant,
    project: Project,
    formatString: String = "%1\$s-%2\$s_%3\$s"
) {
    variant.outputs.configureEach {
        val fileName = formatString.format(project.name,
            outputVariant.generateBuildConfigProvider.orNull?.versionName?.orNull ?:
                project.version, variant.buildType.name)
        val tmpOutputFile: File = when (variant) {
            is com.android.build.gradle.api.ApplicationVariant -> 
                File(variant.packageApplicationProvider!!.get().outputDirectory.asFile
                    .get().absolutePath,"$fileName.apk")
            is com.android.build.gradle.api.LibraryVariant -> 
                File(variant.packageLibraryProvider!!.get().destinationDirectory.asFile
                    .get().absolutePath,"$fileName.aar")
            else -> outputFile
        }
        (this as com.android.build.gradle.internal.api.BaseVariantOutputImpl)
            .outputFileName = tmpOutputFile.name
        println("Output file set to \"${tmpOutputFile.canonicalPath}\"")
    }
}

Original:

The relevant part is here.

android {
    if (it instanceof com.android.build.gradle.AppExtension) {
        it.applicationVariants.all { 
            com.android.build.gradle.api.ApplicationVariant variant ->
                configureOutputFileName(variant, project)
        }
    } else if (it instanceof com.android.build.gradle.LibraryExtension) {
        it.libraryVariants.all { com.android.build.gradle.api.LibraryVariant variant ->
            configureOutputFileName(variant, project)
        }
    }
}

Which simply calls the method below.

@SuppressWarnings("UnnecessaryQualifiedReference")
private void configureOutputFileName(com.android.build.gradle.api.BaseVariant variant,
    Project project) {
    variant.outputs.all { output ->
        def buildType = variant.buildType.name
        String tmpOutputFileName = outputFileName
        if (variant instanceof com.android.build.gradle.api.ApplicationVariant) {
            String fileName = "${project.name}-${variant.versionName}_${buildType}.apk"
            def defaultOutputDir = variant.packageApplicationProvider.get().outputDirectory
            tmpOutputFileName = new File(defaultOutputDir.absolutePath, fileName).name
        }
        if (variant instanceof com.android.build.gradle.api.LibraryVariant) {
            String fileName = "${project.name}_${buildType}.aar"
            def defaultOutputDir = variant.packageLibraryProvider.get()
                .destinationDirectory.asFile.get()
            tmpOutputFileName = new File(defaultOutputDir.absolutePath, fileName).name
        }
        println(tmpOutputFileName)
        outputFileName = tmpOutputFileName
    }
}
Shenk
  • 352
  • 4
  • 12
1

I wasn't using output.outputFile.parentin my gradle. The cause for variantOutput.getPackageApplication() obsolete warning was the dex count plugin. I updated it to 0.8.6 and warning is gone.

'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.6'
Rakesh
  • 1,205
  • 1
  • 14
  • 33
0

The culprit of below warning is output.outputFile

WARNING: API 'variantOutput.getPackageApplication()' is obsolete and has been replaced with 'variant.getPackageApplicationProvider()'.

To get rid of this warning for Android Gradle plugin 3.4.0+, you can manually assemble the output path as below:

def selfAssembledOutputPath = new File("${project.buildDir.absolutePath}/outputs/apk/${variant.flavorName}/${variant.buildType.name}")

Then replace your below line with selfAssembledOutputPath defined above

// this is the line:
outputFileName = selfAssembledOutputPath
shizhen
  • 12,251
  • 9
  • 52
  • 88
0

A bit less dodgy solution:

def variant = findYourVariantSomehow()
def output = findCorrectOutputInVariant(variant)
def fileName = output.outputFileName

def fileDir = variant.packageApplicationProvider.get().outputDirectory.get()

def apkFile = file("$fileDir/$fileName")

source

Peter
  • 340
  • 4
  • 13
-1

I used to wirite like this:

android.applicationVariants.all { variant ->
    if ("release" == variant.buildType.name) {
        variant.outputs.all { output ->
            outputFileName = output.outputFile.name.replace("-release", "")
        }
        variant.assemble.doLast {
            variant.outputs.all { output ->
                delete output.outputFile.parent + "/output.json"
                copy {
                    from output.outputFile.parent
                    into output.outputFile.parentFile.parent
                }
                delete output.outputFile.parent
            }
        }
    }
}

The warning pop up each time, like open AS,sync,clean...

Then I found a way to write , it will just appear in build but will not pop up each time.

android.applicationVariants.all { variant ->
    if ("release" == variant.buildType.name) {
        assembleRelease.doLast {
            variant.outputs.all { output ->
                delete output.outputFile.parent + "/output.json"
                copy {
                    from output.outputFile.parent
                    into output.outputFile.parentFile.parent
                    rename { filename ->
                        filename.replace("-release", "")
                    }
                }
                delete output.outputFile.parent
            }
        }
    }
}

If you just don't want the warning pop each time, these may have some tips for you.

-1

You can also use an older version of gradle. I changed my gradle version from 3.5.0 to 3.2.1 and it worked.enter image description here

inspiredMichael
  • 370
  • 4
  • 9
  • This merely depends on the Gradle version. Meanwhile have it working with little warnings, with the latest Fabric & Google Play Services plug-ins. – Martin Zeitler Sep 20 '19 at 20:44