A good developer ships reliably. This lesson covers the tools that make builds repeatable and releases safe: version control, Gradle, automated builds and the full Google Play process.
Git and GitHub
git init,add,commit,status,log,diffare the daily commands. Commit small, with messages that say why.- Use branches:
git switch -c feature/cart. Merge or rebase back intomain. - Open a pull request on GitHub so teammates can review, and let automated checks run on it.
- Add a
.gitignoreforbuild/,.gradle/,local.propertiesand keystores. Never commit signing keys or API keys. - Resolve conflicts by reading both sides carefully, then run the tests.
Gradle with the Kotlin DSL
Gradle builds your project from build.gradle.kts files. A version catalog (gradle/libs.versions.toml) lists library versions in one place, so every module uses the same ones.
[versions]
room = "2.6.1"
retrofit = "2.11.0"
[libraries]
room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
// in build.gradle.kts
dependencies {
implementation(libs.room.runtime)
implementation(libs.retrofit)
}
Build types, flavors and variants
A build type is debug or release. A product flavor is a version of the app, such as free and paid, or staging and production. Together they make build variants like stagingDebug. Use them for different base URLs, app names and Firebase projects. Put values in buildConfigField and read them from BuildConfig.
android {
buildFeatures { buildConfig = true }
flavorDimensions += "env"
productFlavors {
create("staging") {
dimension = "env"
applicationIdSuffix = ".staging"
buildConfigField("String", "BASE_URL", "\"https://staging.example.com/\"")
}
create("production") {
dimension = "env"
buildConfigField("String", "BASE_URL", "\"https://api.example.com/\"")
}
}
}
Signing configurations
Read passwords from environment variables or an untracked keystore.properties file, never from the build file itself.
signingConfigs {
create("release") {
storeFile = file(System.getenv("KEYSTORE_PATH") ?: "release.jks")
storePassword = System.getenv("KEYSTORE_PASSWORD")
keyAlias = System.getenv("KEY_ALIAS")
keyPassword = System.getenv("KEY_PASSWORD")
}
}
buildTypes { release { signingConfig = signingConfigs.getByName("release"); isMinifyEnabled = true } }
Continuous integration
CI builds and tests every push automatically. With GitHub Actions, a file in .github/workflows describes the job. Store secrets (keystore as base64, passwords) in the repository's encrypted secrets.
name: Android CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with: { distribution: temurin, java-version: 17 }
- uses: gradle/actions/setup-gradle@v4
- run: ./gradlew testDebugUnitTest assembleDebug
Fastlane automates the release steps: building, signing, uploading to Play Console and publishing release notes. Use CD (continuous delivery) to push each tagged build to internal testing automatically.
Play Console in depth
- App signing: use Play App Signing so Google keeps the app signing key. You upload with an upload key.
- Versioning:
versionCodemust increase for each upload,versionNameis shown to users, and the application ID is permanent. - Store listing and ASO: a clear title and short description with the words people search, a high-quality icon, 4 to 8 screenshots and a feature graphic. Honest descriptions help conversion and trust.
- Policy forms: privacy policy URL, data safety, content rating, target audience, ads declaration and permissions declarations.
- Testing tracks: internal (up to 100 testers, instant), closed (invited groups) and open (anyone). Personal developer accounts created recently may need to run a closed test with a minimum number of testers before production; check the current requirements.
- Staged rollout: release to 5 or 10 percent, watch crashes and ratings in Android vitals, then increase or halt.
- After release: reply to reviews, fix crashes first, and follow Play policy updates, since apps that break policy can be removed.
Your task
- Create a GitHub repository for one project with a proper .gitignore, then push a feature branch and open a pull request.
- Add staging and production flavors with different base URLs.
- Add the GitHub Actions workflow and see it pass.
- Write a release checklist for your app.
How to check it worked
- No key or password is in the repository.
- The CI run builds and tests every push.
- You can explain internal, closed, open and production tracks.