在更新到Android Studio 3.0并创建一个新项目后,我注意到在构建中。gradle有一种新方法来添加新的依赖项,而不是compile,而是implementation,而不是testCompile,而是testimplemimplementation。

例子:

 implementation 'com.android.support:appcompat-v7:25.0.0'
 testImplementation 'junit:junit:4.12'

而不是

 compile 'com.android.support:appcompat-v7:25.0.0'
 testCompile 'junit:junit:4.12'

它们之间的区别是什么,我应该用什么?


当前回答

博士tl;

只是替换:

使用实现(如果你不需要传递性)或API(如果你需要传递性)编译 使用testimplemimplementation进行testCompile 使用debugImplementation进行debugCompile androidTestCompile与androidTestImplementation compileOnly仍然有效。它是在3.0中添加的,用于替换提供的和不编译的。(当Gradle没有为该用例提供配置名称时,就引入了该用例,并以Maven提供的作用域命名。)

这是谷歌在IO17大会上宣布的Android Gradle插件3.0的突破性变化之一。

compile配置现在已弃用,应该由实现或api取代

来自Gradle文档:

dependencies { api("commons-httpclient:commons-httpclient:3.1") implementation("org.apache.commons:commons-lang3:3.5") } Dependencies appearing in the api configurations will be transitively exposed to consumers of the library, and as such will appear on the compile classpath of consumers. Dependencies found in the implementation configuration will, on the other hand, not be exposed to consumers, and therefore not leak into the consumers' compile classpath. This comes with several benefits: dependencies do not leak into the compile classpath of consumers anymore, so you will never accidentally depend on a transitive dependency faster compilation thanks to reduced classpath size less recompilations when implementation dependencies change: consumers would not need to be recompiled cleaner publishing: when used in conjunction with the new maven-publish plugin, Java libraries produce POM files that distinguish exactly between what is required to compile against the library and what is required to use the library at runtime (in other words, don't mix what is needed to compile the library itself and what is needed to compile against the library). The compile configuration still exists, but should not be used as it will not offer the guarantees that the api and implementation configurations provide.


注意:如果你只在你的app模块中使用一个库——通常情况下——你不会注意到任何区别。 只有当您有一个相互依赖的模块的复杂项目,或者您正在创建一个库时,您才会看到区别。

其他回答

Gradle依赖项配置

Gradle 3.0引入了以下变化:

compile -> api api keyword is the same as deprecated compile which expose this dependency for all levels compile -> implementation Is preferable way because has some advantages. implementation expose dependency only for one level up at build time (the dependency is available at runtime). As a result you have a faster build(no need to recompile consumers which are higher then 1 level up) provided -> compileOnly This dependency is available only in compile time(the dependency is not available at runtime). This dependency can not be transitive and be .aar. It can be used with compile time annotation processor[About] and allows you to reduce a final output file compile -> annotationProcessor Very similar to compileOnly but also guarantees that transitive dependency are not visible for consumer apk -> runtimeOnly Dependency is not available in compile time but available at runtime.

[POM依赖类型]

博士tl;

只是替换:

使用实现(如果你不需要传递性)或API(如果你需要传递性)编译 使用testimplemimplementation进行testCompile 使用debugImplementation进行debugCompile androidTestCompile与androidTestImplementation compileOnly仍然有效。它是在3.0中添加的,用于替换提供的和不编译的。(当Gradle没有为该用例提供配置名称时,就引入了该用例,并以Maven提供的作用域命名。)

这是谷歌在IO17大会上宣布的Android Gradle插件3.0的突破性变化之一。

compile配置现在已弃用,应该由实现或api取代

来自Gradle文档:

dependencies { api("commons-httpclient:commons-httpclient:3.1") implementation("org.apache.commons:commons-lang3:3.5") } Dependencies appearing in the api configurations will be transitively exposed to consumers of the library, and as such will appear on the compile classpath of consumers. Dependencies found in the implementation configuration will, on the other hand, not be exposed to consumers, and therefore not leak into the consumers' compile classpath. This comes with several benefits: dependencies do not leak into the compile classpath of consumers anymore, so you will never accidentally depend on a transitive dependency faster compilation thanks to reduced classpath size less recompilations when implementation dependencies change: consumers would not need to be recompiled cleaner publishing: when used in conjunction with the new maven-publish plugin, Java libraries produce POM files that distinguish exactly between what is required to compile against the library and what is required to use the library at runtime (in other words, don't mix what is needed to compile the library itself and what is needed to compile against the library). The compile configuration still exists, but should not be used as it will not offer the guarantees that the api and implementation configurations provide.


注意:如果你只在你的app模块中使用一个库——通常情况下——你不会注意到任何区别。 只有当您有一个相互依赖的模块的复杂项目,或者您正在创建一个库时,您才会看到区别。

当你在gradle项目中声明一个依赖项时 代码库+它的依赖关系(声明为api)可以被gradle项目的消费者使用。

让我们举个例子

我们有一级,二级,三级gradle项目。

Level 1使用Level 2。Level 2使用Level 3。

一级<-二级<-三级

使用API和实现,我们可以控制是否应该将级别3的类公开到级别1。

这如何使构建更快:

关卡3的任何变化。不需要重新编译级别1。 特别是在开发过程中,节省时间。

其他答案解释了这种差异。

只要确保对于Kotlin DSL (build.gradle.kts),函数应该有圆括号,它们的字符串参数应该用双引号括起来,而不是单引号:

Groovy (build.gradle) 实现“com.android.support: appcompat-v7:25.0.0” testImplementation“junit: junit: 4.12” 芬兰湾的科特林(build.gradle.kts) 实现(“com.android.support: appcompat-v7:25.0.0”) testImplementation(“junit: junit: 4.12”)

简单的解决方案:

更好的方法是用实现依赖替换所有编译依赖。只有在泄露模块接口时,才应该使用api。这应该会减少大量的重新编译。

 dependencies {
         implementation fileTree(dir: 'libs', include: ['*.jar'])
 
         implementation 'com.android.support:appcompat-v7:25.4.0'
         implementation 'com.android.support.constraint:constraint-layout:1.0.2'
         // …
 
         testImplementation 'junit:junit:4.12'
         androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
             exclude group: 'com.android.support', module: 'support-annotations'
         })
 }

解释:

在Android Gradle插件3.0之前:我们遇到了一个大问题,即一个代码更改导致所有模块被重新编译。造成这种情况的根本原因是Gradle不知道你是否通过另一个模块泄露了一个模块的接口。

在Android Gradle插件3.0之后:最新的Android Gradle插件现在要求你显式定义是否泄露了模块的接口。在此基础上,它可以对应该重新编译的内容做出正确的选择。

因此,compile依赖项已被弃用,并被两个新的依赖项所取代:

Api:你通过你自己的接口泄露了这个模块的接口,这意味着和旧的编译依赖完全一样 实现:你只在内部使用这个模块,不会通过你的接口泄露它

所以现在你可以显式地告诉Gradle重新编译一个模块,如果使用的模块的接口改变与否。

由Jeroen Mols博客提供