Gradle настраиваемый плагин: добавьте зависимость от объекта расширения
Я пытаюсь написать плагин, который добавляет зависимости project.dependencies
в соответствии с информацией, собранной в объекте расширения плагина. Но это кажется невозможным.
Действительно, данные из объекта расширения доступны только в новой задаче или в закрытии project.afterEvaluate
, но зависимости, добавленные в этих местах, игнорируются.
Следующий код пытается добавить зависимость в afterEvaluate
, но зависимость игнорируется:
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
}
В следующем коде инжекция зависимостей работает, но у меня нет доступа к объекту расширения:
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
}
Есть ли решение?
Ответы
Ответ 1
Обновление. Мне удалось понять это с момента моего первоначального ответа. Как это сделать, добавьте DependencyResolutionListener
, в который вы добавляете зависимости, а затем удаляете прослушиватель, чтобы он не пытался добавлять их на последующих шагах разрешения.
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) {}
})
У меня есть рабочий пример плагина, который использует этот здесь
Исходный ответ:
Это также поздно, но для тех, кто заходит. С последним gradle (2.6
на момент написания) вы можете добавить DependencyResolutionListener
и добавить любые зависимости до того, как будут решены зависимости.
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) {
}
})
Однако, на момент написания этой статьи у меня возникли некоторые проблемы с тем, чтобы работать с Android Studio IDE. Проблема отслеживается в моем вопросе здесь
Ответ 2
Я изначально реализовал это решение, используя подход DependencyResolutionListener
Саада. Тем не менее, сам слушатель называется только тогда, когда что-то выполняет итерацию по конфигурации, связанной с зависимостью. Например, если вы хотите динамически добавлять зависимость к compile
, вы должны убедиться, что что-то позже делает что-то вроде:
project.configurations.compile.each {
...
}
Но это происходит, конечно, потому что compile
- известная конфигурация для любого проекта, который использует плагин java. Однако, если вы используете настраиваемую конфигурацию (как и я), тогда подход слушателя не будет работать, если вы явно не перейдете по своей пользовательской конфигурации.
Мне удалось найти лучший способ сделать это и в рамках afterEvaluate
, как первоначально требовалось OP. Я использую настраиваемую конфигурацию здесь, но я не вижу причины, по которой она не будет работать для compile
:
project.afterEvaluate {
def version = project.myPlugin.version
project.configurations.myConfig.dependencies.add(
project.dependencies.add("myConfig", "org.foo:bar:$version")
)
}
Конечно, в какой-то момент что-то по-прежнему должно перебирать зависимости, чтобы они действительно могли быть решены.
Ответ 3
Не знаю, насколько это актуально, но вы можете обойти это, явно добавив конфигурацию компиляции в путь Java classpath в doFirst:
variant.javaCompile.doFirst {
variant.javaCompile.classpath += project.configurations.myconfiguration
}
Ответ 4
Самый простой способ сделать это:
project.dependencies {
delegate.compile("com.android.support:appcompat-v7:25.0.1")
}