前言
这一篇我们就开始讲解Gradle
编程中很重要的一个概念Project
,它就像我们Android
中的Activity
一样,是我们Gradle
编译程序的时候每天都会见到的,下面我们就开始说说这个Project
1.深入了解Project
我们首先使用AS打开我们的实战项目HelloGradle
这里我新建了几个模块,模拟我们在真实项目中的项目结构.我们一般称这个HelloGradle
为Project
,而app
,base
,http
,video
我们成为module
,也就是说一个Project
下面可以有多个Module
,而每个Module
下面又可以有多个Module
,但是我们一般不会这么做,所以我们在IDEA中的项目结构一般为:
+Project
--+Module
----+Module
----+Module
--+Module
--+Module
但是对于我们Gradle
来说不是这样的,首先HelloGradle
是一个Project
,这肯定是毋庸置疑的,但是对于我们Gradle
来说,像app
,base
等也是一个Project
,我们下面就来验证下到底是不是这样的
huangfushengdeMacBook-Pro:HelloGradle huangfusheng$ ./gradlew projects
> Configure project :app
WARNING: The following project options are deprecated and have been removed:
android.enableAapt2
This property has no effect, AAPT2 is now always used.
> Configure project :base
WARNING: The following project options are deprecated and have been removed:
android.enableAapt2
This property has no effect, AAPT2 is now always used.
> Configure project :http
WARNING: The following project options are deprecated and have been removed:
android.enableAapt2
This property has no effect, AAPT2 is now always used.
> Configure project :video
WARNING: The following project options are deprecated and have been removed:
android.enableAapt2
This property has no effect, AAPT2 is now always used.
> Task :projects
------------------------------------------------------------
Root project
------------------------------------------------------------
Root project 'HelloGradle'
+--- Project ':app'
+--- Project ':base'
+--- Project ':http'
\--- Project ':video'
To see a list of the tasks of a project, run gradlew <project-path>:tasks
For example, try running gradlew :app:tasks
BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed
我们执行了./gradlew projects
指令,最终我们看到了结果,有一个Root Project
和四个Sub Project
,这就验证了我们刚才说的对于Gradle
来说每个Module
都是一个Project
同时我们每个Project
都有一个共同点,那就是都必须有一个build.gradle
,不管你是根Project还是子Project.反之如果你没有这个build.gradle
,那么就不是一个Project
,像我们的build
,就只能称之为文件夹,而且我们的Project
最终由谁去配置管理呢?就是我们这个build.gradle
文件.根Project
的build.gradle
的作用基本上就是管理子Project
,子Project
的build.gradle
作用就是输出,像我们这个app
对应就是输出apk
,像base
就种就是输出aar
2.Project
核心API
讲解
Project
中的API
非常多,我们把它分成6组来学习,每组学习主要的API
,这样的话效率上会很高
2.1Project
相关API
2.1.1 getAllprojects()
这个方法获取工程中所有的project
(包括根project
与子project
)
我们之前验证gradle
整体结构的时候使用过一个指令./gradlew projects
,输出我们当前项目的所有Project
,它其实对应的就是我们getAllprojects()
这个方法,我们下面就写一段代码来打印下我们项目中的Project
都有哪些并且输出对应的名字
接下来我们调用下这个方法,怎么执行呢?很简单,我们随便执行一个Gradle
的任务都会执行我们这个方法
注意,我们现在在build.gradle
中写的代码都是在我们Gradle
配置阶段执行的,那如何让我们的代码在Gradle
执行阶段执行呢?我们后面学习Task
的时候为大家讲解
2.1.2 getSubProjects()
这个方法时获取当前project
下,所有的子project
,注意:这个返回结果可能为null
我们先在根Project
下面使用下这个方法,看看打印的结果
接着我们在app
的build.gradle
下面写上这段代码,把根project
的build.gradle
里面的这段代码注释掉,我们运行下,看看打印的结果
因为app
下面没有子Project
,所以什么都没有打印,也就是返回null
2.1.3 getParent()
获取当前project
的父project
(若在rooProject
的build.gradle
调用,则返回null
)
我们现在app
的build.gradle
里面调用下
接着我们在根工程下的build.gradle
里面调用下
这里我们发现根本就编译不过,编译器告诉我们在根工程下面调用getParent()
会返回null
2.1.4 getRootProject()
取项目的根project
(一定不会为null
)
我们同样分两部分来调用下,一部分在app
工程下,一部分在根工程下
我们先在app
工程下调用下
接着我们在根工程下调用
项目的根工程只有一个,所以不管在哪打印出来的值都是一样的并且不为空
2.1.5 project(String path, Closure configureClosure)
这个方法是根据path
找到对应的project
,通过闭包进行配置(闭包的参数是path
对应的project
对象)
这个方法会通过路径path
找对应的project
,如果没找到就会抛出个异常,我们试验下
我们这里传入一个不存在的工程test
,结果编译不过了,下面我们就来配置下我们存在的工程app
(这里有个地方说下,就是如果参数的最后一个是闭包,我们是可以拿到括号外边的,这个是我们在讲groovy
语法介绍过得)
我们先通过这个方法输出下我们path
对应工程的名字
我们在平时开发不可能只输出个名字这么简单,那都能配置什么呢?由于我们的参数是project
,所以project
里面的方法都可以调用
我们先看下app
的build.gradle
里面的内容
这里我们看见有三样东西,那么我们在根工程下至少能为我们的app
这个工程配置这三样东西
这里虽然可以这样写,但是实际我们基本上不会这样处理的,我们每个project
的build.gradle
最好都是只配置自己的东西,独立起来
2.1.6 allprojects(Closure configureClosure)
配置当前project
和其子project
的所有project
这里我们就假定所有的工程group
为com.hfs
,version
为1.0.0-release
我们就用我们的http
工程来试验下,打印它对应的group
和version
,看看是不是和我们写的一样
我们先看下http
工程的build.gradle
内容
接着我们执行下我们修改的代码:
2.1.7 subprojects(Closure configureClosure)
配置子project
的所有project
(不包含当前project
)
我们实际开通过程中有的时候会把我们写好的组件上传到对应的maven
服务器上,这个时候每个子工程可能都需要写一个上传到maven
服务器的插件,这个时候我们就可以通过这个方法统一为我们的子project
统一添加
2.2Task
相关API
这部分我们不在这一篇进行讲解,我们会在下一篇单独写一下Task
,跟我们这一篇写Project
一样,这部分会在哪里进行详细讲解
2.3 属性相关API
我们首先点开Project
的源码中看看它都有哪些主要的属性
首先就是默认的编译文件build.gradle
,这也就是为什么我们每个工程下面都要有一个build.gradle
文件;第二个就是我们Project
的路径分隔符,这里不区分系统,都是:
;第三个就是我们每个工程默认的输出文件夹,每个工程编译完后都会出现;下一个属性gradle.properties
我们会在下面进行讲解,剩下的就都不太主要了,我们在开发中一般也不会用到
2.3.1 在gradle
脚本文件中使用ext
扩展属性
我们先随便看下我们某个工程的build.gradle
文件,这里以video
工程为例
apply plugin: 'com.android.library'
android {
compileSdkVersion 29
buildToolsVersion "29.0.0"
defaultConfig {
minSdkVersion 19
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
我们在写我们应用程序的时候,我们知道在类中尽量不要使用固定的数字或者字符串的,我们称之为魔法值,我们一般是定义成常量来使用,那我们回头看我们这个build.gradle
文件,如果我们也把它看成一个类的话,里面是不是有好多魔法值啊,我们就需要对他们进行统一的定义.这里就需要我们的扩展属性了,那怎么写呢?很简单,使用ext{}
就可以,把你想要定义的扩展属性都写在闭包中即可,这里我们就举两个例子
我们项目中一般会有好多个工程,每个工程都需要配置这两个属性,我们难道要在每个工程的build.gradle
中都写这一段代码吗?我们回想下我们上面讲的subprojects
这个方法,我们是不是可以在这个方法里面为我们每个子工程配置啊,由于父project
中的属性子project
可以直接访问,所以我们的子工程不需要懂任何代码即可,我们实践下看看效果
我们现在根工程下配置下
然后在我们的子工程中使用下,这里我们换成http
工程来验证下
编译完没发现问题,说明这么做是可以的,但是这种方式还能不能改进呢?我们想下,我们通过subprojects
来为我们每个子工程都定义了扩展属性,虽然我们这里只写了一次,但是gradle
在编译的时候都会为子工程定义一遍扩展属性,所以从本质上来说我们每个子工程还是定义了一个扩展属性块,只不过现在是由gradle
帮我们自动进行,那应该怎么改进呢?别急,我们之前讲过子工程可以通过getRootProject
这个方法来获取根工程,那么我们是不是可以直接把扩展属性定义在根工程中呢?然后在每个子工程复用这个根工程中的扩展属性,做法很简单,直接把这个扩展属性块从我们的subProjects
中拿出来
我们在子工程中通过rootProject
来获取相应属性
这里其实我们不加这个rootProject
也可以,这里就相当于继承关系,根工程里面的属性会被子工程继承,所以子工程可以直接使用根工程的属性
到这里我们离最优的方式就差一步了,这里肯定会有同学说你为啥不一开始就说最优的呢?这个主要就演示下这个演进过程,那我们还能对它进行怎么优化呢?这里就是我们把我们的扩展属性都定义在一个gradle
文件中,这样就可以减少我们根工程下的配置代码,下面我们就来看下
这里我就拿我之前写好的来展示下,具体格式都是差不多了
/**
* 全局统一配置文件
*/
ext {
//是否单独开发每个模块
isModule = false
//版本号
versions = [
applicationId : "com.hfs.latteframework", //应用ID
versionCode : 1, //版本号
versionName : "1.0.0", //版本名称
compileSdkVersion : 28,
buildToolsVersion : "28.0.3",
minSdkVersion : 19,
targetSdkVersion : 28,
androidSupportSdkVersion : "28.0.0",
constraintLayoutVersion : "1.1.1",
runnerVersion : "1.0.1",
espressoVersion : "3.0.1",
junitVersion : "4.12",
annotationsVersion : "24.0.0",
javaSDKVersion : 1.8,
multidexVersion : "1.0.2",
butterknifeVersion : "8.4.0",
arouterApiVersion : "1.4.0",
arouterCompilerVersion : "1.2.1",
arouterannotationVersion : "1.0.4",
eventbusVersion : "3.0.0",
novateVersion : "1.5.5",
loggerVersion : "2.2.0",
fastjsonVersion : "1.1.54",
immersionbarVersion : "2.3.2-beta05",
glideVersion : "4.8.0",
bannerVersion : "2.1.4",
javaxVersion : "1.2",
lombokVersion : "1.16.6",
greendaoVersion : "3.2.2",
pickerViewVersion : "4.1.6",
superAdapterVersion : "3.6.8",
scaleImageViewVersion : "3.10.0",
zxingViewVersion : "1.3",
xxpermissionsVersion : "5.5",
rx2JavaVersion : "2.1.5",
rx2AndroidVersion : "2.0.1",
photoview : "1.2.4",
smartRefreshLayout : "1.0.5.1",
baseRecyclerViewAdapterHelper: "2.9.42",
bugly : "latest.release",
kprogresshud : "1.1.0",
stetho : "1.5.0",
alertview : "1.0.3",
VerticalTabLayout : "1.2.5",
FlycoTabLayout : "2.2.1.2@aar",
leakcanary : "1.5.1"
]
//引用的依赖
dependencies = [
"appcompat_v7" : "com.android.support:appcompat-v7:${versions["androidSupportSdkVersion"]}",
"constraint_layout" : "com.android.support.constraint:constraint-layout:${versions["constraintLayoutVersion"]}",
"runner" : "com.android.support.test:runner:${versions["runnerVersion"]}",
"espresso_core" : "com.android.support.test.espresso:espresso-core:${versions["espressoVersion"]}",
"junit" : "junit:junit:${versions["junitVersion"]}",
"support_annotations" : "com.android.support:support-annotations:${versions["annotationsVersion"]}",
"design" : "com.android.support:design:${versions["androidSupportSdkVersion"]}",
"support-v4" : "com.android.support:support-v4:${versions["androidSupportSdkVersion"]}",
"cardview-v7" : "com.android.support:cardview-v7:${versions["androidSupportSdkVersion"]}",
"recyclerview-v7" : "com.android.support:recyclerview-v7:${versions["androidSupportSdkVersion"]}",
//方法数超过65535解决方法64K MultiDex分包方法
"multidex" : "com.android.support:multidex:${versions["multidexVersion"]}",
//路由
"arouter_api" : "com.alibaba:arouter-api:${versions["arouterApiVersion"]}",
"arouter_compiler" : "com.alibaba:arouter-compiler:${versions["arouterCompilerVersion"]}",
"arouter_annotation" : "com.alibaba:arouter-annotation:${versions["arouterannotationVersion"]}",
//黄油刀
"butterknife_compiler" : "com.jakewharton:butterknife-compiler:${versions["butterknifeVersion"]}",
"butterknife" : "com.jakewharton:butterknife:${versions["butterknifeVersion"]}",
//事件订阅
"eventbus" : "org.greenrobot:eventbus:${versions["eventbusVersion"]}",
//网络
"novate" : "com.tamic.novate:novate:${versions["novateVersion"]}",
//日志
"logger" : "com.orhanobut:logger:${versions["loggerVersion"]}",
//fastJson
"fastjson" : "com.alibaba:fastjson:${versions["fastjsonVersion"]}.android",
//沉浸式状态栏
"immersionbar" : "com.gyf.immersionbar:immersionbar:${versions["immersionbarVersion"]}",
//banner
"banner" : "com.bigkoo:ConvenientBanner:${versions["bannerVersion"]}",
//图片加载
"glide" : "com.github.bumptech.glide:glide:${versions["glideVersion"]}",
//lombok
"lombokJavax" : "javax.annotation:javax.annotation-api:${versions["javaxVersion"]}",
"lombok" : "org.projectlombok:lombok:${versions["lombokVersion"]}",
//数据库
"greenDao" : "org.greenrobot:greendao:${versions["greendaoVersion"]}",
//时间,地址,条件选择器
"pickerView" : "com.contrarywind:Android-PickerView:${versions["pickerViewVersion"]}",
//展示大图+手势滑动
"scaleImageView" : "com.davemorrissey.labs:subsampling-scale-image-view:${versions["scaleImageViewVersion"]}",
//二维码扫描
"zxing" : "com.github.0xZhangKe:QRCodeView:${versions["zxingViewVersion"]}",
//危险权限库
"xxpermissions" : "com.hjq:xxpermissions:${versions["xxpermissionsVersion"]}",
//RX家族
"rx2_java" : "io.reactivex.rxjava2:rxjava:${versions["rx2JavaVersion"]}",
"rx2_android" : "io.reactivex.rxjava2:rxandroid:${versions["rx2AndroidVersion"]}",
//图片缩放
"photoview" : "com.github.chrisbanes.photoview:library:${versions["photoview"]}",
//SmartRefreshLayout
"smartRefreshLayout" : "com.scwang.smartrefresh:SmartRefreshLayout:${versions["smartRefreshLayout"]}",
//baseRecyclerViewAdapterHelper
"baseRecyclerViewAdapterHelper": "com.github.CymChad:BaseRecyclerViewAdapterHelper:${versions["baseRecyclerViewAdapterHelper"]}",
//Bugly集成
"bugly" : "com.tencent.bugly:crashreport_upgrade:${versions["bugly"]}",
//仿ios进度条 已抽取到lib中
"kprogresshud" : "com.kaopiz:kprogresshud:${versions["kprogresshud"]}",
//安卓调试神器-Stetho
"stetho" : "com.facebook.stetho:stetho:${versions["stetho"]}",
"stetho-okhttp3" : "com.facebook.stetho:stetho-okhttp3:${versions["stetho"]}",
// 仿ios弹出对话窗体 已抽取到lib中
"alertview" : "com.bigkoo:alertview:${versions["alertview"]}",
//垂直的tabLayout
"VerticalTabLayout" : "q.rorbin:VerticalTabLayout:${versions["VerticalTabLayout"]}",
//水平tablayout
"FlycoTabLayout" : "com.flyco.tablayout:FlycoTabLayout_Lib:${versions["FlycoTabLayout"]}",
//leakcanary内存泄露
"leakcanary-android" : "com.squareup.leakcanary:leakcanary-android:${versions["leakcanary"]}",
"leakcanary-android-no-op" : "com.squareup.leakcanary:leakcanary-android-no-op:${versions["leakcanary"]}",
]
}
我们看这份定义文件,主要就是定义了两个map
,一个是versions
,一个是dependencies
,当然你也可以按照你的定义方式多定义几个map
,那我们怎么使用呢?
首先要在你的根工程的build.gradle
中引入这个配置文件,一般写在最顶部
apply from: "config.gradle"
之后子工程就可以直接使用了,我这里还是拿我写的一个项目来说
apply plugin: 'com.android.library'
apply plugin: 'com.jakewharton.butterknife'
apply plugin: 'org.greenrobot.greendao'
android {
compileSdkVersion rootProject.ext.versions.compileSdkVersion
buildToolsVersion rootProject.ext.versions.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.versions.minSdkVersion
targetSdkVersion rootProject.ext.versions.targetSdkVersion
versionCode rootProject.ext.versions.versionCode
versionName rootProject.ext.versions.versionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
//MultiDex分包方法
multiDexEnabled true
//Arouter路由配置
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
includeCompileClasspath = true
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
//防止编译的时候oom、GC
dexOptions {
javaMaxHeapSize "4g"
}
compileOptions {
targetCompatibility rootProject.ext.versions.javaSDKVersion
sourceCompatibility rootProject.ext.versions.javaSDKVersion
}
}
dependencies {
// 在项目中的libs中的所有的.jar结尾的文件,都是依赖
implementation fileTree(include: ['*.jar'], dir: 'libs')
//把implementation 用api代替,它是对外部公开的, 所有其他的module就不需要添加该依赖
api rootProject.ext.dependencies["appcompat_v7"]
api rootProject.ext.dependencies["constraint_layout"]
api rootProject.ext.dependencies["cardview-v7"]
api rootProject.ext.dependencies["recyclerview-v7"]
api rootProject.ext.dependencies["support-v4"]
api rootProject.ext.dependencies["design"]
api rootProject.ext.dependencies["support_annotations"]
api rootProject.ext.dependencies["junit"]
//MultiDex分包方法
api rootProject.ext.dependencies["multidex"]
//黄油刀
annotationProcessor rootProject.ext.dependencies["butterknife_compiler"]
api rootProject.ext.dependencies["butterknife"]
//Arouter路由
annotationProcessor rootProject.ext.dependencies["arouter_compiler"]
api rootProject.ext.dependencies["arouter_api"]
api rootProject.ext.dependencies["arouter_annotation"]
//eventbus 发布/订阅事件总线
api rootProject.ext.dependencies["eventbus"]
//日志
api rootProject.ext.dependencies["logger"]
//fastJson
api rootProject.ext.dependencies["fastjson"]
//沉浸栏
api rootProject.ext.dependencies["immersionbar"]
//banner
api rootProject.ext.dependencies["banner"]
//图片加载
api rootProject.ext.dependencies["glide"]
//lombok
api rootProject.ext.dependencies["lombok"]
api rootProject.ext.dependencies["lombokJavax"]
//时间 日期 地址 条件选中器
api rootProject.ext.dependencies["pickerView"]
//GreenDao
api rootProject.ext.dependencies["greenDao"]
//scaleImageView
api rootProject.ext.dependencies["scaleImageView"]
//二维码扫描
api rootProject.ext.dependencies["zxing"]
//危险权限
api rootProject.ext.dependencies["xxpermissions"]
//RX
api rootProject.ext.dependencies["rx2_java"]
api rootProject.ext.dependencies["rx2_android"]
//smartRefreshLayout
api rootProject.ext.dependencies["smartRefreshLayout"]
//baseRecyclerViewAdapterHelper
api rootProject.ext.dependencies["baseRecyclerViewAdapterHelper"]
}
我们这种写法呢看上去比较清晰,每个子工程也不需要进行单独的配置了,修改什么东西直接在我们这个配置文件中修改即可
2.3.2 在gradle.properties
文件中使用扩展属性
这小节我们就简单说下扩展属性的另外一种方式,其实也很简单,只需要在我们gradle.properties
中定义即可,从名字也可以看出这个文件就是gradle
的属性
这里定义的只能是key-value
方式,不能像我们上面那种方式那样,我们举个例子
我们在gradle.properties
中定义一个属性isLoadHttp
来标识我们是否加载http
这个工程
然后我们在setting.gradle
中使用下
我们先把这个属性改成true
我们看见我们这个http
就变成我们项目的一个工程,接下来我们把这个属性改成false
我们看见这个http
就变成了一个普通的文件夹了
我们在这文件中也可以定义我们上小节中的变量,我们就拿其中一个举例
我们在我们的video
工程中使用下
我们总结下:在gradle.properties
中定义的属性,可以直接访问,但得到的类型为Object
,一般需要通过toXXX()
方法转型。
2.4 File
相关API
2.4.1 getRootDir()
获取rootProject
目录
2.4.2 getBuildDir()
获取当前project
的build
目录,这里我们都知道我们每个project
下面都会有一个build
文件夹
2.4.3 getProjectDir()
获取当前project
目录
我们分别在根project
和video project
下的build.gradle
中打印下
2.4.4 File file(Object path)
以我们当前的project
来寻找文件,这里我们在我们的根工程下新建一个test.gradle
,里面随便写点东西方便我们一会打印
接着我们就使用file
这个方法来找下这个文件,找到了我们就输出里面的内容,找不到就输出文件找不到
我们执行下这段代码
我们在试一下传入一个不存在的文件路径
直接编译失败
2.4.5 files(Object... paths)
这个方法和file
类似,它的入参是一个可变参数,返回值是ConfigurableFileCollection
,就是一次可以定位多个文件,我们可以遍历这个返回值进行一系列操作
2.4.6 copy(Closure closure)
文件的拷贝,这里既可以拷贝文件也可以拷贝文件夹
我们先拷贝个文件,我们现在app
工程下新建一个app.txt
,我们将他拷贝到我们的根工程build
文件夹下
我们运行下,看看根工程build
文件夹下面有没有这个文件
接下来我们拷贝一个文件夹试试,我们就把app--outputs--logs
这个文件夹拷贝到根工程的build
文件夹下
我们运行下
我们还可以在闭包中指定我们不想被拷贝的文件,用exclude{}
举例:
exclude { details ->
details.file.name.endsWith('.html')
}
我们还可以对拷贝的文件进行重命名rename{}
举例:
rename { String fileName ->
fileName.replace('test', 'test1')
}
2.4.7 fileTree(Object baseDir, Closure configureClosure)
定位一个文件树(目录+文件),可对文件树进行遍历
我们现在app
工程根目录下新建一个文件夹file
,同时我们在这个文件夹下新建几个文件
我们就来输出下这几个文件的名字,同时将他们拷贝到根工程的build
文件夹下
我们运行下
2.5 Gradle
生命周期API
这部分我们在上一篇已经将讲解过了,这里也就不再讲解了
Android Gradle学习系列(五)-Gradle生命周期探索
2.6 其它API
2.6.1 依赖相关API
谈到我们的依赖相关api
我们就不得不提一个方法buildscript{}
,我们每次新建一个项目,在项目的根工程的build.gradle
中都会有这个方法,这个方法里面就是我们依赖配置的核心部分,那这里面都能配置哪些内容呢?我们看下这个方法的源码就知道了
源码中注释告诉我们闭包的参数的类型是ScriptHandler
,由此我们猜想我们能在闭包中调用哪些方法由ScriptHandler
这个类决定,我们继续看下ScriptHandler
这个类的源码
public interface ScriptHandler {
/**
* The name of the configuration used to assemble the script classpath.
*/
String CLASSPATH_CONFIGURATION = "classpath";
/**
* Returns the file containing the source for the script, if any.
*
* @return The source file. Returns null if the script source is not a file.
*/
@Nullable
File getSourceFile();
/**
* Returns the URI for the script source, if any.
*
* @return The source URI. Returns null if the script source has no URI.
*/
@Nullable
URI getSourceURI();
/**
* Returns a handler to create repositories which are used for retrieving dependencies for the script classpath.
*
* @return the repository handler. Never returns null.
*/
RepositoryHandler getRepositories();
/**
* Configures the repositories for the script dependencies. Executes the given closure against the {@link
* RepositoryHandler} for this handler. The {@link RepositoryHandler} is passed to the closure as the closure's
* delegate.
*
* @param configureClosure the closure to use to configure the repositories.
*/
void repositories(Closure configureClosure);
/**
* Returns the dependencies of the script. The returned dependency handler instance can be used for adding new
* dependencies. For accessing already declared dependencies, the configurations can be used.
*
* @return the dependency handler. Never returns null.
* @see #getConfigurations()
*/
DependencyHandler getDependencies();
/**
* Configures the dependencies for the script. Executes the given closure against the {@link DependencyHandler} for
* this handler. The {@link DependencyHandler} is passed to the closure as the closure's delegate.
*
* @param configureClosure the closure to use to configure the dependencies.
*/
void dependencies(Closure configureClosure);
/**
* Returns the configurations of this handler. This usually contains a single configuration, called {@value
* #CLASSPATH_CONFIGURATION}.
*
* @return The configuration of this handler.
*/
ConfigurationContainer getConfigurations();
/**
* Returns the {@code ClassLoader} which contains the classpath for this script.
*
* @return The ClassLoader. Never returns null.
*/
ClassLoader getClassLoader();
}
这个源码里面的get方法我们不关心,剩下的有void repositories(Closure configureClosure);
和void dependencies(Closure configureClosure);
这两个方法,所以我们buildscript{}
里面可以这么写了
我们首选看第一个方法repositories{}
,这个是配置我们工程的仓库地址,那都能配置哪些仓库呢?我们看下它的源码
同样的我们通过注释得知,决定的是我们这个RepositoryHandler
类,我们看下RepositoryHandler
源码
public interface RepositoryHandler extends ArtifactRepositoryContainer {
FlatDirectoryArtifactRepository flatDir(Closure configureClosure);
MavenArtifactRepository jcenter();
MavenArtifactRepository mavenCentral();
MavenArtifactRepository mavenLocal();
MavenArtifactRepository google();
MavenArtifactRepository maven(Closure closure);
IvyArtifactRepository ivy(Closure closure);
}
通过源码我们知道常用的就是上面那几种,我们分别写下
OK,接下来我们看下另外一个方法dependencies{}
,这里我们突出这个方法是配置我们的插件
依赖地址,为啥呢?因为我们的Project
中也有这个方法
也就是我们工程的build.gradle
中也是可以调用一个叫dependencies
名字的方法,但是和我们在buildscript
方法中调用是完全不同的.我们想一下我们的gradle
也是一个编程框架,那么我们在编写gradle
的时候就会用到一些第三方的东西,在buildscript
中dependencies
就是来指定我们要依赖哪第三方的库,而我们project
中build.gradle
中dependencies
是我们这个工程要依赖的第三方库
其实我们上面写的代码可以简化一下,
这样看起来是不是就很熟悉了,跟我们在项目中写法就完全一样了吧
我们下面说一说build.gradle
中的dependencies
方法,我们以我们app
工程为例子
dependencies {
//第一种:依赖文件树
compile fileTree(dir: 'libs', include: ['*.jar'])
// compile file() // 依赖单个文件
// compile files() // 依赖多个文件
// 第二种:依赖仓库中的第三方库
compile 'com.android.support:appcompat-v7:26.1.0'
// 第三种依赖工程下其他Module
compile project('video') {
exclude module: 'support-v4' // 排除依赖:排除指定module
exclude group: 'com.android.support' // 排除依赖:排除指定group下所有的module
transitive false // 禁止传递依赖,默认值为false
}
// 栈内编译
provided('com.tencent.tinker:tinker-android-anno:1.9.1')
}
传递依赖:
我们一般是禁止传递依赖的,也就是工程A是禁止直接调用工程C中的依赖库的方法,只有工程B可以,因为有可能哪天工程B升级不再依赖工程C了,结果工程A还在使用,就会在编译过程中出现问题
下面我们来说说这个provided
:
- 依赖包只在编译期起作用。(如:
tinker
的tinker-android-anno
只用于在编译期生成Application
类,同时我们并不需要把该库中类打包进apk
,这样可以减小apk
包体积) - 被依赖的工程中已经有了相同版本的第三方库,为了避免重复引用,可以使用
provided
。