我试图弄清楚在构建我的依赖关系时,api和implementation配置之间有什么区别。
api
implementation
在文档中,它说implementation有更好的构建时间,但是,在类似的问题中看到这个评论,我想知道这是否是真的。
因为我不是Gradle的专家,我希望有人能帮助我。我已经读了文档,但我想知道一个容易理解的解释。
Gradle compile关键字已弃用,改用api和implementation关键字来配置依赖项。
compile
使用api相当于使用已弃用的compile,因此如果将所有compile替换为api,则一切都将照常工作。
要理解implementation关键字,请考虑以下示例。
例子
假设你有一个名为MyLibrary的库,它在内部使用另一个名为InternalLibrary的库。就像这样:
MyLibrary
InternalLibrary
// 'InternalLibrary' module public class InternalLibrary { public static String giveMeAString(){ return "hello"; } }
// 'MyLibrary' module public class MyLibrary { public String myString(){ return InternalLibrary.giveMeAString(); } }
假设MyLibrary build.gradle在dependencies{}中使用api配置,如下所示:
build.gradle
dependencies{}
dependencies { api project(':InternalLibrary') }
你想在你的代码中使用MyLibrary,所以在你的应用程序的build.gradle中添加这个依赖:
dependencies { implementation project(':MyLibrary') }
使用api配置(或已弃用的compile),您可以在应用程序代码中访问InternalLibrary:
// Access 'MyLibrary' (granted) MyLibrary myLib = new MyLibrary(); System.out.println(myLib.myString()); // Can ALSO access the internal library too (but you shouldn't) System.out.println(InternalLibrary.giveMeAString());
以这种方式,模块MyLibrary是潜在的“泄漏”;某物的内部实现。你不应该(不能)使用它,因为它不是你直接导入的。
dependencies { implementation project(':InternalLibrary') }
你将不能再在你的应用程序代码中调用InternalLibrary.giveMeAString()。
InternalLibrary.giveMeAString()
这种装箱策略允许Android Gradle插件知道,如果你在InternalLibrary中编辑了一些东西,它必须只触发MyLibrary的重新编译,而不则是整个应用程序的重新编译,因为你没有访问InternalLibrary的权限。
当你有很多嵌套依赖时,这种机制可以大大加快构建速度。(请观看最后链接的视频,以充分了解这一点)
结论
当你切换到新的Android Gradle插件3.X。X,你应该用implementation关键字*(1)替换你所有的compile。然后试着编译和测试你的应用程序。如果一切正常,保持代码原样,如果你有问题,你可能是你的依赖关系有问题,或者你使用了一些现在是私有的,不太容易访问的东西。* Android Gradle插件工程师Jerome Dochez的建议(1))
有用的文章显示实现和api之间的差异
< >强引用 (为了节省时间,这是同一段视频)
谷歌I/O 2017 -如何加快Gradle构建(完整视频)
< a href = " https://youtu.be/7ll-rkLCtyk?t=22m21s" rel="noreferrer">谷歌I/O 2017 -如何加速Gradle构建(新Gradle插件3.0.0部分ONLY) .
< a href = " https://youtu.be/7ll-rkLCtyk?t=30m37s" rel="noreferrer">谷歌I/O 2017 -如何加快Gradle构建(参考1*)
Android文档
我喜欢将api依赖项视为公共(其他模块可以看到),而将implementation依赖项视为私人(仅本模块可以看到)。
注意,与public/private变量和方法不同,api/implementation依赖关系不是由运行时强制执行的。这只是一个构建时优化,它允许Gradle知道当其中一个依赖项更改其API时需要重新编译哪些模块。
public
private
Gradle
假设你有app模块,它使用lib1作为库,而lib1使用lib2作为库。类似这样:app -> lib1 -> lib2。
app
lib1
lib2
app -> lib1 -> lib2
现在,当在lib1中使用api lib2时,当在app模块中使用:api lib1或implementation lib1时,则app 可以看到 lib2代码。
api lib2
api lib1
implementation lib1
但是当在lib1中使用implementation lib2时,则app 看不见 lib2代码。
implementation lib2
@matpag和@dev-bmax的答案足够清楚,可以让人们理解实现和api之间的不同用法。我只是想从另一个角度做一个额外的解释,希望对有同样问题的人有所帮助。
我创建了两个项目进行测试:
上面描述的依赖层次结构如下:
[project-b] -> [project-a] -> [spring-boot-gradle-plugin]
然后我测试了以下场景:
在B项目根目录的终端中运行gradle dependencies命令,通过以下输出截图,我们可以看到'spring-boot-gradle-plugin'出现在runtimeClasspath依赖树中,但不在compileClasspath的依赖树中,我认为这就是为什么我们不能使用使用实现声明的库,它只是不会通过编译。
gradle dependencies
< / p >
再次在B对象根目录下的终端执行gradle dependencies命令。 现在'spring-boot-gradle-plugin'同时出现在compileClasspath和runtimeClasspath依赖树中
我注意到一个显著的区别是,在生产者/库项目中以实现方式声明的依赖项不会出现在消费者项目的compileClasspath中,因此我们不能在消费者项目中使用相应的库。
从gradle文档:
让我们看一下基于jvm的项目的一个非常简单的构建脚本。
plugins { id 'java-library' } repositories { mavenCentral() } dependencies { implementation 'org.hibernate:hibernate-core:3.6.7.Final' api 'com.google.guava:guava:23.0' testImplementation 'junit:junit:4.+' }
实现 编译项目的生产源代码所需的依赖项,这些依赖项不是项目公开的API的一部分。例如,该项目使用Hibernate进行内部持久层实现。 api 编译项目生产源代码所需的依赖项,这些依赖项是项目公开的API的一部分。例如,该项目使用了Guava,并在方法签名中公开了带有Guava类的公共接口。
实现
编译项目的生产源代码所需的依赖项,这些依赖项不是项目公开的API的一部分。例如,该项目使用Hibernate进行内部持久层实现。
编译项目生产源代码所需的依赖项,这些依赖项是项目公开的API的一部分。例如,该项目使用了Guava,并在方法签名中公开了带有Guava类的公共接口。
现在在文档中有很好的解释
api配置应该用来声明依赖关系 由库API导出,而实现配置 应用于声明依赖项,这些依赖项是 组件。< / p >
关于api vs implementation还有一个技术注意事项。假设你有以下依赖项:
dependencies { api "com.example:foo:1.0" implementation "com.example:bar:1.0" }
如果你在本地Maven存储库中安装了一个生成的jar文件(在maven-publish插件的帮助下),你会看到生成的pom.xml文件看起来像这样:
maven-publish
pom.xml
<dependency> <groupId>com.example</groupId> <artifactId>foo</artifactId> <version>1.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.example</groupId> <artifactId>bar</artifactId> <version>1.0</version> <scope>runtime</scope> </dependency>
注意:api被转换为compile作用域,implementation -被转换为runtime作用域。
runtime
这允许这个库的使用者避免在他们的编译类路径中有运行时依赖项。
请参考android开发者官方网站上的链接:Android Studio依赖配置。
在dependencies块中,您可以使用几种不同的依赖项配置(如上面所示的实现)之一来声明一个库依赖项。每个依赖项配置都为Gradle提供了关于如何使用依赖项的不同说明。