Is there a way to use DslLifecycle methods of AndroidComponentsExtension in custom gradle plugin included as composite build?

Viewed 125

In my project I use custom gradle plugin to combine different linters (like detekt, cpd, android linter) and collect all reports in one place. I add plugin to my projects with includeBuild as a composite build.

Originally I used to configure Android Linter by setting properties of lintOptions after evaluation of the project.

class StaticAnalysisPlugin : Plugin<Project> {

    override fun apply(target: Project) {
        with(target) {
            setupLintForProject(target)

            // create StaticAnalysis tasks
        }
    }

    private fun setupLintForProject(project: Project) {
        project.gradle.projectsEvaluated {
            project.subprojects
                .mapNotNull { it.extensions.findByType(AppExtension::class.java) }
                .first()
                .lintOptions.apply {
                        xmlReport = true
                        htmlReport = false
                        textReport = false
                        xmlOutput = project.getLintReportFile()
                    }
                }
        }
    }

    private fun Project.getLintReportFile() = file("${rootProject.buildDir}/reports/lint-report.xml")
}

After updating AGP to 7.0+ I got this exception while configuring the project.

It is too late to set abortOnError
It has already been read to configure this project.
Consider either moving this call to be during evaluation,
or using the variant API.

Google presented new API to customize the DSL Objects programmatically. It perfectly works but only if you use plugin inside buildSrc.

But when you try to get AndroidComponentsExtension inside composite plugin when configuring the project like this

private fun setupForProject(project: Project) {
        project.subprojects
            .mapNotNull { it.extensions.findByType(AndroidComponentsExtension::class.java) }
            .first()
            .finalizeDsl { ext ->
                ext.lint {
                    xmlReport = true
                    htmlReport = false
                    textReport = false
                    xmlOutput = project.getLintReportFile()
                }
            }
    }

You'll get exception because certain extension of subproject is not created yet.

But if you get AndroidComponentsExtension after project evaluated like this:

private fun setupForProject(project: Project) {
        project.gradle.projectsEvaluated {
            project.subprojects
                .mapNotNull { it.extensions.findByType(AndroidComponentsExtension::class.java) }
                .first()
                .finalizeDsl { ext ->
                    ext.lint {
                        xmlReport = true
                        htmlReport = false
                        textReport = false
                        xmlOutput = project.getLintReportFile()
                    }
                }
        }
    }

your configuration will have no effect.

So, I wonder is there a way to customize DSL objects like Lint in custom plugin included as composite build via includeBuild?

1 Answers

It seems you're getting an error because the com.android.library or com.android.application plugin is not yet applied. So make sure to apply the necessary plugin mentioned above before calling the finalizeDsl method. A minimal example to help you get started.

project.subprojects
        .mapNotNull { it.extensions.findByType(AndroidComponentsExtension::class.java) }
        .first().apply {
            project.pluginManager.apply("com.android.library")
            finalizeDsl { ext ->
                ext.lint {
                    xmlReport = true
                    htmlReport = false
                    textReport = false
                    xmlOutput = project.getLintReportFile()
                }
            }
        }
Related