添加 Android Gradle 插件作为运行时依赖

Add Android Gradle plugin as a runtime dependency

我正在为 Android 编写一个 Gradle 插件,它使用新的 Transform API。不幸的是,我在将 Android 插件添加为我的插件的依赖项时遇到了问题。我的插件的简化 Gradle 配置如下所示:

plugin/build.gradle:

apply plugin: "groovy"

dependencies {
    compile gradleApi()
    compile localGroovy()
    compile "com.android.tools.build:gradle:1.4.0-beta2"
}

这是使用我的 Gradle 插件的应用程序项目的简化配置:

application/build.gradle:

buildscript {
    dependencies {
        classpath "com.android.tools.build:gradle:1.4.0-beta2"
        classpath "my-plugin:my-plugin:1.0.0"
    }
}

apply plugin: "com.android.application"
apply plugin: "my-plugin"

android {
    compileSdkVersion 23
    buildToolsVersion '23.0.1'

    defaultConfig {
        applicationId 'com.myapplication'
        minSdkVersion 16
        targetSdkVersion 23
        versionCode 1
        versionName version
    }
}

使用此配置一切正常,但我还希望我的插件能够与使用以前版本的 Android 插件的项目一起正常工作。所以我尝试在我的应用程序配置文件中更改 Android 插件版本:

application/build.gradle(使用 Android 插件 1.3.1):

buildscript {
    dependencies {
        classpath "com.android.tools.build:gradle:1.3.1"
        classpath "my-plugin:my-plugin:1.0.0"
    }
}

/* Everything else is the same. */

但在这种情况下 Android 插件 1.4.0-beta2 仍然被使用。我相信这是因为当 Gradle 解析类路径依赖时,它更喜欢 1.4.0-beta2 而不是 1.3.1 所以整个项目开始使用 1.4.0-beta2 版本的 Android 插件。

我也尝试过将 Android 插件添加为 runtime 依赖项,但在进行此更改后,我的插件停止编译,因为 'unable to resolve' 错误如下:

Unable to resolve class com.android.build.gradle.api.BaseVariant @ line 19, column 1.
import com.android.build.gradle.api.BaseVariant

有没有办法根据最新版本的 Android 插件构建我的插件,但在运行时使用构建环境提供的 Android 插件版本?

最后,我通过手动添加 provided 范围解决了这个问题。这是一篇关于将 provided 作用域添加到 Gradle 的好文章:http://www.sinking.in/blog/provided-scope-in-gradle/。不幸的是,它没有解释如何让 maven-publish 插件处理 provided 范围。所以我将解释如何做到这一点。

在我的项目中,我在 buildSrc 中有一个小插件,负责发布到 Maven。我将所有与 provided 相关的代码添加到此插件中,但它可以添加到 build.gradle 文件中。

插件框架如下所示:

class PublishPlugin implements Plugin<Project> {
    private static final PROVIDED_CONFIGURATION_NAME = "provided"

    private Project project

    @Override
    void apply(final Project project) {
        project.apply plugin: 'java'
        project.apply plugin: 'maven-publish'
        project.apply plugin: 'com.jfrog.bintray'
        project.apply plugin: 'idea'

        addProvidedConfiguration()
        configureIdeaModule()

        project.afterEvaluate {
            modifyPomDependencyScopes()
        }
    }

然后我们创建一个 provided 作用域。可以在编译期间使用使用此作用域添加的依赖项。在生成的 pom.xml 文件中,这些依赖项将具有 provided 范围。

    private void addProvidedConfiguration() {
        final Configuration provided =
                addConfiguration(project.configurations,
                        PROVIDED_CONFIGURATION_NAME)
        final Javadoc javadoc =
                project.tasks.getByName(JavaPlugin.JAVADOC_TASK_NAME) as Javadoc
        javadoc.classpath = javadoc.classpath.plus(provided)
    }

    private static Configuration addConfiguration(
           final ConfigurationContainer configurations, final String name) {
        final Configuration compile =
                configurations.getByName(JavaPlugin.COMPILE_CONFIGURATION_NAME)
        final Configuration configuration = configurations.create(name)

        compile.extendsFrom(configuration)
        configuration.visible = false
        configuration.transitive = false

        configuration.allDependencies.all { final dependency ->
            configurations.default.exclude(
                    group: dependency.group, module: dependency.name)
        }

        return configuration
    }

我使用 IntelliJ IDEA,所以我需要将其设为 'understand' provided 范围。如果你使用它,你必须对 Eclipse 做同样的事情。

    private void configureIdeaModule() {
        project.idea.module {
            scopes.PROVIDED.plus += [project.configurations.provided]
        }
    }

最后我们需要更改生成的 pom.xml 文件中的范围。默认情况下 Gradle 将所有依赖项的范围设置为 runtime。如果需要,以下代码将它们更改为 compileprovided

    private void modifyPomDependencyScopes() {
        modifyPomDependencyScope(JavaPlugin.COMPILE_CONFIGURATION_NAME)
        modifyPomDependencyScope(PROVIDED_CONFIGURATION_NAME)
    }

    private void modifyPomDependencyScope(final String scope) {
        project.publishing.publications.all {
            pom.withXml {
                final DependencySet dependencies =
                        project.configurations.getByName(scope).allDependencies
                asNode().dependencies.'*'.findAll() {
                    dependencies.find { it.name == node.artifactId.text()
                }.each { it.scope*.value = scope }
            }
        }
    }
}

就是这样。然后你只需要将这个插件应用到一个需要发布到 Maven 的项目中,并将依赖类型从 compile 更改为 provided:

apply plugin: "groovy"
apply plugin: "my-publish-plugin"

dependencies {
    compile gradleApi()
    compile localGroovy()
    provided "com.android.tools.build:gradle:1.4.0-beta2"
}