Блок buildscript
Каждый разработчик, использующий Gradle в качестве основного инструмента сборки, знает о блоке buildscript
. Или хотя бы знает, как им пользоваться. Прежде чем я углублюсь в то, почему мы должны избавиться от этого, я хочу объяснить, что это такое на самом деле и для чего он нужен.
buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.1.1' } }
Приведенный выше файл build.gradle
автоматически создается Android Studio каждый раз, когда вы создаете новый проект (без Kotlin), и находится в каталоге верхнего уровня вашего проекта.
Но что делает этот блок? По сути, он определяет зависимости, которые требуются для самой сборки. Или, другими словами: он определяет зависимости, которые требуются для создания вашего приложения (каким бы ни было ваше «приложение» (приложение для Android, подключаемый модуль Gradle, настольное приложение Swift…)).
В нашем примере Android мы должны определить зависимость Android Gradle Plugin, которая помогает нам создавать APK:
// project/build.gradle buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.1.1' } } // project/app/build.gradle.kts apply { plugin("com.android.application") }
Поскольку мы знаем, что он делает, почему мы должны отказываться от него? 🤔
Ну, я не говорил, что нам больше не нужна логика, лежащая в основе этого (применить зависимости, необходимые для сборки). Я скорее говорю, что мы должны заменить старый блок buildscript
чем-то «новым».
Возвышение блока плагинов
Новый блок plugins
на самом деле не нов. Это уже было введено в Gradle 2.1. В то время это явно не привлекало особого внимания.
Тем не мение. Блок плагинов удобнее для чтения и использования:
// project/app/build.gradle.kts plugins { id("org.gradle.java") kotlin("jvm") version "1.2.40" }
Вы, наверное, заметили, что это только один файл вместо двух ?!
Но есть некоторые «ограничения». По умолчанию блок plugin
может разрешать только плагины, которые:
- Основные плагины (предоставляет сама Gradle). Это, например:
org.gradle.java
,org.gradle.groovy
,org.gradle.java-gradle-plugin
и так далее… - Публикуется на Портале плагинов Gradle.
К сожалению, не все плагины Gradle доступны на портале плагинов (посмотрите на вас, Android Gradle Plugin! 😡).
Как мы можем применять такие плагины, которые не являются «основными» и не публикуются на портале плагинов?
Для этого есть довольно приятный трюк. На мой взгляд, для этого требуется некоторый «шаблонный код» в settings.gradle.kts
, но это стоит того:
pluginManagement { repositories { gradlePluginPortal() jcenter() google() } resolutionStrategy { eachPlugin { if (requested.id.id == "com.android.application") { useModule("com.android.tools.build:gradle:${requested.version}") } } } }
Сначала мы должны определить все репозитории, в которых блок plugin
должен искать плагины (порядок важен *). В блоке eachPlugin
мы можем взглянуть на каждый примененный плагин (из id("name")
) и вести себя на его основе. В нашем примере мы говорим что-то вроде:
«если id равно com.android.application, то используйте this в качестве модуля».
* Порядок на самом деле не «важен». Но Gradle будет искать примененные плагины в этих репозиториях в заданной последовательности. Возможно, вы захотите сначала добавить репозиторий с большинством доступных плагинов.
Вы можете спросить, что это за строка в useModule
? Это строка classpath
, которую мы использовали в устаревшем блоке buildscript
.
Обладая этой информацией, Gradle знает, где искать и как искать там плагины в блоке plugins
. Довольно круто, не так ли? 😎
Наконец, мы можем применить подключаемый модуль Android Gradle следующим образом:
plugins { id("com.android.application") version "3.1.1" }
Пришло время меняться!
Проблема с версией
Gradle разработан для модульности. Это означает, что проект может содержать разные модули, которые могут применять разные (или одинаковые) плагины. Если вы это сделаете, вы можете закончить так:
// project/app/build.gradle.kts plugins { id("com.android.application") version "3.1.1" kotlin("android") version "1.2.40" } // project/library1/build.gradle.kts plugins { id("com.android.library") version "3.1.1" kotlin("android") version "1.2.40" } // project/library2/build.gradle.kts plugins { id("com.android.library") version "3.1.1" kotlin("android") version "1.2.40" kotlin("kapt") version "1.2.40" }
Представьте, что вы хотите обновить применяемые плагины. Очень неприятно переходить в каждый build.gradle.kts
файл и менять там версию (кроме того, что это может привести к ошибкам. Например, вы забыли один файл Gradle или использовали неправильную версию). Но помощь есть. Другой раз, когда нам могут помочь Настройки Gradle.
Интересный факт: как разработчик Android вы, возможно, никогда не касались settings.gradle или даже не знали, что он существует, верно? 😉
Помимо добавления только useModule
(для отсутствующих плагинов на портале плагинов) мы можем дополнительно использовать useVersion
. Для всех плагинов! Даже если они опубликованы на портале плагинов (что верно для всех плагинов Kotlin):
pluginManagement { repositories { ... } eachPlugin { if (requested.id.id.startsWith("com.android")) { useModule("com.android.tools.build:gradle:3.1.1") } if (requested.id.id.startsWith("org.jetbrains.kotlin")) { useVersion("1.2.31") } } }
С этим небольшим изменением мы можем применять наши плагины без определенной версии. Теперь Gradle знает конкретную версию для всех плагинов, которые начинаются с com.android и org.jetbrains.kotlin:
plugins { id("com.android.application") kotlin("android") kotlin("kapt") }
Резюме
- Удалите блок
buildscript
- Скопируйте и вставьте приведенный выше код в свой
settings.gradle
- Используйте блок
plugins
и танцуйте 🕺