tbruyelle
tbruyelle

Reputation: 13045

Gradle custom plugin : add dependency from extension object

I'm trying to write a plugin which adds dependencies to project.dependencies according to informations gathered in the plugin extension object. But it seems to be impossible.

Indeed, the data from extension object is only available in a new task or in project.afterEvaluate closure, but dependencies added in those places are ignored.


The following code tries to add the dependency in afterEvaluate but the dependency is ignored :

apply plugin: MyPlugin

myplugin {
  version '1.0'
}

class MyPlugin implements Plugin<Project> {
  void apply(Project project) {
    project.extensions.create('myplugin', MyPluginExtension)

    project.afterEvaluate {
       def version = project.myplugin.version
       project.dependencies.add("compile", "org.foo:bar:$version") // --> ignored
    }
  }
}

class MyPluginExtension {
  def version
}

In the following code the dependency injection works but I don't have access to the extension object :

apply plugin: MyPlugin

myplugin {
  version '1.0'
}

class MyPlugin implements Plugin<Project> {
  void apply(Project project) {
    project.extensions.create('myplugin', MyPluginExtension)    

    def version = project.myplugin.version // == null
    project.dependencies.add("compile", "org.foo:bar:$version") // --> fail because $version is null

  }
}

class MyPluginExtension {
  def version
}

Is there a solution ?

Upvotes: 27

Views: 15297

Answers (4)

Jared Burrows
Jared Burrows

Reputation: 55527

The easiest way to do this:

project.dependencies {
  delegate.compile("com.android.support:appcompat-v7:25.0.1")
}

Upvotes: 2

Vivin Paliath
Vivin Paliath

Reputation: 95528

I originally implemented this solution using the DependencyResolutionListener approach by Saad. However, the listener itself is called only when something iterates over the configuration associated with the dependency. For example, if you want to dynamically add a dependency to compile, you have to make sure that something later on does something like:

project.configurations.compile.each {
   ...
}

But this is something that happens as a matter of course, since compile is a known configuration for any project that uses the java plugin. However, if you are using a custom configuration (as I was), then the listener approach won't work unless you explicitly iterate over your custom configuration.

I was able to find a better way to do this, and within afterEvaluate as the OP originally wanted. I'm using a custom configuration here, but I don't see a reason why it wouldn't work for compile either:

project.afterEvaluate {
    def version = project.myPlugin.version
    project.configurations.myConfig.dependencies.add(
        project.dependencies.add("myConfig", "org.foo:bar:$version")
    )
}

Of course, at some point something still has to iterate over the dependencies for them to actually get resolved.

Upvotes: 5

Saad Farooq
Saad Farooq

Reputation: 13402

Update: I managed to figure this out since my original answer. The way do this is to add a DependencyResolutionListener in which you add the dependencies and then remove the listener so it doesn't try to add them on later resolution steps.

compileDeps = project.getConfigurations().getByName("compile").getDependencies()
project.getGradle().addListener(new DependencyResolutionListener() {
    @Override
    void beforeResolve(ResolvableDependencies resolvableDependencies) {
        compileDeps.add(project.getDependencies().create("org.foo:bar:$version"))
        project.getGradle().removeListener(this)
    }

    @Override
    void afterResolve(ResolvableDependencies resolvableDependencies) {}
})

I have a working example of a plugin that uses this here

Original Answer:

This is also late but for anyone dropping in. With the latest gradle (2.6 at the time of writing), you can add a DependencyResolutionListener and add any dependencies before dependencies are resolved.

project.getGradle().addListener(new DependencyResolutionListener() {
    @Override
    void beforeResolve(ResolvableDependencies resolvableDependencies) {
        depsToAdd.each { dep ->
            compileConfig.getDependencies()
                .add(project.getDependencies().create(dep))
        }
    }

    @Override
    void afterResolve(ResolvableDependencies resolvableDependencies) {

    }
})

However, as of this writing I was having some issues getting this to work with Android Studio IDE. The problem is tracked in my question here

Upvotes: 19

EvilDuck
EvilDuck

Reputation: 4436

Don't know if that's still relevant, but you can workaround this by explicitly adding your compile configuration to Java classpath in doFirst:

variant.javaCompile.doFirst {
    variant.javaCompile.classpath += project.configurations.myconfiguration
}

Upvotes: 1

Related Questions