Breaking Free from Android Studio: Harnessing the Full Potential of Gradle for Building and Running Projects Independently from Android Studio.

IO DevBlue
14 min readAug 7, 2023

Having a good understanding of the Gradle build system and utilizing it efficiently is one of the requirements of being a good native Android developer.

Gradle is a build system that is essential for native Android developers. It helps streamline the process of compiling and organizing code, resources and dependencies to create an Android application efficiently.

Abstract AI generated imagery of a build system

While Android Studio acts as an intermediary between Gradle and a developer providing a user-friendly interface to make the build and compile process simpler and easier, it can be resource-intensive and slow especially for developers working on low-memory setups. This can be a heavy setback to a developer or team’s work flow especially when handling complex multi-modular projects.

Android studio as an intermediary between a native developer and Gradle

With Android studio out of the way, a programmer’s setup can run Gradle tasks on the background and have more free memory to run other programs resulting in smoother multitasking. This is useful for setups running with low memory.

Direct usage of Gradle through command-line

Using this method, an Android developer can use Android studio for writing codes utilizing the code assistance, generation and analysis provided for the development process but can resort to running Gradle at the command-line to compile, install, run and debug Android applications.

I have personally used this workflow for developing Android applications and libraries especially multi-modular projects while running on a 4 GB RAM and 8 GB RAM setups which would take hours to build through Android studio but within few minutes via command-line.

This article would be covering the process of utilizing Gradle to build, compile, install and run Android applications without the assistance of Android studio.

This article is for:

  1. Native Android developers.
  2. React Native developers.
  3. Flutter developers.
  4. Java and Kotlin programmers.

Or anyone looking to understand command-line Gradle for Android projects.

Requirements:

  • A simple text editor.
  • Gradle build system (latest version can be gotten here)
  • Java Development Kit (latest version can be gotten here)
  • Terminal/Command-line interface.
  • Android Studio (optional). Latest version can be gotten here.

I will be using Gradle version 8.0 with JDK 17 along with Android studio Flamingo | 2022.2.1.

Locate your Gradle installation location

The default location is C:\Users\ (your-username)\.gradle

However, your Gradle location can be located elsewhere. For example, my Gradle is located at C:\Gradle as pictured below:

Custom Gradle installation folder
Custom Gradle installation folder

The reason for this preference is simply on the premise that folders and files named with a period prefix (/.gradle, .my_image.jpg etc.) should be hidden and also it is more preferable to have the Gradle installation in the root windows folder (C:\).

Have this in mind that the implication of choosing an alternate Gradle location is that command-line Gradle and Android studio would not be able to locate the default Gradle installation location and it would have to be manually keyed in.

For Android Studio, once for every project in the Settings:

Setting the custom location for the Gradle installation folder
Setting the custom location for the Gradle installation folder

For command-line Gradle, the installation location has to be keyed in every time Gradle is invoked. This would be showed later in the article.

Locate your Java Development Kit installation location

The default location for Java Development Kit is in C:\Program Files\Java.

If you have multiple versions of the Java Development Kit installed, you should select the latest or the most compatible JDK for your Android project.

As pictured below, the latest JDK version I have installed is version 18.0.1.1.

Default Java Development Kit installation folder
Default Java Development Kit installation folder

Which has the following content:

JDK 18.0.1.1 content
JDK 18.0.1.1 content

But as of August 2023 at the time of this publication, Java 18 is not supported fully as the default JDK for Android development and it is preferable to use the Jetbrains (jbr) JDK which is bundled along with Android studio which is located at the default location: C:\Program Files\Android\Android Studio\jbr as pictured below:

Android studio’s JetBrains JDK

This is the preferred Java JDK for Android projects. For Android studio Flamingo, JDK version 17 is bundled with the executable package.

For reference purposes, The Jetbrains (jbr) JDK can be selected as the default JDK for a project on Android studio as pictured below:

Setting the JDK in Android studio using JetBrains version

Configuring Gradle

Gradle needs to be configured in such a way that it can run faster, effectively and more efficiently when invoked. This is possible using these configurations below in gradle.properties:

org.gradle.jvmargs=-Xmx3584m -XX:MaxMetaspaceSize=3584m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.parallel=true
org.gradle.daemon=true
org.gradle.configureondemand=true
org.gradle.caching=true
org.gradle.unsafe.configuration-cache=true
org.gradle.warning.mode=none

NOTE: These settings are opinionated and it is required you have basic understanding of how each configuration functions and whether it applies to your project.

org.gradle.jvmargs: This configuration is used to specify Java Virtual Machine (JVM) arguments for Gradle’s build process. These arguments control how much memory Gradle can use and other JVM-specific settings. By configuring the above JVM arguments, the Gradle build process gains more memory allocation, efficient memory management and better handling of potential memory-related errors. The specific values provided (e.g., 3584 MB) can be adjusted based on the available system resources and the requirements of the Gradle projects being built. However, it’s crucial to strike a balance between allocating enough memory for the build tasks and not using an excessive amount that could cause issues or compete with other processes running on the system. Let’s break down the specific arguments in this configuration:

  • -Xmx3584m: This argument sets the maximum heap size for the JVM to 3584 megabytes (MB). It defines the maximum amount of memory that can be allocated to the Java heap which is where objects are stored during program execution. Increasing this value can help prevent OutOfMemoryError when dealing with large projects or resource-intensive tasks.
  • -XX:MaxMetaspaceSize=3584m: This argument sets the maximum size of the Metaspace which is the storage area for class metadata and reflection-related data in the JVM. Similar to the -Xmx argument, it also specifies a maximum size of 3584 MB for Metaspace.
  • -XX:+HeapDumpOnOutOfMemoryError: When this argument is included, the JVM will generate a heap dump file if an OutOfMemoryError occurs. A heap dump contains information about the memory usage of the program at the time of the error which can be useful for diagnosing memory-related issues.
  • -Dfile.encoding=UTF-8: This argument sets the default file encoding for the JVM to UTF-8. UTF-8 is a character encoding that can represent a wide range of characters from various languages and is commonly used for internationalization support.

org.gradle.parallel=true: This configuration enables parallel execution of tasks which can significantly speed up the build process by utilizing multiple CPU cores and processing tasks concurrently.

org.gradle.daemon=true: When this configuration is set to true, Gradle will use a build daemon which is a long-lived process that remains running in the background. The daemon keeps certain parts of the build process in memory, reducing startup overhead and improving build performance for subsequent invocations.

org.gradle.configureondemand=true: When enabled, Gradle will only configure the projects and tasks that are required for the current build, ignoring any unnecessary parts. This can help speed up the configuration phase of the build for large multi-module projects.

org.gradle.caching=true: This configuration enables Gradle’s build caching feature which stores build outputs in a cache. When subsequent builds are run with the same inputs, Gradle can reuse the cached outputs, resulting in faster build times.

org.gradle.unsafe.configuration-cache=true: This configuration is used to enable the experimental configuration caching feature in Gradle. When enabled, Gradle caches the results of project configuration leading to faster build times. However, note that enabling Gradle’s configuration cache would lead to inconsistencies and build failures when used with other Gradle plugins such as the Dokka documentation plugin. You can disable configuration caching when problems arise.

org.gradle.warning.mode=none: Setting this configuration to “none” disables all warning messages during the build process. Warnings are typically informative messages about potential issues but can be suppressed if deemed unnecessary.

kotlin.daemon.useFallbackStrategy=true: This configuration is specific to projects using the Kotlin language. When set to true, it allows Gradle to use a fallback strategy if the Kotlin daemon is not available or fails. The Kotlin daemon improves the performance of Kotlin-related tasks during the build.

Keep in mind that some of these configurations might have side effects or may not be suitable for all projects. It’s essential to understand their implications and use them judiciously based on the specific requirements and characteristics of your Gradle projects.

With all these in place, Gradle is ready to work faster and more efficiently than in its default state.

Relevant Android Gradle tasks

There are tasks which are commonly invoked by Gradle for Android projects you should be aware of.

These tasks play a vital role in the Android project build process, contributing to the creation of the final APK, enabling smooth development, testing and deployment workflows.

They are executed automatically when you run specific Gradle commands like gradlew clean, gradlew installDebug, etc., or when you trigger a build from Android Studio.

These are some of the common Android Gradle tasks used in Android projects:

  • clean: This task is used to clean the build outputs of the project. It removes all the build artifacts, intermediate files and output directories thereby allowing for a fresh build from scratch.
  • compileDebugKotlin: This task compiles Kotlin source code files in the “debug” build variant. It converts Kotlin code into Java bytecode that can be executed on the Android platform. This task is part of the Kotlin plugin for Gradle.
  • installDebug: This task installs the “debug” variant of the Android application on a connected device or emulator. It first compiles the code and then deploys the APK to the target device for testing and debugging.
  • kaptGenerateStubsDebugKotlin: This task is used in projects that utilize Kotlin Annotation Processing Tool (KAPT) to generate code from annotations. It generates the stubs for Kotlin annotation processors in the “debug” variant.
  • kaptDebugKotlin: This task triggers the Kotlin Annotation Processing Tool (KAPT) to process annotations and generate code in the “debug” variant. It is responsible for generating code based on annotations in Kotlin source files.
  • processDebugResources: This task processes resources (e.g., XML layouts, images, strings) for the “debug” variant. It compiles resources, applies resource qualifiers, and generates the final resource files to be included in the APK.
  • compileKotlin (for non-android modules): This task is similar to compileDebugKotlin, but it is used for non-Android modules within an Android project. It compiles Kotlin source code in regular Java/Kotlin modules and is not specific to Android.

Note that most of these tasks are notable time consuming. Also, do note that the above are debug tasks which have their release equivalent.

Invoking Gradle

The Gradle wrapper simplifies project setup, enhances consistency and facilitates collaboration among team members by providing a standardized and reproducible build environment. Its usage is strongly recommended for any Gradle project to avoid potential build-related issues and create a more manageable development experience.

The Gradle wrapper is recommended for Gradle projects for several reasons:

  • Consistent Gradle version: The Gradle wrapper ensures that everyone working on the project uses the same version of Gradle. This eliminates version discrepancies between developers which can lead to build inconsistencies and potential issues. With the wrapper, the project specifies a specific version of Gradle and the wrapper script automatically downloads and uses that version for all developers.
  • Easy setup: When a new developer clones the project or checks it out from version control, they don’t need to install Gradle separately. The Gradle wrapper takes care of downloading the specified Gradle version if it’s not already available on the system. This streamlines the setup process and makes it easier for new team members to get started quickly.
  • Cross-platform compatibility: The Gradle wrapper is a script (typically gradlew for Unix-like systems and gradlew.bat for Windows) that can be executed on various platforms without any modifications. This means that the project can be built consistently on different operating systems without worrying about the differences in local Gradle installations.
  • Gradle version upgrades: Upgrading the Gradle version for a project can be challenging as it may require updates to build scripts and configuration files. The Gradle wrapper simplifies this process by isolating the Gradle distribution from the project making it easier to switch to a newer version without affecting the overall project setup.
  • Continuous Integration (CI) and automated builds: CI systems like Jenkins, Travis CI or CircleCI can easily use the Gradle wrapper to build the project since it requires minimal configuration. The wrapper makes it straightforward to set up automated builds without having to install Gradle explicitly on the CI server.
  • Reproducible builds: By using the Gradle wrapper, you can ensure that anyone building the project will get the same results. This is crucial for reproducibility as it guarantees that the build environment is consistent across different machines and over time.

However in this article, Gradle would be invoked without depending on the Gradle wrapper.

There is no particular reason for this other than the Gradle wrapper by default looks for the Gradle installation at the default location C:\Users\ (your-username)\.gradle and if it is not found (say in a situation where Gradle is located elsewhere), then the Gradle wrapper begins to download the Gradle version it is configured to work with.

When using the Gradle wrapper, Gradle is invoked with gradlew eg: gradlew tasks.

Without the Gradle wrapper, Gradle is invoked with gradle eg: gradle tasks

You can read further on the Gradle wrapper in the official documentation.

Take note of the location of your Gradle installation. My Gradle is installed in C:\Gradle. It will be passed to the --gradle-user-home command like so:

--gradle-user-home C:\Gradle

Take note of the location of where your JDK is installed. It is recommended to use the Android studio JetBrains (jbr) version. It will be passed to the -Dorg.gradle.java.home command like so:

-Dorg.gradle.java.home=”C:\Program Files\Android\Android Studio\jbr”

Open your terminal and change to the directory containing your Android project. Say for example, you have BannerX source files located at C:\Github_Projects\Android\BannerX

BannerX source files

Switch to the folder on the terminal using:

cd C:\Github_Projects\Android\BannerX
Switching to BannerX source files via command-line

For context, I am running Gradle on a 64-bit windows OS using an AMD E1–6010 APU with AMD Radeon R2 and 4GB RAM with (3.45 GB usable).

Low resource setup

This is below the standard for native Android and programming in general. I will be using this to demonstrate the relevance of running Gradle on the command-line for setups with low resources as opposed to using Android studio.

To invoke Gradle to execute a project wide task, using the information gotten from the above steps, the syntax is:

gradle [task] --gradle-user-home C:\Gradle -Dorg.gradle.java.home="C:\Program Files\Android\Android Studio\jbr"

For example, to execute the tasks Gradle task which prints all available Gradle tasks for the project:

gradle tasks --gradle-user-home C:\Gradle -Dorg.gradle.java.home="C:\Program Files\Android\Android Studio\jbr"
gradle tasks command-line output

To invoke Gradle to execute several project wide tasks, each task is separated using white spaces and executed in the order they are declared.

gradle [task] [task]…[task] --gradle-user-home C:\Gradle -Dorg.gradle.java.home="C:\Program Files\Android\Android Studio\jbr"

For example, to clean and then build the project:

gradle clean build --gradle-user-home C:\Gradle -Dorg.gradle.java.home="C:\Program Files\Android\Android Studio\jbr"

To invoke Gradle to execute several tasks for a single module, each task is separated using white spaces and executed in the order they are declared.

gradle :[module][task] :[module][task]…:[module][task] --gradle-user-home C:\Gradle -Dorg.gradle.java.home="C:\Program Files\Android\Android Studio\jbr"

For example, to clean and then run the assembleDebug task for the sample module of the BannerX project:

gradle :sample:clean :sample:assembleDebug --gradle-user-home C:\Gradle -Dorg.gradle.java.home="C:\Program Files\Android\Android Studio\jbr"

To invoke Gradle to execute a task for a single module, the syntax is:

gradle :[module][task] --gradle-user-home C:\Gradle -Dorg.gradle.java.home="C:\Program Files\Android\Android Studio\jbr"

For example, to execute the assembleDebug task for the sample module of the BannerX project:

gradle :sample:assembleDebug --gradle-user-home C:\Gradle -Dorg.gradle.java.home="C:\Program Files\Android\Android Studio\jbr"

For command-line, this took 2 minutes, 53 seconds.

Using Android studio, it took 5 minutes, 34 seconds.

It is also important to note the memory usage of the JVM while Gradle was running. On Windows, you can use the Task Manager. On Mac, this is done using the Activity Monitor.

While using command-line Gradle for assembleDebug, the total memory usage was peaking at approximately 515MB out of 3.45GB RAM. This leaves enough room to run other applications while Gradle does its job on the background.

While using Android studio to run the same assembleDebug, the total memory usage was peaking at around 2.17GB out of 3.45GB RAM. Any attempt to run other applications would freeze both Android studio and the entire system.

The system running Gradle and Android studio in this scenario does not have enough resources to spare while running both applications at the same time. Performance and build time would get progressively worse as the project increases in size and complexity.

By running Gradle from the command-line independently, you can free up resources and allocate them to other applications, resulting in smoother multitasking.

Executing the installed APK

Recall, the assembleDebug task is used to build a debuggable APK and the installDebug is used to install the debuggable APK on an emulator or physical device.

Note: Physical devices have to be plugged in and emulators have to be running before the above tasks are executed.

When these tasks have been executed, the APK would be available on the target device and can be launched manually.

However to launch the APK automatically, the Android Debug Bridge (adb) command-line is needed. The android debug bridge has commands you can be familiar with.

To do this, you need the module’s namespace or root package declaration and the android:name attribute of the launching Activity which has the MAIN intent action.

The namespace attribute can be gotten from the module’s build.gradle

Namespace declaration for BannerX

The activity with the MAIN intent action can be gotten from the AndroidManifest.xml file.

The syntax is :

adb -d shell am start -n your.app.package.name/.entry_activity

For example, in the sample module of the BannerX project, the namespace/package declaration is com.blueiobase.api.android.bannerx.sample and the entry activity android:name value is .ui.activity.MainActivity.

The final invocation would then be:

adb -d shell am start -n com.blueiobase.api.android.bannerx.sample/.ui.activity.MainActivity

This command immediately launches the application from the entry activity.

Harnessing the power of Gradle from the command-line offers Android developers faster build times, efficient resource management and increased productivity.

By employing the Gradle wrapper and configuring Gradle parameters optimally, developers can break free from Android Studio’s resource-heavy environment while maintaining a seamless development experience.

--

--

IO DevBlue

Android platform specialist || C++, Java and Kotlin programmer || Android API Technical Writer.