Build System
NASA Explorer uses Gradle with Kotlin DSL for its build system. The project supports multiple build variants and configurations.
Prerequisites
Before building, ensure you have completed the requirements setup :
Verify Android Studio
Ensure you have Android Studio Koala or newer installed.
Configure API Keys
Create local.properties with your NASA API key: nasaApiKey =YOUR_NASA_API_KEY
Add Firebase Configuration
Place google-services.json in the app/ directory.
Building will fail without the NASA API key and Firebase configuration files. These are required dependencies.
Building from Android Studio
The easiest way to build and run the application.
Initial Setup
Open Project
Open the project in Android Studio: cd NASAExplorer
# Then File > Open in Android Studio
Sync Gradle
Android Studio will automatically prompt you to sync Gradle. Click Sync Now to download dependencies. If sync doesn’t start automatically, click:
File > Sync Project with Gradle Files
Select Build Variant
Open the Build Variants panel (bottom left) and select:
debug - For development
release - For production builds
Running the App
Connect Device
Connect an Android device via USB with USB debugging enabled, or start an Android emulator.
Select Target Device
Choose your target device from the device dropdown in the toolbar.
Run
Click the Run button (green play icon) or press Shift + F10 . Android Studio will build the APK and install it on your device.
The first build may take several minutes as Gradle downloads dependencies. Subsequent builds will be faster thanks to caching.
Building from Command Line
For automation, CI/CD, or advanced users, you can build using Gradle commands.
Debug Build
Build a debug APK for development:
# Linux/macOS
./gradlew assembleDebug
# Windows
gradlew.bat assembleDebug
The APK will be generated at:
app/build/outputs/apk/debug/app-debug.apk
Release Build
Build a release APK optimized for production:
./gradlew assembleRelease
The APK will be generated at:
app/build/outputs/apk/release/app-release.apk
Release builds require signing configuration. Without it, you’ll get an unsigned APK that can only be used for testing.
Install Directly
Build and install the app on a connected device in one command:
Clean Build
Remove all build artifacts and rebuild from scratch:
Build Configuration
Understanding the build configuration files.
App Build Configuration
The app/build.gradle.kts file defines app-specific build settings:
Application ID
Build Types
Java Compatibility
android {
namespace = "com.ccandeladev.nasaexplorer"
compileSdk = 34
defaultConfig {
applicationId = "com.ccandeladev.nasaexplorer"
minSdk = 28
targetSdk = 34
versionCode = 1
versionName = "1.0"
}
}
API Key Injection
The NASA API key is injected from local.properties during build:
// Read local.properties
val localProperties = Properties (). apply {
load (project.rootProject. file ( "local.properties" ). inputStream ())
}
// Get API key
val nasaApiKey: String = localProperties. getProperty ( "nasaApiKey" ) ?: ""
// Inject into BuildConfig
android {
defaultConfig {
buildConfigField ( "String" , "NASA_API_KEY" , " \" $nasaApiKey \" " )
}
buildFeatures {
buildConfig = true
}
}
Access in code:
val apiKey = BuildConfig.NASA_API_KEY
Signing Configuration
To distribute your app, you need to sign it with a keystore.
Creating a Keystore
Generate Keystore
Use the keytool command to create a keystore: keytool -genkey -v -keystore nasa-explorer.keystore \
-alias nasa-explorer \
-keyalg RSA \
-keysize 2048 \
-validity 10000
Store Safely
Save the keystore file in a secure location outside the project directory. Never commit keystore files or passwords to version control.
Add Signing Configuration
Add signing configuration to local.properties: nasaApiKey =YOUR_NASA_API_KEY
storeFile =/path/to/nasa-explorer.keystore
storePassword =YOUR_STORE_PASSWORD
keyAlias =nasa-explorer
keyPassword =YOUR_KEY_PASSWORD
Update app/build.gradle.kts to use the keystore:
val localProperties = Properties (). apply {
load (project.rootProject. file ( "local.properties" ). inputStream ())
}
android {
signingConfigs {
create ( "release" ) {
storeFile = file (localProperties. getProperty ( "storeFile" ))
storePassword = localProperties. getProperty ( "storePassword" )
keyAlias = localProperties. getProperty ( "keyAlias" )
keyPassword = localProperties. getProperty ( "keyPassword" )
}
}
buildTypes {
release {
signingConfig = signingConfigs. getByName ( "release" )
isMinifyEnabled = true
proguardFiles (
getDefaultProguardFile ( "proguard-android-optimize.txt" ),
"proguard-rules.pro"
)
}
}
}
Code Optimization
ProGuard / R8
The release build uses R8 for code shrinking and obfuscation.
buildTypes {
release {
isMinifyEnabled = true
proguardFiles (
getDefaultProguardFile ( "proguard-android-optimize.txt" ),
"proguard-rules.pro"
)
}
}
R8 is enabled by default and provides better performance than ProGuard. It automatically handles most Android libraries.
Custom ProGuard Rules
Add custom rules in app/proguard-rules.pro:
# Keep Firebase classes
-keep class com.google.firebase.** { *; }
# Keep Retrofit interfaces
-keep interface com.ccandeladev.nasaexplorer.data.api.** { *; }
# Keep data models for Gson
-keep class com.ccandeladev.nasaexplorer.data.api.NasaResponse { *; }
-keep class com.ccandeladev.nasaexplorer.domain.** { *; }
Build Variants
The project currently has two build types:
Variant Purpose Minification Debuggable debug Development No Yes release Production Yes No
Adding Custom Build Variants
You can add custom build variants for different environments:
android {
buildTypes {
debug {
applicationIdSuffix = ".debug"
versionNameSuffix = "-DEBUG"
}
create ( "staging" ) {
initWith ( getByName ( "debug" ))
applicationIdSuffix = ".staging"
versionNameSuffix = "-STAGING"
}
release {
isMinifyEnabled = true
proguardFiles (
getDefaultProguardFile ( "proguard-android-optimize.txt" ),
"proguard-rules.pro"
)
}
}
}
Optimize build performance with these Gradle settings.
gradle.properties Optimizations
# Use more RAM for Gradle daemon
org.gradle.jvmargs =-Xmx4096m - Dfile.encoding =UTF-8
# Enable parallel builds
org.gradle.parallel =true
# Enable Gradle caching
org.gradle.caching =true
# Enable configuration cache (experimental)
org.gradle.configuration-cache =true
# Use Kotlin incremental compilation
kotlin.incremental =true
Build Cache
Enable Gradle build cache in settings.gradle.kts:
buildCache {
local {
isEnabled = true
directory = File (rootDir, "build-cache" )
}
}
Troubleshooting
Common build issues and solutions.
Gradle Sync Failed
Invalidate Caches
In Android Studio: File > Invalidate Caches… > Invalidate and Restart
Delete Gradle Cache
rm -rf ~/.gradle/caches
./gradlew clean build --refresh-dependencies
Missing API Key Error
BuildConfig.NASA_API_KEY is empty
Solution: Ensure local.properties exists with your NASA API key:
nasaApiKey =YOUR_API_KEY_HERE
Google Services Plugin Error
File google-services.json is missing
Solution: Download google-services.json from Firebase Console and place it in the app/ directory.
Out of Memory Error
OutOfMemoryError: Java heap space
Solution: Increase Gradle JVM heap size in gradle.properties:
org.gradle.jvmargs =-Xmx4096m - Dfile.encoding =UTF-8
Generating AAB for Play Store
Android App Bundles (AAB) are the recommended format for Play Store distribution.
The AAB will be generated at:
app/build/outputs/bundle/release/app-release.aab
AAB files are smaller and allow Google Play to generate optimized APKs for different device configurations.
CI/CD Integration
Example GitHub Actions workflow for automated builds:
.github/workflows/build.yml
name : Build APK
on :
push :
branches : [ main ]
pull_request :
branches : [ main ]
jobs :
build :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v4
- name : Set up JDK 17
uses : actions/setup-java@v4
with :
java-version : '17'
distribution : 'temurin'
- name : Create local.properties
run : |
echo "nasaApiKey=${{ secrets.NASA_API_KEY }}" > local.properties
- name : Add google-services.json
run : |
echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > app/google-services.json
- name : Build Debug APK
run : ./gradlew assembleDebug
- name : Upload APK
uses : actions/upload-artifact@v4
with :
name : app-debug
path : app/build/outputs/apk/debug/app-debug.apk
Store sensitive keys (API keys, keystore passwords) as GitHub Secrets, never commit them to the repository.