原文地址:https://hackernoon.com/android-how-to-add-gradle-dependencies-using-foreach-c4cbcc070458#.mqxce4ehy
如果一个大的android项目中有几个modules并且有多个Gradle文件需要配置的话,是一个神烦的任务,通常要做的是向每个模块添加依赖项,在本篇文章中将介绍如何使用一个Gradle文件来控制所有模块的依赖项。
我们的目标是将如下的文件:
dependencies {
compile ‘com.android.support:appcompat-v7:24.2.0’
compile ‘com.google.dagger:dagger:2.7’
apt ‘com.google.dagger:dagger-compile:2.7’
compile ‘io.reactivex:rxjava:1.2.0’
compile ‘io.reactivex:rxandroid:1.2.1’
compile ‘com.squareup.okhttp3:okhttp:3.4.1’
compile ‘com.google.code.gson:gson:2.7’
testCompile ‘junit:junit:4.12’
}
转换成如下:
dependencies {
rootProject.appDependencies.each {
add(it.configuration, it.dependency, it.options)
}
}
Dependencies File
为了完成这个转换,首先创建一个文件来管理项目依赖
创建一个文件denpendencies.gradle在项目的根目录下,然后定义所有用到的library的版本号。
ext{
def versionAndroidSDK = '24.2.0'
def versionDagger = '2.7'
def versionRxJava = '1.2.0'
def versionRxAndroid = '1.2.1'
def versionOkHttp = '3.4.1'
def versionGson = '2.7'
def versionJUnit = '4.12'
}
一旦完成,让我们创建依赖映射,为了使文件尽量有组织,将定义三个map,一个用于Android官方库,一个用于第三方库,最后一个用于测试库。
看一下文件的样子:
ext {
//...
///
/// LIBS
///
def androidLibs = [
appCompat : [group: 'com.android.support', name: 'appcompat-v7', version: versionAndroidSDK]
]
def libs = [
dagger: [group: 'com.google.dagger', name: 'dagger', version:versionDagger],
daggerCompiler: [group: 'com.google.dagger', name: 'dagger-compiler', version:versionDagger],
rxAndroid: [group: 'io.reactivex', name: 'rxandroid', version: versionRxAndroid],
rxJava: [group: 'io.reactivex', name: 'rxjava', version: versionRxJava],
rxOkHttp: [group: 'com.squareup.okhttp3', name: 'okhttp', version: versionOkHttp],
gson: [group: 'com.google.code.gson', name: 'gson', version: versionGson],
]
def testLibs = [
junit: [group: 'junit', name: 'junit', version: versionJUnit]
]
}
现在每个模块都需要包含一个所有依赖项的列表。
作为一个示例,app模块将会使用到所定义的AppCompat,Dagger,RxJava
和RxAndroid,如下列表所示:
ext {
// Versions
/// Libs
/// Modules dependencies
appDependencies = [
[configuration: "compile", dependency: androidLibs.appCompat],
[configuration: "compile", dependency: libs.dagger],
[configuration: "apt", dependency: libs.daggerCompiler],
[configuration: "compile", dependency: libs.rxAndroid],
[configuration: "compile", dependency: libs.rxJava],
]
}
列表中的每一个对象,都包含一个定义依赖关系的映射及其配置,在这个例子中使用了compile和apt配置,但是还有很多,如“provided”,“testCompile”,“androidTestCompile”,等等。
现在打开app模块的gradle文件,并且使用如下代码:
dependencies{
rootProject.appDependencies.each{
add(it.configuration,it.dependency)
}
}
这是如何工作的?
通常我们添加一个依赖项如下所示:
compile 'com.google.code.gson:gson:2.7'
DependencyHandle对象添加方法会被直接调用,让我们看一下这个添加方法:
add(String configurationName,Object dependencyNotation)
向给定配置添加依赖关系
这两个方法接受两个参数,第一个是配置名称(compile,testCompile,androidTestCompile),第二个参数是依赖本身。
Dependency可以按照常规方式定义为一个String变量。
'com.google.code.gson:gson:2.7'
如果使用最新的gradle版本的话,可以被定义成一个Map。
[group:'com.google.code.gson',name:'gson',version:'2.7']
回到代码:
dependencies{
rootProject.appDependencies.each{
add(it.configuration,it.dependency)
}
}
appdependencies列表在迭代之前创建,每次迭代都添加一个依赖项及其配置,it表示在迭代中表示当前元素。
这个过程需要在每个build.gradle文件中重复进行,这样当需要新的依赖时只需要把依赖添加到依赖文件中相应的集合中,这样,所有的依赖关系只用控制这一个文件中,此文件将可以在其他Android项目中重复使用。
模块之间的依赖
可以用于添加模块之间的依赖项
要这样做,需要在dependencies.gradle文件中定义所有模块,比如,app、data和domain模块。
{
/// Versions
/// Libs
/// Module dependencies
///
/// Modules
///
def modules = [
app: ':app',
data: ':data',
domain: ':domain'
]
}
如果app模块要使用domain模块的话,那么dependency需要按如下方式添加:
ext {
// Versions
/// Libs
/// Modules dependencies
appDependencies = [
[configuration: "compile", dependency: androidLibs.appCompat],
[configuration: "compile", dependency: libs.dagger],
[configuration: "apt", dependency: libs.daggerCompiler],
[configuration: "compile", dependency: libs.rxAndroid],
[configuration: "compile", dependency: libs.rxJava],
// Domain dependency
[configuration: "compile", dependency: project(modules.domain)],
]
}
可选项
如果需要任何其他选项,例如排除模块或使用可传递,常规的方法是:
androidTestCompile ('com.android.support.test:runner:0.5'){
exclude module:'support-annotations'
}
首先要做的是,在依赖中添加一个额外的键值来表示选项。让我们看一个例子:
// Exclude example
[configuration: "androidTestCompiler", dependency: testRunner,
options: { exclude module: 'support-annotations'}]
现在app模块中的build.gradle文件中需要修改并且更改add方法,因此他添加一个闭包作为一个额外的参数以添加选项:
add(String configurationName,Object dependencyNotation,Closure configurationClosure)
向给定配置添加依赖关系,并使用给定的闭包配置依赖关系。
build.gradle文件看起来如下:
dependencies{
rootProject.addDependencies.each{
add(it.configuration, it.dependency, it.options)
}
}
插件
有了这个过程,我们也可以管理,我们在每个模块中使用的插件,并通过dependencies.gradle文件来控制所有的插件,让我们看一个例子:
apply plugin:'com.neebedankt.android-apt'
apply plugin:'realm-android'
apply plugin:'com.tatarka.retrolambda'
可以用如下替换:
rootProject.appPlugins.each{
apply plugin.it
}
只需要创建一个列表,该插件将有dependencies.gradle文件中的模块使用。
ext {
/// Versions
/// Libs
/// Modules Dependencies
/// Modules
/// Plugins
appPlugins = [
'com.neenbedankt.android-apt',
'realm-android',
'me.tatarka.retrolambda'
]
}
调用dependencies.gradle
以上所有过程得以调用完全依赖于在项目根路径下的build.gradle文件中调用dependencies.gradle文件
apply from: 'dependencies.gradle'
缺点
在这个过程中并非一切都是完美的,这种添加管理依赖的方式使得Android Studio在库过时的时候得到通知。
为了解决这个问题,可以使用常规方法和此方法共同管理,Android原生库使用常规方法管理以便在过时的时候接收到通知。
dependencies {
compile "com.android.support:appcompat-v7:$rootProject.versionAndroidSDK"
rootProject.appDependencies.each {add(it.configuration, it.dependency, it.options)
}
}