There are a few dependency-related concepts that are interesting to understand, even if you might not need to use them today. One of them is the concept of configurations, which explains the compile
keyword that we have been using for dependencies throughout this chapter.
Sometimes you might have to work with an SDK that is only present on certain devices, like a Bluetooth SDK from a specific vendor, for example. In order to be able to compile the code, you need to add the SDK to your compile classpath. You do not need to include the SDK in your APK though, because it is already on the device. This is where dependency configurations come in.
Gradle groups dependencies into configurations, which are just named sets of files. These are the standard configurations for an Android app or library:
compile
apk
provided
testCompile
androidTestCompile
The compile
configuration is the default one and contains all dependencies required to compile the main application. Everything in this configuration is not only added to the classpath, but also to the generated APK.
The dependencies in the apk
configuration will only be added to the package, and are not added to the compilation classpath. The provided
configuration does the exact opposite, and its dependencies will not be packaged. These two configurations only take JAR dependencies. Trying to add library projects to them will result in an error.
Finally, the testCompile
and androidTestCompile
configurations add extra libraries specifically for testing. These configurations are used when running test-related tasks, which can be useful when adding a testing framework such as JUnit or Espresso. You only want these frameworks to be present in the test APK, not in the release APK.
Besides those standard configurations, the Android plugin also generates configurations for every build variant, making it possible to add dependencies to configurations such as debugCompile
, releaseProvided
, and so on. This can be useful if you want to add a logging framework to only your debug builds, for example. You can find more information on this in Chapter 4, Creating Build Variants.
Versioning is an important aspect of dependency management. Dependencies added to repositories such as JCenter are assumed to follow a set of rules for versioning, called semantic versioning. With semantic versioning, a version number always has the format major.minor.patch
, and the numbers are incremented according to the following rules:
In some situations, you might want to get the latest version of a dependency every time you build your app or library. The best way to accomplish this is by using dynamic versions. There are several ways to apply dynamic versions, here are some examples:
dependencies { compile 'com.android.support:support-v4:22.2.+' compile 'com.android.support:appcompat-v7:22.2+' compile 'com.android.support:recyclerview-v7:+' }
In the first line, we tell Gradle to get the latest patch release. In line two, we specify that we want to get every new minor version, and it has to be at least minor version 2. In the last line, we tell Gradle always to get the newest version of the library.
You should be careful with using dynamic versions. If you allow Gradle to pick up the latest version, it might pick up a dependency version that is unstable, causing the build to break. Even worse, you could end up with different versions of a dependency on the build server and on your personal machine, causing your application's behavior to be inconsistent.
Android Studio will warn you about the possible problems with dynamic versions when you try to use it in your build file, as you can see in the following screenshot: