2

I have my own Gradle plugin where I'd like to add a task which would take launcher icons from main folder and output icons for each build type/flavor folder tinted with different colors depending on user's extension configuration.

I've added the task for application variant:

variant.registerResGeneratingTask(tintTask, new File("${project.buildDir}/generated/res/${variant.name}"))

Then in the task I perform the operation described above. Until here everything is fine - the sources are generated and the folder is marked as a resource folder.

The problem is when I try to create a build and the flow hits the mergeXXXResources task (in this case xxx == debug).

At this point I get an exception comparing the mipmap-[dpi]-v4/ic_launcher in the main/res with those in generated/res/debug.

For example:

Execution failed for task ':app:mergeDebugResources'.
[mipmap-hdpi-v4/ic_launcher] /{proj_location}/android_example/app/src/main/res/mipmap-hdpi/ic_launcher.png  
[mipmap-hdpi-v4/ic_launcher] /{proj_location}/android_example/app/build/generated/res/debug/mipmap-hdpi/ic_launcher.png: 
Error: Duplicate resources

I tried different locations for my output files, but I don't believe it makes any difference. I expected the resource merger to be able to identify generated resources and parse them in the final output, but obviously I'm doing something horribly wrong.

I've tried using the Transform API instead, but perhaps because of scarce documentation and my lack of understanding my attempts weren't very successful (I couldn't locate resource files in a fashion similar to the way I've located java files during transform operation).

I'm looking for either a piece of advice on how to resolve my current problem, or an alternative approach which would perform the task I've initially set out to achieve.

EDIT: on request, code for my task action:

@TaskAction
def convertLauncherIcons() {
    def android = project.extensions.getByType(AppExtension)
    File outputDir = new File("${project.buildDir}/generated/tintLaunchIcons/res/${taskVariant.name}")

    android.sourceSets.each {
        if ("main".equals(it.name)) {
            it.res.srcDirs.each { dirIt ->
                dirIt.absoluteFile.list().each { resDir ->
                    if (resDir.startsWith("mipmap-")) {
                        def relIconPath = "${resDir}/ic_launcher.png"
                        File launcherFile = new File(dirIt.absolutePath, relIconPath);
                        if (launcherFile.exists()) {
                            BufferedImage img = ImageIO.read(launcherFile);
                            /* IMAGE MANIPULATION HERE */
                            File outputFile = new File(outputDir, relIconPath);
                            if (!outputFile.exists()) {
                                File parent = outputFile.getParentFile();
                                if (!parent.exists() && !parent.mkdirs()) {
                                    throw new IllegalStateException("Couldn't create dir: " + parent);
                                }
                                outputFile.createNewFile();
                            }
                            println "writing file ${outputFile.canonicalPath}"
                            ImageIO.write(img, "png", outputFile);
       } ... 
9
  • What is your putput path for the generated resources? Commented May 2, 2016 at 9:47
  • @Kelevandos do you mean project's merge resources output? It's the standard one, so app/build/intermediates/incremental/mergeDebugResources, app/build/intermediates/res/merged/debug and app/build/intermediates/blame/res/debug. But this is executed only after the task registered as resGeneratingTask. Commented May 2, 2016 at 11:03
  • I think the problem here is that you target the task at the build directory. Try setting the output path of the variant.registerResGeneratingTask to the main directory and let gradle take care of merging it into the build. Let me know if it helps :) Commented May 2, 2016 at 11:13
  • Ah I see. I've changed the output to ./app/src/debug/res/mipmap-[density]i/ic_launcher.pngbut I'm still getting the same error. In act of desperation I've tried overriding the resource in "main" (though obviously this is not what I ultimately want to do), but that enraged the build process even further and I got the "duplicate" error about all kinds of resources I haven't even touched. Commented May 2, 2016 at 11:36
  • Any chance you could paste in the task code? Commented May 2, 2016 at 11:43

1 Answer 1

2

Ok, summing up what we came up with in the comments discussion above:


The problem here is most probably the fact that you are trying to modify the files before the gradle script merges the main directory with the current flavor. My suggestion is that you should try firing your task after the merging is done, like this:

variant.mergeResources.doLast { //fire your task here }

This should be a bit simpler and will save you a lot of research into how the Android gradle plugin actually handles this stuff :-)

Sign up to request clarification or add additional context in comments.

1 Comment

While this is correct it will break incremental building as the output of mergeResources changes with every build, it will trigger mergeResources for every build even without any changes to any of the source files

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.