0x2、依赖规则
Gradle会声明每个依赖项的适用范围,可以理解为 分组
,如:有些依赖在编译时用到,有些则在运行时用到,Gradle通过 Configuration
来表示这个范围(分组),不同的Configuration通过不同的name区分。
许多Gradle插件会预置一些Configuration添加到你的项目中,如Java插件:
有点懵,没关系,看下Android内置的这些Configuration你就懂了(2.x是废弃的):
// 对应2.x的 compile,既参与编译又参与打包 implementation → 当前模块依赖,但不向其他模块暴露此依赖,编译时只能在本模块访问; api → 当前模块依赖,且向其他模块暴露此依赖,同compile; 举例区分下: 模块A、B,如果A依赖了Gson库,B依赖A,使用implementation,B用不了Gson,使用api,B可以使用Gson。 // 对应2.x的provided和apk,用的较少 compileOnly → 编译时有效,不会参与打包; runtimeOnly → 运行时有效,不会参与编译; annotationProcessor → 注解处理器依赖 testCompile → 对应2.x的testImplementation,只在单元测试代码的编译以及最终打包测试apk时有效; debugCompile → 对应2.x的debugImplementation,只在debug模式的编译和最终的debug apk打包时有效; releaseCompile → releaseImplementation,只在release的编译和最终的release apk打包时有效; 附:四种依赖方式 // ① 本地library依赖 implementation project(":mylibrary") // ② 本地二进制依赖 implementation files('libs/xxx.jar', 'libs/yyy.jar') // 依赖特定库 implementation fileTree(dir: 'libs', include: ['*.jar']) // 依赖目录下的库 // ③ 远程二进制依赖 implementation('io.reactivex:rxandroid:1.2.1') // ④ AAR包依赖 implementation(name: 'me.leolin:ShortcutBadger', ext: 'aar') // 本地 implementation 'me.leolin:ShortcutBadger:1.1.17@aar' // 远程
当然,你也可以自定义一个Configuration,示例如下:
allprojects { // 配置maven仓库地址 repositories { maven { url "https://maven.aliyun.com/repository/jcenter" } } } // 定义一个名为myDependency的Configuration configurations { myDependency } // 为自定义Configuration添加依赖 dependencies { myDependency('io.reactivex:rxjava:1.1.9') myDependency('io.reactivex:rxandroid:1.2.1') } // 打印自定义Configuration下载依赖后的文件地址 task showMyDependency { println configurations.myDependency.asPath }
终端键入:gradle showMyDependency,输出结果如下:
还可以调 extendsFrom
方法来继承另一个Configuration的所有dependencies,比如implementation就继承了compile。
最后还得提提两个标志,默认都为true:
- canBeResolved:编译时依赖
- canBeConsumed:运行时依赖
0x3、依赖创建的过程
Tips:跟源码了解下原理,不感兴趣可以直接跳过,不影响后续学习~
1. 依赖识别
build.gradle
处点开 dependencies
,定位到了 Project
类:
看注释:传递的闭包由此Project的 DependencyHandler
执行,定位到此接口:
可以看到每个方法都返回 Dependency
实例,点开这个接口:
噢吼,接口定义了获取group、name、version的方法,回到 DependencyHandler
的 add()
方法,最多可传递三个参数:
implementation(io.reactivex:rxandroid:1.2.1) { transitive = false } Dependency add(String configurationName, Object dependencyNotation, Closure configureClosure); // 参数一一对应: implementation、io.reactivex:rxandroid:1.2.1、后面跟着的大括号(依赖配置闭包)
AS只能跟到这里,接着用VS Code打开Gradle的源码,全局搜下 implements DependencyHandler
,定位到 DefaultDependencyHandler
类:
该类除了实现 DependencyHandler
接口外,还实现了一个**MethodMixIn
** 接口:
在讲解这个接口前,我们先来了解下Groovy语言的两个特性:invokeMethod 和 methodMissing,先介绍下前者:
package groovy.reflect class InvokeTest1 { def hello() { '执行Hello方法' } def invokeMethod(String name, Object args) { return "未知方法 $name(${args.join(',')})" } static main(args) { def it = new InvokeTest1() println it.hello() println it.foo("test", 28) } } // 运行输出: // 执行Hello方法 // 未知方法 foo(test, 28)
对于一个对象的方法调用,类中有此方法就分发给此方法,如果不能分派,就调用invokeMethod方法,而methodMissing同样能实现上面的效果:
package groovy.reflect class InvokeTest1 { def hello() { '执行Hello方法' } def methodMissing(String name, Object args) { return "未知方法 $name(${args.join(',')})" } static main(args) { def it = new InvokeTest1() println it.hello() println it.foo("test", 28) } }
输出结果相同,而在Groovy中invokeMethod是用来 分发一个对象的所有方法 (已实现和未实现)的,要借助 GroovyInterceptable
接口。而methodMissing则只能 分发一个类未实现的方法,无论它是否实现了GroovyInterceptable接口。
总结下就是:invokeMethod管理所有方法,methodMissing只管理类所有的未实现方法!
弄懂后回到 MethodMixIn
接口,其实就是Gradle对methodMissing的封装,类想要实现这个特性,只需实现此接口,接口中定义了一个抽象方法 getAdditionalMethods()
返回一个 MethodAccess
对象:
定义了两个方法:判断某Method是否存在,动态执行Method,如出一辙,可以,跟下 getAdditionalMethods
重写处:
跟下哪里给 dynamicMethods
属性赋值:
跟下 DynamicAddDependencyMethods
:
参数个数判断,最后都调用到 dependencyAdder.add()
,而 DependencyAdder
是一个内部接口,跟下哪里实现了:
实际上还是调用的 DefaultDependencyHandler
的 doAdd()
方法:
判断dependencyNotation是否为Configuration对象,如果存在,就让当前的configuration对象继承dependencyNotation,即将添加到dependencyNotation的依赖都添加到configuration中。
2. 依赖创建
往下一点,可以看到 DefaultDependencyHandler
调用 create()
方法创建了一个 Dependency
的实例,跟下:
跟下:DefaultDependencyFactory → createDependency()
调用 dependencyNotationParser
实例的 parseNotation()
创建了 Dependency
实例,往上跟下:
构造方法里设置了这个参数,跟下哪里传入的:
跟下:DependencyNotationParser → parser()