api 中的实现和 Gradle 中的编译有什么区别?
What's the difference between implementation, api and compile in Gradle?
更新到 Android Studio 3.0 并创建新项目后,我注意到 build.gradle
中有一种添加新依赖项的新方法,而不是 compile
implementation
而不是 testCompile
有 testImplementation
.
示例:
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;dr
只需替换:
compile
和 implementation
(如果您不需要传递性)或 api
(如果您需要传递性)
testCompile
与 testImplementation
debugCompile
与 debugImplementation
androidTestCompile
与 androidTestImplementation
compileOnly
仍然有效。它是在 3.0 中添加的,用于替换提供的而不是编译的。 (provided
在 Gradle 没有该用例的配置名称并根据 Maven 提供的范围命名时引入。)
这是 Android Gradle plugin 3.0 that Google announced at IO17 带来的重大变化之一。
compile
配置为now deprecated,应替换为implementation
或api
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.
注意:如果您仅在应用程序模块中使用库(常见情况),您不会注意到任何差异。
如果您有一个模块相互依赖的复杂项目,或者您正在创建一个库,您只会看到差异。
Compile
配置已弃用,应替换为 implementation
或 api
。
您可以在 API and implementation separation 部分阅读文档。
简短的部分是-
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.
如需进一步说明,请参阅此图片。
简要解决方案:
更好的方法是将所有 compile
依赖项替换为 implementation
依赖项。只有在泄漏模块接口的地方,才应该使用 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
:你通过自己的接口泄露了这个模块的接口,意思和老的compile
依赖完全一样
implementation
: 你只在内部使用这个模块,不会通过你的接口泄露它
所以现在你可以明确地告诉 Gradle 如果使用的模块的接口发生变化,则重新编译模块。
感谢 Jeroen Mols 博客
此答案将展示 implementation
、api
和 compile
在项目上的区别。
假设我有一个包含三个 Gradle 模块的项目:
- 应用程序(Android 应用程序)
- myandroidlibrary(一个 Android 库)
- myjavalibrary(一个 Java 库)
app
具有 myandroidlibrary
作为依赖项。 myandroidlibrary
具有 myjavalibrary
作为依赖项。
myjavalibrary
有一个 MySecret
class
public class MySecret {
public static String getSecret() {
return "Money";
}
}
myandroidlibrary
有 MyAndroidComponent
class 操纵来自 MySecret
class.
的值
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());
现在,我们来谈谈依赖关系...
app
需要消耗:myandroidlibrary
,所以在app
build.gradle中使用implementation
.
(注意:你也可以使用api/compile。但请稍等片刻。)
dependencies {
implementation project(':myandroidlibrary')
}
你认为 myandroidlibrary
build.gradle 应该是什么样子?我们应该使用哪个范围?
我们有三种选择:
dependencies {
// Option #1
implementation project(':myjavalibrary')
// Option #2
compile project(':myjavalibrary')
// Option #3
api project(':myjavalibrary')
}
What's the difference between them and what should I be using?
编译或Api(选项#2 或#3)
如果您使用的是 compile
或 api
。我们的 Android 应用程序现在可以访问 myandroidcomponent
依赖项,这是一个 MySecret
class.
TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can access MySecret
textView.setText(MySecret.getSecret());
实施(选项 #1)
如果您使用的是 implementation
配置,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
。
如果你不想暴露依赖关系(隐藏你的内部模块)那么使用implementation
.
注:
这只是Gradle配置的要点,更详细的解释请参考Table 49.1. Java Library plugin - configurations used to declare dependencies。
此答案的示例项目可在 https://github.com/aldoKelvianto/ImplementationVsCompile
上找到
通俗的说就是:
- 如果您正在开发一个接口或模块,该接口或模块通过公开指定依赖项的成员来为其他模块提供支持,您应该使用 'api'。
- 如果您制作的应用程序或模块将在内部实现或使用规定的依赖项,请使用 'implementation'。
- 'compile' 与 'api' 的工作方式相同,但是,如果您只是实施或使用任何库,'implementation' 会更好地工作并节省资源。
阅读@aldok 的回答以获得综合示例。
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| Name | Role | Consumable? | Resolveable? | Description |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| api | Declaring | no | no | This is where you should declare |
| | API | | | dependencies which are transitively |
| | dependencies | | | exported to consumers, for compile. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| implementation | Declaring | no | no | This is where you should |
| | implementation | | | declare dependencies which are |
| | dependencies | | | purely internal and not |
| | | | | meant to be exposed to consumers. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| compileOnly | Declaring compile | yes | yes | This is where you should |
| | only | | | declare dependencies |
| | dependencies | | | which are only required |
| | | | | at compile time, but should |
| | | | | not leak into the runtime. |
| | | | | This typically includes dependencies |
| | | | | which are shaded when found at runtime. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| runtimeOnly | Declaring | no | no | This is where you should |
| | runtime | | | declare dependencies which |
| | dependencies | | | are only required at runtime, |
| | | | | and not at compile time. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testImplementation | Test dependencies | no | no | This is where you |
| | | | | should declare dependencies |
| | | | | which are used to compile tests. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testCompileOnly | Declaring test | yes | yes | This is where you should |
| | compile only | | | declare dependencies |
| | dependencies | | | which are only required |
| | | | | at test compile time, |
| | | | | but should not leak into the runtime. |
| | | | | This typically includes dependencies |
| | | | | which are shaded when found at runtime. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testRuntimeOnly | Declaring test | no | no | This is where you should |
| | runtime dependencies | | | declare dependencies which |
| | | | | are only required at test |
| | | | | runtime, and not at test compile time. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
自版本 5.6.3 Gradle documentation 提供了简单的经验法则来确定旧 compile
依赖项(或新依赖项)是否应替换为 implementation
或 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)
Gradle依赖配置
Gradle 3.0
引入了下一个变化:
compile
-> api
api
关键字与 deprecated compile
相同,后者公开了所有级别的依赖关系
compile
-> implementation
是更可取的方式,因为它有一些优势。 implementation
仅在构建时公开 一级 的依赖项(依赖项在运行时可用)。因此,您的构建速度更快(无需重新编译高于 1 级的消费者)
provided
-> compileOnly
此依赖项仅在编译时可用(此依赖项在运行时不可用)。这种依赖不能传递并且是.aar
。它可以与编译时注释处理器[About]一起使用,并允许您减少最终输出文件
compile
-> annotationProcessor
与compileOnly
非常相似,但也保证传递依赖对消费者不可见
apk
-> runtimeOnly
依赖在编译时不可用,但在运行时可用。
[POM dependency type]
实现: 我们大多使用实现配置。它隐藏了模块对其使用者的内部依赖,以避免意外使用任何传递依赖,从而加快编译速度并减少重新编译。
api: 必须非常小心地使用,因为它会泄漏消费者的编译类路径,因此滥用 api 可能导致依赖污染。
compileOnly: 当我们在运行时不需要任何依赖时,因为 compileOnly 依赖不会成为最终构建的一部分。我们将获得更小的构建尺寸。
runtimeOnly: 当我们想要在运行时(在最终构建中)更改或交换库的行为时。
我创建了一个post with an in-depth understanding of each one with Working Example: source code
https://medium.com/@gauraw.negi/how-gradle-dependency-configurations-work-underhood-e934906752e5
继续之前的一些注意事项; compile 已弃用,文档说明您应该使用实现,因为 compile 将在 Gradle 7.0 版中删除。
如果您 运行 您的 Gradle 使用 --warning-mode all
构建,您将看到以下消息;
The compile configuration has been deprecated for dependency declaration. This will fail with an error in Gradle 7.0. Please use the implementation configuration instead.
仅通过查看帮助页面中的图像,就很有意义。
所以你有蓝框 compileClasspath
和 runtimeClassPath
。
compileClasspath
是在 运行 宁 gradle build
时成功构建所需的条件。编译时将出现在类路径中的库将是使用 compileOnly
或 implementation
.
在 gradle 构建中配置的所有库
然后我们有 runtimeClasspath
,这些都是您使用 implementation
或 runtimeOnly
添加的包。所有这些库都将添加到您在服务器上部署的最终构建文件中。
正如您在图中看到的那样,如果您希望一个库既用于编译又希望将其添加到构建文件中,则应使用 implementation
。
runtimeOnly
的例子可以是数据库驱动。
compileOnly
的一个例子可以是 servlet-api.
implementation
的例子可以是 spring-core.
当您在 gradle 项目中声明依赖项时
消费者 gradle 项目可以使用代码库及其依赖项(声明为 api)。
举个例子
我们有 1 级、2 级、3 级 gradle 个项目。
level 1使用level 2.level 2使用level 3.
级别 1 <- 级别 2 <- 级别 3
使用 api 和实现,我们可以控制级别 3 的 类 是否应该暴露给级别 1。
这如何使构建速度更快:
级别 3 中的任何更改。不需要重新编译级别 1。
特别是在开发中,节省时间。
其他答案解释了差异。
只要确保对于 Kotlin DSL (build.gradle.kts),函数应该有括号,并且它们的字符串参数用双引号而不是单引号括起来:
- Groovy (build.gradle)
implementation 'com.android.support:appcompat-v7:25.0.0'
testImplementation 'junit:junit:4.12'
- 科特林 (build.gradle.kts)
implementation("com.android.support:appcompat-v7:25.0.0")
testImplementation("junit:junit:4.12")
更新到 Android Studio 3.0 并创建新项目后,我注意到 build.gradle
中有一种添加新依赖项的新方法,而不是 compile
implementation
而不是 testCompile
有 testImplementation
.
示例:
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;dr
只需替换:
compile
和implementation
(如果您不需要传递性)或api
(如果您需要传递性)testCompile
与testImplementation
debugCompile
与debugImplementation
androidTestCompile
与androidTestImplementation
compileOnly
仍然有效。它是在 3.0 中添加的,用于替换提供的而不是编译的。 (provided
在 Gradle 没有该用例的配置名称并根据 Maven 提供的范围命名时引入。)
这是 Android Gradle plugin 3.0 that Google announced at IO17 带来的重大变化之一。
compile
配置为now deprecated,应替换为implementation
或api
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
andimplementation
configurations provide.
注意:如果您仅在应用程序模块中使用库(常见情况),您不会注意到任何差异。
如果您有一个模块相互依赖的复杂项目,或者您正在创建一个库,您只会看到差异。
Compile
配置已弃用,应替换为 implementation
或 api
。
您可以在 API and implementation separation 部分阅读文档。
简短的部分是-
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.
如需进一步说明,请参阅此图片。
简要解决方案:
更好的方法是将所有 compile
依赖项替换为 implementation
依赖项。只有在泄漏模块接口的地方,才应该使用 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
:你通过自己的接口泄露了这个模块的接口,意思和老的compile
依赖完全一样implementation
: 你只在内部使用这个模块,不会通过你的接口泄露它
所以现在你可以明确地告诉 Gradle 如果使用的模块的接口发生变化,则重新编译模块。
感谢 Jeroen Mols 博客
此答案将展示 implementation
、api
和 compile
在项目上的区别。
假设我有一个包含三个 Gradle 模块的项目:
- 应用程序(Android 应用程序)
- myandroidlibrary(一个 Android 库)
- myjavalibrary(一个 Java 库)
app
具有 myandroidlibrary
作为依赖项。 myandroidlibrary
具有 myjavalibrary
作为依赖项。
myjavalibrary
有一个 MySecret
class
public class MySecret {
public static String getSecret() {
return "Money";
}
}
myandroidlibrary
有 MyAndroidComponent
class 操纵来自 MySecret
class.
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());
现在,我们来谈谈依赖关系...
app
需要消耗:myandroidlibrary
,所以在app
build.gradle中使用implementation
.
(注意:你也可以使用api/compile。但请稍等片刻。)
dependencies {
implementation project(':myandroidlibrary')
}
你认为 myandroidlibrary
build.gradle 应该是什么样子?我们应该使用哪个范围?
我们有三种选择:
dependencies {
// Option #1
implementation project(':myjavalibrary')
// Option #2
compile project(':myjavalibrary')
// Option #3
api project(':myjavalibrary')
}
What's the difference between them and what should I be using?
编译或Api(选项#2 或#3)
如果您使用的是 compile
或 api
。我们的 Android 应用程序现在可以访问 myandroidcomponent
依赖项,这是一个 MySecret
class.
TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can access MySecret
textView.setText(MySecret.getSecret());
实施(选项 #1)
如果您使用的是 implementation
配置,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
。
如果你不想暴露依赖关系(隐藏你的内部模块)那么使用implementation
.
注:
这只是Gradle配置的要点,更详细的解释请参考Table 49.1. Java Library plugin - configurations used to declare dependencies。
此答案的示例项目可在 https://github.com/aldoKelvianto/ImplementationVsCompile
上找到通俗的说就是:
- 如果您正在开发一个接口或模块,该接口或模块通过公开指定依赖项的成员来为其他模块提供支持,您应该使用 'api'。
- 如果您制作的应用程序或模块将在内部实现或使用规定的依赖项,请使用 'implementation'。
- 'compile' 与 'api' 的工作方式相同,但是,如果您只是实施或使用任何库,'implementation' 会更好地工作并节省资源。
阅读@aldok 的回答以获得综合示例。
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| Name | Role | Consumable? | Resolveable? | Description |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| api | Declaring | no | no | This is where you should declare |
| | API | | | dependencies which are transitively |
| | dependencies | | | exported to consumers, for compile. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| implementation | Declaring | no | no | This is where you should |
| | implementation | | | declare dependencies which are |
| | dependencies | | | purely internal and not |
| | | | | meant to be exposed to consumers. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| compileOnly | Declaring compile | yes | yes | This is where you should |
| | only | | | declare dependencies |
| | dependencies | | | which are only required |
| | | | | at compile time, but should |
| | | | | not leak into the runtime. |
| | | | | This typically includes dependencies |
| | | | | which are shaded when found at runtime. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| runtimeOnly | Declaring | no | no | This is where you should |
| | runtime | | | declare dependencies which |
| | dependencies | | | are only required at runtime, |
| | | | | and not at compile time. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testImplementation | Test dependencies | no | no | This is where you |
| | | | | should declare dependencies |
| | | | | which are used to compile tests. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testCompileOnly | Declaring test | yes | yes | This is where you should |
| | compile only | | | declare dependencies |
| | dependencies | | | which are only required |
| | | | | at test compile time, |
| | | | | but should not leak into the runtime. |
| | | | | This typically includes dependencies |
| | | | | which are shaded when found at runtime. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testRuntimeOnly | Declaring test | no | no | This is where you should |
| | runtime dependencies | | | declare dependencies which |
| | | | | are only required at test |
| | | | | runtime, and not at test compile time. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
自版本 5.6.3 Gradle documentation 提供了简单的经验法则来确定旧 compile
依赖项(或新依赖项)是否应替换为 implementation
或 api
依赖:
- Prefer the
implementation
configuration overapi
when possibleThis 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)
Gradle依赖配置
Gradle 3.0
引入了下一个变化:
compile
->api
api
关键字与 deprecatedcompile
相同,后者公开了所有级别的依赖关系compile
->implementation
是更可取的方式,因为它有一些优势。
implementation
仅在构建时公开 一级 的依赖项(依赖项在运行时可用)。因此,您的构建速度更快(无需重新编译高于 1 级的消费者)provided
->compileOnly
此依赖项仅在编译时可用(此依赖项在运行时不可用)。这种依赖不能传递并且是
.aar
。它可以与编译时注释处理器[About]一起使用,并允许您减少最终输出文件compile
->annotationProcessor
与
compileOnly
非常相似,但也保证传递依赖对消费者不可见apk
->runtimeOnly
依赖在编译时不可用,但在运行时可用。
[POM dependency type]
实现: 我们大多使用实现配置。它隐藏了模块对其使用者的内部依赖,以避免意外使用任何传递依赖,从而加快编译速度并减少重新编译。
api: 必须非常小心地使用,因为它会泄漏消费者的编译类路径,因此滥用 api 可能导致依赖污染。
compileOnly: 当我们在运行时不需要任何依赖时,因为 compileOnly 依赖不会成为最终构建的一部分。我们将获得更小的构建尺寸。
runtimeOnly: 当我们想要在运行时(在最终构建中)更改或交换库的行为时。
我创建了一个post with an in-depth understanding of each one with Working Example: source code
https://medium.com/@gauraw.negi/how-gradle-dependency-configurations-work-underhood-e934906752e5
继续之前的一些注意事项; compile 已弃用,文档说明您应该使用实现,因为 compile 将在 Gradle 7.0 版中删除。
如果您 运行 您的 Gradle 使用 --warning-mode all
构建,您将看到以下消息;
The compile configuration has been deprecated for dependency declaration. This will fail with an error in Gradle 7.0. Please use the implementation configuration instead.
仅通过查看帮助页面中的图像,就很有意义。
所以你有蓝框 compileClasspath
和 runtimeClassPath
。
compileClasspath
是在 运行 宁 gradle build
时成功构建所需的条件。编译时将出现在类路径中的库将是使用 compileOnly
或 implementation
.
然后我们有 runtimeClasspath
,这些都是您使用 implementation
或 runtimeOnly
添加的包。所有这些库都将添加到您在服务器上部署的最终构建文件中。
正如您在图中看到的那样,如果您希望一个库既用于编译又希望将其添加到构建文件中,则应使用 implementation
。
runtimeOnly
的例子可以是数据库驱动。
compileOnly
的一个例子可以是 servlet-api.
implementation
的例子可以是 spring-core.
当您在 gradle 项目中声明依赖项时 消费者 gradle 项目可以使用代码库及其依赖项(声明为 api)。
举个例子
我们有 1 级、2 级、3 级 gradle 个项目。
level 1使用level 2.level 2使用level 3.
级别 1 <- 级别 2 <- 级别 3
使用 api 和实现,我们可以控制级别 3 的 类 是否应该暴露给级别 1。
这如何使构建速度更快:
级别 3 中的任何更改。不需要重新编译级别 1。 特别是在开发中,节省时间。
其他答案解释了差异。
只要确保对于 Kotlin DSL (build.gradle.kts),函数应该有括号,并且它们的字符串参数用双引号而不是单引号括起来:
- Groovy (build.gradle)
implementation 'com.android.support:appcompat-v7:25.0.0' testImplementation 'junit:junit:4.12'
- 科特林 (build.gradle.kts)
implementation("com.android.support:appcompat-v7:25.0.0") testImplementation("junit:junit:4.12")