Вступление
Статья пишется с прицелом на нативные андроид проекты, но, так как градл универсальная система сборки, в принципе, подойдет и для других проектов, которые может собрать градл. Идея не моя, я ее подчерпнул из гитхаб проекта у Jake Wharton SdkSearch — набор программ для поиска по документации андроид сдк.
Проблема
Современное приложение практически невозможно(нецелесообразно) написать не используя библиотеки. С появлением зависимостей возникает задача управления версионностью. Возможно для одномодульного андроид приложения средней руки это не составляет проблем, то в более крупных проектах с переиспользованием кода проблема актуальна. Особенно в управлении версиями
Решение
При таком количестве зависимостей очень важно чтобы все модули зависели от одной версии библиотеки, иначе сюрпризы в рантайме будут вылазить в самом неожиданном месте.
Градл в качестве скриптового языка использует groovy, что в паре с динамической типизацией дает удобную возможность упорядочить управление зависимостями.
В градл DSL есть возможность добавлять свойства в проект при помощи объекта ext ExtraPropertiesExtension. Также, внутри скрипта модуля можно обратиться к скрипту проекта(корневого модуля), что позволяет задекларировать все версии зависимостей в корневом скрипте, а ссылаться на них уже можно из любого модуля внутри.
Для примера, пусть наше андроид приложение использует зависимости: kotlin, kotlin stdlib, kotlin junit, facebook sdk, androidx, google material
Корневой build.gradle:
buildscript {
ext {
versions = [
'kotlin': '1.3.50',
'fb': '4.40.0'
]
deps = [
'kotlin': [
'stdlib': [
'jdk': "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}"
],
'test': [
'common': "org.jetbrains.kotlin:kotlin-test-common:${versions.kotlin}",
'annotations': "org.jetbrains.kotlin:kotlin-test-annotations-common:${versions.kotlin}",
'jdk': "org.jetbrains.kotlin:kotlin-test-junit:${versions.kotlin}"
]
],
'androidx' : [
'annotation': "androidx.annotation:annotation:1.1.0",
'appCompat': 'androidx.appcompat:appcompat:1.1.0',
'constraintLayout': 'androidx.constraintlayout:constraintlayout:1.1.3',
'ktx': 'androidx.core:core-ktx:1.1.0',
'dynamicAnimation': 'androidx.dynamicanimation:dynamicanimation:1.0.0',
'gridLayout': 'androidx.gridlayout:gridlayout:1.0.0',
'localBroadcastManager': 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0',
'multidex': 'androidx.multidex:multidex:2.0.1',
'recyclerView': 'androidx.recyclerview:recyclerview:1.1.0-beta04'
],
'material': 'com.google.android.material:material:1.0.0',
'fb': [
'core': "com.facebook.android:facebook-core:${versions.fb}",
'login': "com.facebook.android:facebook-login:${versions.fb}",
'share': "com.facebook.android:facebook-share:${versions.fb}"
]
]
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.0-alpha11'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
}
}
Пара моментов:
Если несколько зависимостей имеют одну версионность, например части одного большого сдк, то версия добавляется в свойство versions, как например с версиями котлина и фейсбука. Если же зависимость в виде одной строки, как например google material, то выносить версию нецелесообразно. Версии библиотек androidx тоже не нужно выносить, т.к. гугл отказался от выравнивания версий между собой для ускорения релизов отдельных библиотек.
В результате такого определения, во всех дочерних модулях декларация зависимостей становится лаконичной иерархией избавленной от версионности, т.к. теперь все модули зависят от одних и тех же версий библиотек.
пример раздела зависимостей модуля в build.gradle
dependencies {
implementation deps.kotlin.stdlib.jdk
implementation deps.androidx.appCompat
implementation deps.androidx.browser
implementation deps.androidx.cardView
implementation deps.androidx.constraintLayout
implementation deps.androidx.ktx
implementation deps.androidx.multidex
implementation deps.androidx.recyclerView
implementation deps.material
implementation deps.fb.core
implementation deps.fb.login
implementation deps.fb.share
testImplementation deps.kotlin.test.jdk
}
Что получилось — исчезли версии библиотек у модулей, появилась иерархия библиотек
Также стоит отметить, что модуль не обязан зависеть от всех библиотек описанных в корневом скрипте, а только от тех, от которых необходимо.
Как я и упоминал выше, рабочий проект с использованием такой схемы находится тут.
Комментарии (6)
panman
27.09.2019 11:45В данном подходе есть одна проблема. Android Studio перестает подсвечивать устаревшие версии библиотек. Если в ext выносить только версии, то подсветка останется.
soul_survivor Автор
27.09.2019 11:53Тут палка о двух концах — чтобы изменить версию библиотеки нужно пойти посмотреть, а не подняли они minSdk, не перешли ли на какую-то несовместимую зависимость, не сломали ли апи. Я обычно пересматриваю внешние зависимости где-то раз в пару месяцев либо когда узнал о новой версии из медиа — обычно стабильность билда важнее чем иметь самую самую последнюю версию библиотеки, даже если она вносит что-нибудь очень полезное.
vmm86
Я столкнулся с досадным багом Gradle-проектов в IntelliJ IDEA — пришлось откатиться на Maven. После первого же обновления проекта из конфига после внесённых изменений слетает привязка папок (исходники и ресурсы, обычные и тестовые), даже если руками прописать их в конфиге. Есть возможность это исправить, или писать багрепорт в поддержку Jetbrains? lany, можете помочь?
lany
Лучше всего написать в саппорт. Я не специалист по гредлу.