Setting Up CI/CD for Android App with Gradle

Setting up CI/CD for Android raises more questions than it seems. A common situation: a developer pushes code, CI fails with a 'Keystore not found' error, or the build takes 15 minutes, and the release is delayed by a day. Recently, a team of 5 developers approached us: their build took 30 minutes,

Development and support of all types of mobile applications:

Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1All 1734 services
Setting Up CI/CD for Android App with Gradle
Medium
~2-3 days

Our competencies:

Frequently Asked Questions

Latest works

  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    896
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    1003
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    597

Setting up CI/CD for Android raises more questions than it seems. A common situation: a developer pushes code, CI fails with a 'Keystore not found' error, or the build takes 15 minutes, and the release is delayed by a day. Recently, a team of 5 developers approached us: their build took 30 minutes, releases came out once every two weeks. After implementing CI/CD with Gradle caching and parallel builds, build time dropped to 10 minutes, release frequency increased to weekly. Reducing build time directly lowers CI runner costs and speeds up update delivery, saving the team's budget.

The main pitfalls: keystore in the repo, manual versioning, no CI caching, incorrect build variant configuration. Each of these mistakes can block a release or lead to secret leakage. Our CI/CD setup service includes a full audit of your current build, Gradle configuration following best practices, integration with a CI system, and deployment to Google Play. Investment in CI/CD setup pays off through faster release cycles and reduced manual work. We guarantee stable operation after implementation.

How to properly sign APKs in CI?

Storing the keystore in Git is a critical mistake, even in private repositories. The correct approach: keystore Base64-encoded → CI secret → decode on the fly.

# GitHub Actions - name: Decode Keystore run: | echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > app/release.keystore - name: Build Release AAB run: ./gradlew bundleRelease env: SIGNING_STORE_FILE: release.keystore SIGNING_STORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} SIGNING_KEY_ALIAS: ${{ secrets.KEY_ALIAS }} SIGNING_KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} 

In app/build.gradle.kts:

signingConfigs { create("release") { storeFile = file(System.getenv("SIGNING_STORE_FILE") ?: "debug.keystore") storePassword = System.getenv("SIGNING_STORE_PASSWORD") ?: "" keyAlias = System.getenv("SIGNING_KEY_ALIAS") ?: "" keyPassword = System.getenv("SIGNING_KEY_PASSWORD") ?: "" } } buildTypes { release { signingConfig = signingConfigs.getByName("release") isMinifyEnabled = true proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") } } 

The keystore does not end up in artifacts — we delete it after the build: rm -f app/release.keystore.

The process consists of several steps:

  1. Upload the keystore to CI secrets as a Base64 string.
  2. Create a job to decode and build.
  3. Configure signingConfig in build.gradle.kts using environment variables.
  4. After the build, delete the keystore from the file system.

Why is automatic versioning the standard?

versionCode in Android must be unique for each build. A mistake is to update it manually. On CI — automate it:

// build.gradle.kts val ciPipelineNumber = System.getenv("CI_BUILD_NUMBER")?.toIntOrNull() ?: 1 val gitCommitCount = "git rev-list --count HEAD".runCommand().trim().toIntOrNull() ?: 1 android { defaultConfig { versionCode = ciPipelineNumber.takeIf { it > 1 } ?: gitCommitCount versionName = "2.4.${gitCommitCount}" } } 

Comparison of methods:

Method Description Monotonicity CI dependency
CI_BUILD_NUMBER Build number from provider Yes, if not reset Yes (problems when switching CI)
git commit count Number of commits Always monotonic No (universal)

We recommend git commit count — it is not tied to a CI system.

How to speed up Gradle builds?

Slow Gradle is the top complaint for Android CI. Several specific settings in gradle.properties:

  • org.gradle.parallel=true — parallel module building.
  • org.gradle.configureondemand=true — configure only needed modules.
  • org.gradle.caching=true — local task cache. When module code is unchanged, Gradle takes the result from cache without recompilation. On CI this works via actions/cache (GitHub) with a key based on the hash of *.gradle* files.
  • org.gradle.jvmargs=-Xmx4g -XX:+UseParallelGC — increased heap.
  • android.defaults.buildfeatures.buildconfig=false — generate BuildConfig only for active build.

More on cache configuration: see Gradle Build Cache. Comparison of build time with different configurations on ubuntu-latest runner:

Configuration Build time (minutes)
No optimizations 10–15
Parallelism + configureondemand 6–8
Full caching + JVM heap 4GB 2–4

Proper caching reduces build time by 3-4 times. Use R8 instead of ProGuard — it's faster.

Which build variants should be configured?

Different variants for different environments is standard:

flavorDimensions += "env" productFlavors { create("dev") { applicationIdSuffix = ".dev" buildConfigField("String", "API_URL", "\"https://api.dev.example.com\"") } create("prod") { buildConfigField("String", "API_URL", "\"https://api.example.com\"") } } 

On CI — separate jobs for each variant:

  • PR → assembleDevDebug + tests
  • merge to develop → assembleDevRelease + Firebase App Distribution
  • release tag → bundleProdRelease + Google Play

Uploading to Google Play via Gradle

gradle-play-publisher plugin:

// build.gradle.kts plugins { id("com.github.triplet.play") version "3.9.1" } play { serviceAccountCredentials.set(file(System.getenv("PLAY_STORE_JSON") ?: "play-store-credentials.json")) track.set("internal") defaultToAppBundles.set(true) } 

Credentials JSON — a service account from Google Play Console with Release manager access. Pass via environment variable on CI, similar to the keystore.

What's included in CI/CD setup?

Stage Description Timeline
Analysis Audit of current build, infrastructure, and CI configuration 1 day
Gradle configuration Setting up signing, versioning, flavors, caching 1–2 days
CI integration Configuring workflows (GitHub Actions/GitLab CI/Bitrise), secrets, deployment 1–2 days
Optimization Speeding up builds, introducing tests, parallel tasks 1–2 days
Documentation Description of the process, guide for the team 1 day

Timeline

Basic CI/CD setup (signing, versioning, one CI) takes 2–4 days. Full configuration with build variants, deployment to Google Play, build optimization — 1–2 weeks. Cost is calculated individually.

If your build takes too long or releases keep failing, it's time to implement professional CI/CD. Contact us — we'll audit and set up the process so you can forget about release issues. We guarantee stable results.