After updating to Android Studio 3.0 and creating a new project, I noticed that in build.gradle
there is a new way to add new dependencies instead of compile
there is implementation
and instead of testCompile
there is testImplementation
.
Example:
implementation 'com.android.support:appcompat-v7:25.0.0' testImplementation 'junit:junit:4.12'
instead of
compile 'com.android.support:appcompat-v7:25.0.0' testCompile 'junit:junit:4.12'
What's the difference between them and what should I be using?
Fortunately, the implementation dependency configuration provides the same functionality as compile. You should always use implementation rather than compile for dependencies, as compile is now deprecated or removed in the case of Gradle 7+.
Compile − The dependencies required to compile the production source of the project. Runtime − The dependencies required by the production classes at runtime. By default, it also includes the compile time dependencies. Test Compile − The dependencies required to compile the test source of the project.
compile is the group of dependencies you need to build your application while testCompile is a group of dependencies that you need only for testing. This specifies that hibernate-core is needed to build your code but junit (a testing framework) is needed just for testing.
A Dependency represents a dependency on the artifacts from a particular source. A source can be an Ivy module, a Maven POM, another Gradle project, a collection of Files, etc... A source can have zero or more artifacts.
Obviously you can do the same thing if you have local module libraries Gradle compile keyword was deprecated in favor of the api and implementation keywords to configure dependencies. Using api is the equivalent of using the deprecated compile, so if you replace all compile with api everything will works as always.
Let’s find out with the two simple rules described in this article. Quick answer: use the implementation configuration and never compile, BUT read on for some important caveats When declaring Java dependencies in Gradle you provide a dependency configuration to which to assign your dependency. e.g.
This plugin adds an additional api configuration, on top of the already mentioned implementation configuration. For any Gradle projects consuming a project built using the Java Library Plugin, the following applies: any api dependencies declared in the consumed library will appear on the compile and runtime classpaths of the consumer library
Using api is the equivalent of using the deprecated compile, so if you replace all compile with api everything will works as always. To understand the implementation keyword consider the following example. Suppose you have a library called MyLibrary that internally uses another library called InternalLibrary. Something like this:
tl;dr
Just replace:
compile
with implementation
(if you don't need transitivity) or api
(if you need transitivity)testCompile
with testImplementation
debugCompile
with debugImplementation
androidTestCompile
with androidTestImplementation
compileOnly
is still valid. It was added in 3.0 to replace provided and not compile. (provided
introduced when Gradle didn't have a configuration name for that use-case and named it after Maven's provided scope.)It is one of the breaking changes coming with Android Gradle plugin 3.0 that Google announced at IO17.
The compile
configuration is now deprecated and should be replaced by implementation
or api
From the Gradle documentation:
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.
Note: if you are only using a library in your app module -the common case- you won't notice any difference.
you will only see the difference if you have a complex project with modules depending on each other, or you are creating a library.
This answer will demonstrate the difference between implementation
, api
, and compile
on a project.
Let's say I have a project with three Gradle modules:
app
has myandroidlibrary
as dependencies. myandroidlibrary
has myjavalibrary
as dependencies.
myjavalibrary
has a MySecret
class
public class MySecret { public static String getSecret() { return "Money"; } }
myandroidlibrary
has MyAndroidComponent
class that manipulate value from MySecret
class.
public class MyAndroidComponent { private static String component = MySecret.getSecret(); public static String getComponent() { return "My component: " + component; } }
Lastly, app
is only interested in the value from myandroidlibrary
TextView tvHelloWorld = findViewById(R.id.tv_hello_world); tvHelloWorld.setText(MyAndroidComponent.getComponent());
Now, let's talk about dependencies...
app
need to consume :myandroidlibrary
, so in app
build.gradle use implementation
.
(Note: You can use api/compile too. But hold that thought for a moment.)
dependencies { implementation project(':myandroidlibrary') }
What do you think myandroidlibrary
build.gradle should look like? Which scope we should use?
We have three options:
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?
Compile or Api (option #2 or #3)
If you're using compile
or api
. Our Android Application now able to access myandroidcomponent
dependency, which is a MySecret
class.
TextView textView = findViewById(R.id.text_view); textView.setText(MyAndroidComponent.getComponent()); // You can access MySecret textView.setText(MySecret.getSecret());
Implementation (option #1)
If you're using implementation
configuration, MySecret
is not exposed.
TextView textView = findViewById(R.id.text_view); textView.setText(MyAndroidComponent.getComponent()); // You can NOT access MySecret textView.setText(MySecret.getSecret()); // Won't even compile
So, which configuration you should choose? That really depends on your requirement.
If you want to expose dependencies use api
or compile
.
If you don't want to expose dependencies (hiding your internal module) then use implementation
.
Note:
This is just a gist of Gradle configurations, refer to Table 49.1. Java Library plugin - configurations used to declare dependencies for more detailed explanation.
The sample project for this answer is available on https://github.com/aldoKelvianto/ImplementationVsCompile
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With