Gradle Structure and Tasks in Android Studio, Let’s Dig Deeper!

Ahmed Adel
EGDroid
Published in
7 min readAug 23, 2018
Before starting working with the project, let’s review its structure in the Project pane in Android Studio.

Gradle Structure in Android Studio

Pay attention to the files with the green Gradle icon and .gradle extension. These files are generated by Android Studio automatically during project creation. They are responsible for the processing of your project’s build. They contain the necessary info about the project structure, library dependencies, library versions, and the app versions you’ll get as a result of the build process.

I. Project-level build.gradle :

Find the build.gradle file in the root directory of the project. It’s called a top-level (project-level) build.gradle file. It contains the settings which are applied to all modules of the project.

// 1
buildscript {
ext.kotlin_version = '1.2.50'
// 2
repositories {
google()
jcenter()
}
// 3
dependencies {
classpath 'com.android.tools.build:gradle:3.1.4'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
// 4
allprojects {
repositories {
google()
jcenter()
}
}

Here’s what’s going on, step by step:

  1. In the buildscript block you define settings needed to perform your project building.
  2. In the repositories block you add names of the repositories that Gradle should search for the libraries you use.
  3. The dependencies block contains necessary plugin dependencies, in this case, the Gradle and Kotlin plugins. DO NOT put your module dependencies in this block.
  4. The structure of the allprojects block is similar to the buildscript block, but here you define repositories for all of your modules, not for Gradle itself. Usually, you don’t define the dependencies section for allprojects. The dependencies for each module are different and should reside in the module-level build.gradle.

II. Module-level build.gradle

Now go to the build.gradle file in the app module directory. It contains dependencies (libraries which a module relies on), and instructions for the build process. Each module defines its own build.gradle file.

// 1
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
// 2
android {
// 3
compileSdkVersion 27
// 4
buildToolsVersion "27.0.3"
// 5
defaultConfig {
// 6
applicationId "com.ahmedadelsaid.gradleexample"
// 7
minSdkVersion 21
// 8
targetSdkVersion 27
// 9
versionCode 1
// 10
versionName "1.0"
}
}
// 11
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
}

The code above does the following:

  1. Specifies a list of plugins needed to build the module. The com.android.application plugin is necessary in order to set up the android-specific settings of the build process. Here you can also use com.android.library it if you’re creating a library module. The kotlin-android and kotlin-android-extensions plugins allow you to use the Kotlin language and the Kotlin Android Extensions in your module.
  2. In the android block you place all platform-specific options of the module.
  3. The compileSdkVersion option indicates the API level your app will be compiled with. In other words, you cannot use features from an API higher than this value. Here, you’ve set the value to use APIs from Android Oreo.
  4. The buildToolsVersion option indicates the version of the compiler. From Gradle plugin 3.0.0 onward, this field is optional. If it is not specified, the Android SDK uses the most recent downloaded version of the Build Tools.
  5. The defaultConfig block contains options that will be applied to all build versions (e.g., debug, release, etc) of your app by default.
  6. The applicationId is the identifier of your app. It should be unique so as to successfully publish or update your app on Google Play Store.
  7. In order to set the lowest API level supported, use minSdkVersion. Your app will not be available in the Play Store for the devices running on lower API levels.
  8. The targetSdkVersion parameter defines the maximum API level your app has been tested on. That is to say, you’re sure your app works properly on the devices with this SDK version, and it doesn’t require any backward compatibility behaviors. The best approach is to thoroughly test an app using the latest API, keeping your targetSdkVersion value equal to compileSdkVersion.
  9. versionCode is a numeric value for the app version.
  10. versionName is a user-friendly string for the app version.
  11. The dependencies block contains all dependencies needed for this module. Later in this blog, you’ll find out more about managing your project’s dependencies.

III. Finally, settings.gradle

We will move to the settings.gradle file in the root directory. Its contents should look as follows:

include ':app'

In this file, you should define all of your project’s modules by name. Here we have only one module — app. In a large, multi-module project, this file can have a much longer list.

Gradle Tasks in Android Studio!

To execute Gradle commands, you can use both the command line and Android Studio. It’s better to start from the former one to get acquainted more deeply about what’s going on. So, how can you start working with Gradle commands? Pretty easy — use gradlew.

gradlew is the Gradle Wrapper. You don’t need to worry about installation Gradle on your computer — the wrapper will do that for you. Even more, it will allow you to have different projects built with various versions of Gradle.

Open your command line and move to the root directory of the starter project.

gradlew tasks

After that, execute the following command:

./gradlew tasks

You’ll see a list containing all available tasks:

> Task :tasks------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
Android tasks
-------------
androidDependencies - Displays the Android dependencies of the project.
signingReport - Displays the signing info for each variant.
sourceSets - Prints out all the source sets defined in this project.
Build tasks
-----------
assemble - Assembles all variants of all applications and secondary packages.
assembleAndroidTest - Assembles all the Test applications.
assembleDebug - Assembles all Debug builds.
assembleRelease - Assembles all Release builds.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
clean - Deletes the build directory.
cleanBuildCache - Deletes the build cache directory.
compileDebugAndroidTestSources
compileDebugSources
compileDebugUnitTestSources
compileReleaseSources
compileReleaseUnitTestSources
mockableAndroidJar - Creates a version of android.jar that's suitable for unit tests.
Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.
Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'Android Projects'.
components - Displays the components produced by root project 'Android Projects'. [incubating]
dependencies - Displays all dependencies declared in root project 'Android Projects'.
dependencyInsight - Displays the insight into a specific dependency in root project 'Android Projects'.
dependentComponents - Displays the dependent components of components in root project 'Android Projects'. [incubating]
help - Displays a help message.
model - Displays the configuration model of root project 'Android Projects'. [incubating]
projects - Displays the sub-projects of root project 'Android Projects'.
properties - Displays the properties of root project 'Android Projects'.
tasks - Displays the tasks runnable from root project 'Android Projects' (some of the displayed tasks may belong to subprojects).
Install tasks
-------------
installDebug - Installs the Debug build.
installDebugAndroidTest - Installs the android (on device) tests for the Debug build.
uninstallAll - Uninstall all applications.
uninstallDebug - Uninstalls the Debug build.
uninstallDebugAndroidTest - Uninstalls the android (on device) tests for the Debug build.
uninstallRelease - Uninstalls the Release build.
Verification tasks
------------------
check - Runs all checks.
connectedAndroidTest - Installs and runs instrumentation tests for all flavors on connected devices.
connectedCheck - Runs all device checks on currently connected devices.
connectedDebugAndroidTest - Installs and runs the tests for debug on connected devices.
deviceAndroidTest - Installs and runs instrumentation tests using all Device Providers.
deviceCheck - Runs all device checks using Device Providers and Test Servers.
lint - Runs lint on all variants.
lintDebug - Runs lint on the Debug build.
lintRelease - Runs lint on the Release build.
lintVitalRelease - Runs lint on just the fatal issues in the release build.
test - Run unit tests for all variants.
testDebugUnitTest - Run unit tests for the debug build.
testReleaseUnitTest - Run unit tests for the release build.
To see all tasks and more detail, run gradlew tasks --allTo see more detail about a task, run gradlew help --task <task>

These commands exist to help you with tasks like project initialization, building, testing, and analyzing. If you forget a specific command, just execute ./gradlew tasks it to refresh your memory.

gradlew assemble

Now skim the list of commands again, and find commands starting with assembling under the Build tasks section. Run the first command:

./gradlew assemble

Below is the output of executing this command:

> Task :app:compileDebugKotlin
Using kotlin incremental compilation
> Task :app:compileReleaseKotlin
Using kotlin incremental compilation
BUILD SUCCESSFUL in 1m 45s
53 actionable tasks: 40 executed, 13 up-to-date

From the output, it’s apparent that Gradle compiled two versions of the app debug and release. Verify this by changing to the build output directory:

cd app/build/outputs/apk/

gradlew lint

The lint command, and any commands which start with lint, analyze the whole project looking for various mistakes, typos, or vulnerabilities. The first command will find all the issues in a project with both critical and minor severity.

You’ll get the output with the count of issues found:

> Task :app:lint
Ran lint on variant debug: 3 issues found
Ran lint on variant release: 3 issues found
Wrote HTML report to file:///Users/ahmedadel/Downloads/Medium%20Blogs/Android%20Projects/app/build/reports/lint-results.html
Wrote XML report to file:///Users/ahmedadel/Downloads/Medium%20Blogs/Android%20Projects/app/build/reports/lint-results.xml
BUILD SUCCESSFUL in 27s
32 actionable tasks: 1 executed, 31 up-to-date

Review the report by typing the following on Mac:

open app/build/reports/lint-results.html

or on Linux:

xdg-open app/build/reports/lint-results.html

You can inspect all the issues found with code snippets and an expanded description of a possible solution.

However, don’t focus too much on all of these issues — pay attention to the critical ones and fix them immediately. Minor issues shouldn’t necessarily warrant a refactoring, depending upon your teams' guidelines and processes.

--

--

Ahmed Adel
EGDroid

Senior Software Engineer @ Zendesk. Co-Founder & Mentor @ EGDroid. Usually, I do Android 📱Photography 📸 and Football ⚽