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?
The brief difference in layman's term is:
read the answer by @aldok for a comprehensive example.
This answer will demonstrate the difference between
implementation
,api
, andcompile
on a project. Let's say I have a project with three Gradle modules:app
hasmyandroidlibrary
as dependencies.myandroidlibrary
hasmyjavalibrary
as dependencies.myjavalibrary
has aMySecret
classmyandroidlibrary
hasMyAndroidComponent
class that manipulate value fromMySecret
class.Lastly,
app
is only interested in the value frommyandroidlibrary
Now, let's talk about dependencies on
app
build.gradle. It's simple and intuitive.app
need to use:myandroidlibrary
But, what do you think
myandroidlibrary
build.gradle should look like? Which scope we should use?We have three options:
Compile and Api
If you're using
compile
andapi
. Our Android Application now able to accessmyandroidcomponent
dependency, which is aMySecret
class.Implementation
If you're using
implementation
configuration,MySecret
is not exposed.So, which configuration you should choose? That really depends on your requirement.
If you want to expose dependencies use
api
orcompile
, if you don't want to expose dependencies (hiding your internal module) then useimplementation
.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
tl;dr
Just replace:
compile
withimplementation
testCompile
withtestImplementation
debugCompile
withdebugImplementation
androidTestCompile
withandroidTestImplementation
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 Gradle 3.0 that Google announced at IO17.
The
compile
configuration is now deprecated and should be replaced byimplementation
orapi
From the Gradle documentation:
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.
Compile
configuration was deprecated and should be replaced byimplementation
orapi
.You can read the docs at https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation.
The brief part being-
For further explanation refer to this image.
Brief Solution:
The better approach is to replace all
compile
dependencies withimplementation
dependencies. And only where you leak a module’s interface, you should useapi
. That should cause a lot less recompilation.Explain More:
Before Android Gradle plugin 3.0: we had a big problem which is one code change causes all modules to be recompiled. The root cause for this is that Gradle doesn’t know if you leak the interface of a module through another one or not.
After Android Gradle plugin 3.0: the latest Android Gradle plugin now requires you to explicitly define if you leak a module’s interface. Based on that it can make the right choice on what it should recompile.
As such the
compile
dependency has been deprecated and replaced by two new ones:api
: you leak the interface of this module through your own interface, meaning exactly the same as the oldcompile
dependencyimplementation
: you only use this module internally and does not leak it through your interfaceSo now you can explicitly tell Gradle to recompile a module if the interface of a used module changes or not.
Courtesy of Jeroen Mols blog