gradle 新依赖函数 implementation api详解
在 gradle 3.0 之后 compile、provided、apk 被 deprecated,取而代之的是 implementation 、api、compileOnly、runtimeOnly。
本文重点是介绍implementation和api。
api
api 修饰的依赖会被暴露并传递给外部,也就是说:在外部module引用该lib时,module会把该lib的api依赖传递依赖过来,并添加到module自己的compile classpath上。(在运行期和编译期api依赖都可见。)如果有一个api dependency修改了对外API,那么所有依赖和间接依赖了该 dependency 的module都会被重新编译。
implementation
implementation 则相反,implementation修饰的依赖不会被暴露给外部module,在引用该lib时,lib内通过implementation申明的依赖不会被添加到module 的 compile classpath上。(也就是说lib的依赖仅在runtime可见,编译期不可见。)如果有一个implementation dependency 修改了API,那么仅该dependency 和 直接依赖于它的module会被重新编译。
compile
compile 的行为和api一致,已经被标记为deprecated。
为什么要提供两种依赖函数呢?
-
可以更好的控制 transitive dependency
-
compile classpath更精简,编译速度得到提升
-
implementation dependencies 发生改变不会导致全量地重新编译
-
在POM中依赖关系更加清晰:编译library的依赖和运行library的依赖区可以分开了。
举例说明:
└── App |
A lib分别通过implementation 和 api 依赖了a1、a2;
B lib分别通过implementation 和 api 依赖了b1、b2;
App 通过implementation直接依赖了A、B lib;
App 被A传递依赖了a2;
App 被B传递依赖了b2;
- 编译App时,compile classpath中的依赖有 A、B、a2、b2
- a1 对外暴露的API有修改 —— 仅 a1 和 A 会被重新编译,b1 同理。
- a2 对外暴露的API有修改 —— a2 、 A 、App 都会被重新编译,b2 同理。
如何判断自己library的依赖属于哪种类型呢?
api 依赖一般是指那些暴露在library binary interface(也叫Application Binary Interface)中的,包括但不仅仅限于下面case:
-
在interface和父类中被引用到的
-
在
public
方法参数中引用到的,包括泛型参数 -
在
public
属性中引用到的 -
在
public
annotation 中引用到的。
注这里
public
是广义上的,泛指对编译器可见,比如:public
,protected
以及package private
概念都是public
的)
相反,下面case和ABI不相关的,则应该被申明为implementation
dependency:
-
仅仅被方法内部引用的
-
仅仅被 private 成员引用的
-
仅仅被内部类引用的(未来,Gradle 会允许用户申明那些包属于公共API)
官方提供了一个例子,如何根据上述规则推导不同依赖类型。
实际上使用时,可以偷懒地判断,大部分情况下:
- 在app和test module中应该使用implementation引入dependency
- 在library module中应该使用api引入dependency,除了非public引用的dependency。
Author: deskid
Link: https://deskid.github.io/2017/12/04/gradle-compile/
License: 知识共享署名-非商业性使用 4.0 国际许可协议