Question

Fix registerResGeneratingTask Deprecated Warning in Android Gradle

kotlinandroidandroid-studiogradleandroid-studio-3.0

Question

After upgrading to Android Studio and Android Gradle Plugin 3.0.0, the build displays this warning:

registerResGeneratingTask is deprecated; use registerGeneratedFolders(FileCollection)

What does this warning mean, and how should generated resource folders be registered with the newer Gradle API?

Short Answer

This warning means that a Gradle build script or a third-party Gradle plugin is using an older Android Gradle Plugin API for generated resources. You will learn how to find the code that produces the warning, replace the deprecated registration call with a generated-folder registration, and update dependencies when the call comes from an external plugin.

Concept

Android builds can create files during the build, such as generated source code, images, XML resources, or configuration files. Gradle and the Android Gradle Plugin (AGP) need to know where those generated files are located so they can include them in later build steps.

Older AGP integrations could register a task as a resource-generating task using registerResGeneratingTask(...). In AGP 3.0, that API was deprecated in favor of registerGeneratedFolders(FileCollection).

The newer API focuses on the important result: the generated folders. A FileCollection can also describe which task builds those folders, allowing Gradle to preserve task ordering and incremental-build information.

This matters because generated files must be available before Android packages resources or compiles source code. If a generated folder is not registered correctly, the build may fail to find a resource or may run tasks in the wrong order.

If the warning is emitted by a third-party plugin rather than your own build logic, the correct fix is usually to update that plugin. You generally cannot fix a deprecated API call inside a dependency from your app module alone.

Mental Model

Think of an Android build as a factory assembly line.

  • A generation task is a machine that creates new boxes of files.
  • A generated folder is the storage shelf where those boxes are placed.
  • AGP needs the shelf location so the next machine can use the boxes.

The old API said, “This machine generates Android resources.” The newer API says, “Here are the shelves containing generated output.” Gradle can still know which machine fills a shelf when the file collection is marked as being built by that task.

Take Quiz

Syntax and Examples

In legacy Groovy Gradle build logic, replace a deprecated registration like this:

// Deprecated in Android Gradle Plugin 3.0
variant.registerResGeneratingTask(generateTask, generatedResDir)

with a FileCollection representing the generated directory:

variant.registerGeneratedFolders(
    files(generatedResDir).builtBy(generateTask)
)

files(generatedResDir) creates a Gradle FileCollection. The .builtBy(generateTask) part tells Gradle that generateTask must run before anything consumes that folder.

A complete simplified example:

android.applicationVariants.all { variant ->
    def generatedResDir = file("$buildDir/generated/custom-res/${variant.name}")

    def generateTask = tasks.create("generate${variant.name.capitalize()}Resources") {
        outputs.dir(generatedResDir)

        doLast {
            def valuesDir = new File(generatedResDir, "values")
            valuesDir.mkdirs()
            new File(valuesDir, "generated.xml").text = '''
                <resources>
                    <string name="generated_message">Hello</string>
                </resources>
            '''.stripIndent()
        }
    }

    variant.registerGeneratedFolders(
        files(generatedResDir).builtBy(generateTask)
    )
}

The generated directory contains Android resource files, and AGP is informed that it should treat the folder as generated build output.

Step by Step Execution

Consider this build logic:

android.applicationVariants.all { variant ->
    def outputDir = file("$buildDir/generated/custom/${variant.name}")

    def generateTask = tasks.create("generate${variant.name.capitalize()}File") {
        outputs.dir(outputDir)
        doLast {
            outputDir.mkdirs()
            new File(outputDir, "message.txt").text = "Created for ${variant.name}"
        }
    }

    variant.registerGeneratedFolders(files(outputDir).builtBy(generateTask))
}

When Gradle builds the debug variant:

  1. variant.name is debug.
  2. outputDir becomes build/generated/custom/debug.
  3. Gradle creates a task named generateDebugFile.
  4. The task declares that it writes to outputDir using outputs.dir(outputDir).
  5. registerGeneratedFolders(...) gives AGP a file collection containing that directory.
  6. .builtBy(generateTask) records that the folder is produced by generateDebugFile.
  7. Before a consumer needs the generated folder, Gradle can run generateDebugFile first.

For Android resources, the task should write a valid Android resource directory structure, such as values/generated.xml or drawable/generated_icon.xml.

Real World Use Cases

Generated folders are common in Android build automation:

  • Build configuration resources: Generate XML or JSON files containing environment-specific values.
  • API clients and models: Generate Java or Kotlin source files from an API specification.
  • Localization: Convert a translation source file into Android values/strings.xml resources.
  • Asset pipelines: Transform SVG, image, or design assets into generated Android resources.
  • Feature flags: Generate a resource or source file based on build variant, flavor, or CI configuration.
  • Code-generation plugins: Plugins such as annotation processors or schema tools produce files that must be included in compilation or packaging.
Take Quiz

Real Codebase Usage

In a production project, avoid placing large custom task definitions directly in an app module when possible. Put reusable generation logic in a convention plugin or a dedicated Gradle plugin.

Useful patterns include:

  • Declare outputs: Use outputs.dir(...) or outputs.file(...) so Gradle can determine whether work is up to date.
  • Connect producer and consumer: Use files(outputDir).builtBy(task) so task dependencies are inferred instead of manually forcing task order.
  • Use variant-aware paths: Include the variant name in output paths so debug and release output never overwrite each other.
  • Validate inputs early: Fail with a clear message when a required template, API specification, or configuration value is missing.
  • Update external plugins: If a warning names a plugin task or appears after applying a dependency, check that plugin's release notes and use a version compatible with the AGP version in the project.

For current AGP versions, prefer the supported Android Components APIs and Gradle's lazy task APIs when writing new build plugins. The registerGeneratedFolders migration is mainly relevant to build logic written for the AGP 3.0-era variant API.

Common Mistakes

Replacing the method but losing the task dependency

This may register the directory, but it does not explicitly tell Gradle what produces it:

variant.registerGeneratedFolders(files(generatedResDir))

Prefer:

variant.registerGeneratedFolders(files(generatedResDir).builtBy(generateTask))

Registering the wrong directory

If a resource generator writes to build/generated/res/debug/values/generated.xml, register the resource root:

build/generated/res/debug

Do not register only the values child unless the API specifically expects that child. Android resource directories need their expected structure below the registered root.

Sharing one output folder across variants

This can cause debug and release builds to overwrite each other:

file("$buildDir/generated/resources")

Use a variant-specific folder instead:

file("$buildDir/generated/resources/${variant.name}")

Editing dependency code blindly

If an external plugin produces the warning, changing your app's build.gradle may not affect it. Upgrade or replace the plugin, or use a compatible AGP version until the plugin is updated.

Assuming deprecation is immediately fatal

A deprecation warning usually allows the build to continue, but it signals that a future plugin version may remove the old API. Fix your own build logic before upgrading further.

Comparisons

ApproachWhat it describesStatus for the AGP 3.0 migration
registerResGeneratingTask(task, dir)A task and a generated resource directoryDeprecated
registerGeneratedFolders(files(dir).builtBy(task))Generated folders and their producing taskReplacement API in this migration
Manual dependsOn onlyTask ordering, but not necessarily generated-folder integrationUsually incomplete
No registrationNeither generated output nor its relationship to the Android buildGenerated files may not be consumed

A FileCollection is more flexible than a single File: it can represent one folder, several folders, task outputs, and build dependencies.

Take Quiz

Cheat Sheet

// Old, deprecated AGP 3.0-era API
variant.registerResGeneratingTask(generateTask, generatedDir)

// Replacement
variant.registerGeneratedFolders(
    files(generatedDir).builtBy(generateTask)
)
  • generatedDir should be the root directory containing generated output.
  • Use a different output directory for each build variant.
  • Declare task output with outputs.dir(generatedDir).
  • Use .builtBy(task) to preserve the producer relationship.
  • If a third-party plugin causes the warning, update that plugin rather than changing unrelated app code.
  • For newly written plugins targeting modern AGP, check the current Android Components API instead of copying legacy variant API examples.

FAQ

What causes the registerResGeneratingTask is deprecated warning?

A Gradle script or plugin is calling an old Android Gradle Plugin API. It is often custom build logic or an outdated third-party plugin.

Does this warning stop the Android build?

Usually no. A deprecation warning means the API still works for now, but may be removed in a later version.

How do I find which code causes the warning?

Run Gradle with additional warning information, for example:

./gradlew assembleDebug --warning-mode all

Then inspect the reported script, task, or plugin name.

Should I replace registerResGeneratingTask with registerGeneratedFolders directly?

Yes, when you own the legacy build logic and the AGP version exposes that replacement API. Pass a FileCollection, commonly files(directory).builtBy(task).

Why use builtBy(generateTask)?

It tells Gradle that the generated directory is produced by that task, allowing Gradle to schedule the task before consumers use the directory.

What if the warning comes from a library or Gradle plugin?

Update the plugin to a version compatible with your Android Gradle Plugin. If no update exists, use a compatible plugin/AGP combination or migrate away from the outdated plugin.

Is registerGeneratedFolders the preferred API for every modern Android project?

Not necessarily. It was the replacement for this legacy AGP migration. New build plugins should use the APIs recommended by the AGP version they target.

Take Quiz

Mini Project

Description

Create a small Gradle task that generates an Android string resource for each application variant and registers its output as a generated folder. This models a build that creates environment-specific resources automatically.

Goal

Generate a generated_message string resource for every variant and make it available to the Android build.

Requirements

Requirement list is provided below.

Take Quiz

Keep learning

Related questions

View more