
Вступление
Статья пишется с прицелом на нативные андроид проекты, но, так как градл универсальная система сборки, в принципе, подойдет и для других проектов, которые может собрать градл. Идея не моя, я ее подчерпнул из гитхаб проекта у 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 }
Что получилось — исчезли версии библиотек у модулей, появилась иерархия библиотек
Также стоит отметить, что модуль не обязан зависеть от всех библиотек описанных в корневом скрипте, а только от тех, от которых необходимо.
Как я и упоминал выше, рабочий проект с использованием такой схемы находится тут.
