在更新到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'

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


当前回答

从版本5.6.3开始,Gradle文档提供了简单的经验规则来识别旧的编译依赖项(或新的依赖项)是否应该用一个实现或api依赖项替换:

Prefer the implementation configuration over api when possible This keeps the dependencies off of the consumer’s compilation classpath. In addition, the consumers will immediately fail to compile if any implementation types accidentally leak into the public API. So when should you use the api configuration? An API dependency is one that contains at least one type that is exposed in the library binary interface, often referred to as its ABI (Application Binary Interface). This includes, but is not limited to: types used in super classes or interfaces types used in public method parameters, including generic parameter types (where public is something that is visible to compilers. I.e. , public, protected and package private members in the Java world) types used in public fields public annotation types By contrast, any type that is used in the following list is irrelevant to the ABI, and therefore should be declared as an implementation dependency: types exclusively used in method bodies types exclusively used in private members types exclusively found in internal classes (future versions of Gradle will let you declare which packages belong to the public API)

其他回答

这个答案将演示项目中的实现、api和编译之间的区别。


假设我有一个有三个Gradle模块的项目:

app (Android应用程序) myandroidlibrary(一个Android库) myjavalibrary(一个Java库)

应用程序有myandroidlibrary作为依赖项。Myandroidlibrary有myjavlibrary作为依赖项。

myjavlibrary有一个MySecret类

public class MySecret {

    public static String getSecret() {
        return "Money";
    }
}

myandroidlibrary中有MyAndroidComponent类,用于操作MySecret类的值。

public class MyAndroidComponent {

    private static String component = MySecret.getSecret();

    public static String getComponent() {
        return "My component: " + component;
    }    
}

最后,app只对myandroidlibrary的值感兴趣

TextView tvHelloWorld = findViewById(R.id.tv_hello_world);
tvHelloWorld.setText(MyAndroidComponent.getComponent());

现在,让我们谈谈依赖关系……

应用需要消耗:myandroidlibrary,所以在应用构建中。Gradle使用实现。

(注意:你也可以使用api/compile。但请稍等片刻。)

dependencies {
    implementation project(':myandroidlibrary')      
}

你认为myandroidlibrary构建了什么?Gradle应该是什么样子?我们应该使用哪个作用域?

我们有三个选择:

dependencies {
    // Option #1
    implementation project(':myjavalibrary') 
    // Option #2
    compile project(':myjavalibrary')      
    // Option #3
    api project(':myjavalibrary')           
}

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

编译或Api(选项#2或#3)

如果你使用的是编译器或者api。我们的Android应用现在可以访问myandroidcomponent依赖,这是一个MySecret类。

TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can access MySecret
textView.setText(MySecret.getSecret());

实现(选项#1)

如果您正在使用实现配置,MySecret将不会公开。

TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can NOT access MySecret
textView.setText(MySecret.getSecret()); // Won't even compile

那么,应该选择哪种配置呢?那要看你的要求了。

如果你想公开依赖关系,请使用api或compile。

如果你不想公开依赖关系(隐藏你的内部模块),那么使用实现。

注意:

这只是Gradle配置的一个要点,参见表49.1。Java库插件-用于声明依赖关系的配置,以获得更详细的解释。

这个答案的示例项目可以在https://github.com/aldoKelvianto/ImplementationVsCompile上找到

在继续之前先做一些笔记;compile已弃用,并且文档声明您应该使用implementation,因为compile将在Gradle 7.0版本中被删除。 如果你使用——warning-mode运行Gradle构建,你会看到以下消息:

对于依赖项声明,compile配置已弃用。这将失败,并在Gradle 7.0中出现错误。请改用实现配置。


只要看看帮助页上的图片,就很有意义了。

你有蓝色框compileClasspath和runtimeClassPath。 当运行gradle build时,compileClasspath是成功构建所必需的。编译时将出现在类路径上的库将是在gradle构建中使用compileOnly或implementation配置的所有库。

然后我们有runtimeClasspath,这些都是使用实现或runtimeOnly添加的包。所有这些库都将添加到您部署到服务器上的最终构建文件中。

如图所示,如果您希望一个库既用于编译,又希望将它添加到构建文件中,那么应该使用实现。

runtimeOnly的示例可以是数据库驱动程序。 compileOnly的一个例子可以是servlet-api。 实现的一个例子是spring-core。

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

只要确保对于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取代。

你可以在API和实现分离部分阅读文档。

简短的部分是

The key difference between the standard Java plugin and the Java Library plugin is that the latter introduces the concept of an API exposed to consumers. A library is a Java component meant to be consumed by other components. It's a very common use case in multi-project builds, but also as soon as you have external dependencies. The plugin exposes two configurations that can be used to declare dependencies: api and implementation. The api configuration should be used to declare dependencies which are exported by the library API, whereas the implementation configuration should be used to declare dependencies which are internal to the component.

进一步的解释请参考这张图片。

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

让我们举个例子

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

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

一级<-二级<-三级

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

这如何使构建更快:

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