# Build Variants Documentation
## Overview
Rhythm uses Android build variants (product flavors) to create different builds for different distribution channels while maintaining a single codebase.
## Quick Reference
```bash
# Build commands
./gradlew assembleFdroidRelease # For F-Droid
./gradlew assembleGithubRelease # For GitHub Releases
# List all build variants
./gradlew tasks --all | grep assemble
```
## Build Configuration
### Flavor Dimension: `distribution`
All flavors belong to the `distribution` dimension, ensuring they're mutually exclusive.
### Product Flavors
#### 1. `fdroid`
**Purpose:** F-Droid repository distribution
**Package:** `chromahub.rhythm.app`
**Version Suffix:** `-fdroid`
**BuildConfig Flags:**
```kotlin
ENABLE_YOUTUBE_MUSIC = true
ENABLE_SPOTIFY_SEARCH = true
ENABLE_LYRICALLY_API = true
ENABLE_DEEZER = true
ENABLE_LRCLIB = true
```
**Default Settings:** All features enabled. APIs and auto-updates disabled by default (opt-in for F-Droid compliance).
**Philosophy:** FOSS users expect maximum functionality. F-Droid isn't bound by corporate app store policies, but opt-in defaults ensure compliance.
---
#### 2. `github`
**Purpose:** Direct GitHub releases
**Package:** `chromahub.rhythm.app`
**Version Suffix:** `-gh`
**BuildConfig Flags:**
```kotlin
ENABLE_YOUTUBE_MUSIC = true
ENABLE_SPOTIFY_SEARCH = true
ENABLE_LYRICALLY_API = true
ENABLE_DEEZER = true
ENABLE_LRCLIB = true
```
**Default Settings:** All features enabled. APIs and auto-updates enabled by default (opt-out available).
**Use Case:** Users who download directly from GitHub releases get the full-featured experience.
---
## How BuildConfig Flags Work
### 1. Compile-Time Conditional Compilation
Flags are defined in `app/build.gradle.kts`:
```kotlin
buildConfigField("boolean", "ENABLE_YOUTUBE_MUSIC", "true")
```
### 2. Runtime API Initialization
APIs are initialized conditionally in `NetworkClient.kt`:
```kotlin
val ytmusicApiService: YTMusicApiService? = if (BuildConfig.ENABLE_YOUTUBE_MUSIC) {
ytmusicRetrofit.create(YTMusicApiService::class.java)
} else null
```
### 3. Settings UI Adaptation
UI components check BuildConfig before rendering:
```kotlin
if (BuildConfig.ENABLE_YOUTUBE_MUSIC) {
ApiServiceRow(title = "YouTube Music", ...)
}
```
### 4. Runtime Feature Checks
Code checks both BuildConfig AND user settings:
```kotlin
fun isYTMusicApiEnabled(): Boolean =
BuildConfig.ENABLE_YOUTUBE_MUSIC && (appSettings?.ytMusicApiEnabled?.value ?: false)
```
**Default Settings by Variant:**
- **F-Droid:** APIs and auto-updates disabled by default (opt-in for compliance)
- **GitHub:** APIs and auto-updates enabled by default (opt-out available)
**This ensures:**
- Build variants properly control feature availability
- Users can toggle features on/off within allowed limits
- F-Droid compliance through opt-in defaults
- Single codebase maintains all variants
---
## Variant-Specific Resources
### Directory Structure
```
app/src/
├── main/ # Shared code and resources
├── fdroid/
│ └── res/
│ └── values/
│ └── config.xml
└── github/
└── res/
└── values/
└── config.xml
```
### Resource Flags
Each variant has a `config.xml` with boolean resources:
**fdroid/res/values/config.xml:**
```xml
true
true
true
true
true
F-Droid
```
**github/res/values/config.xml:**
```xml
true
true
true
true
true
GitHub
```
---
## Build Output
### APK Naming Convention
```
Rhythm-{versionName}-{flavorVariant}-{abi}.apk
```
**Examples:**
```
Rhythm-5.1.414.1085 Beta-fdroidRelease-arm64-v8a.apk
Rhythm-5.1.414.1085 Beta-githubRelease-armeabi-v7a.apk
```
### Output Locations
**APKs:**
```
app/build/outputs/apk/fdroid/release/
app/build/outputs/apk/github/release/
```
**App Bundles (AAB):**
```
app/build/outputs/bundle/fdroidRelease/app-fdroid-release.aab
app/build/outputs/bundle/githubRelease/app-github-release.aab
```
---
## Testing Variants
### Build All Variants
```bash
# Release builds
./gradlew assembleRelease
# Debug builds
./gradlew assembleDebug
# Specific variant
./gradlew assembleFdroidDebug
```
### Install Specific Variant
```bash
# Install F-Droid debug
./gradlew installFdroidDebug
# Install GitHub release
adb install app/build/outputs/apk/github/release/Rhythm-*.apk
```
### Verify BuildConfig Values
After building, check generated BuildConfig:
**F-Droid:**
```
app/build/generated/source/buildConfig/fdroid/release/chromahub/rhythm/app/BuildConfig.java
```
Should contain:
```java
public static final boolean ENABLE_YOUTUBE_MUSIC = true;
public static final boolean ENABLE_SPOTIFY_SEARCH = true;
```
**GitHub:**
```
app/build/generated/source/buildConfig/github/release/chromahub/rhythm/app/BuildConfig.java
```
Should contain:
```java
public static final boolean ENABLE_YOUTUBE_MUSIC = true;
public static final boolean ENABLE_SPOTIFY_SEARCH = true;
```
---
## CI/CD Integration
### GitHub Actions Example
```yaml
name: Build All Variants
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: '21'
- name: Build F-Droid variant
run: ./gradlew assembleFdroidRelease
- name: Build GitHub variant
run: ./gradlew assembleGithubRelease
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: apk-variants
path: app/build/outputs/apk/**/release/*.apk
```
### F-Droid Metadata
Add to `.fdroid.yml` or `metadata/*.yml`:
```yaml
Builds:
- versionName: 5.1.414.1085 Beta
versionCode: 514141085
gradle:
- fdroid
# F-Droid will automatically use the fdroid flavor
```
---
## Troubleshooting
### Issue: Wrong variant built
**Symptom:** APK has unexpected features enabled/disabled
**Solution:** Verify you ran the correct assemble task (e.g., `./gradlew assembleFdroidRelease`)
### Issue: UI shows disabled features
**Symptom:** F-Droid build hides YouTube Music settings
**Solution:** Check `BuildConfig.ENABLE_YOUTUBE_MUSIC` in generated files
### Issue: Null pointer when calling API
**Symptom:** Crash when accessing `ytmusicApiService`
**Solution:** Ensure null-safe access:
```kotlin
if (ytmusicApiService != null) {
ytmusicApiService.search(...)
}
```
### Issue: Build fails with variant not found
**Symptom:** `Task 'assembleFdroid' not found`
**Solution:** Use full variant name: `assembleFdroidRelease` or `assembleFdroidDebug`
---
## Maintenance
### Adding a New Build Variant
1. **Add flavor in `app/build.gradle.kts`:**
```kotlin
create("newvariant") {
dimension = "distribution"
applicationId = "chromahub.rhythm.app"
buildConfigField("boolean", "ENABLE_YOUTUBE_MUSIC", "true")
versionNameSuffix = "-new"
}
```
2. **Create variant directory:**
```bash
mkdir -p app/src/newvariant/res/values
```
3. **Add config.xml:**
```xml
New Variant
```
4. **Test build:**
```bash
./gradlew assembleNewvariantRelease
```
### Removing a Build Variant
1. Delete flavor block from `build.gradle.kts`
2. Remove `app/src/variantname/` directory
3. Sync Gradle: `./gradlew --refresh-dependencies`
---
## Best Practices
### 1. Version Consistency
- All variants share the same `versionCode` and `versionName`
- Only `versionNameSuffix` differs for logging
### 2. Feature Parity
- F-Droid and GitHub should always have identical features
### 3. Testing
- Test each variant separately before release
- Ensure disabled features don't appear in UI
- Verify API calls are actually blocked
### 4. Documentation
- Keep this README updated when adding/removing features
- Document any variant-specific behavior
---
## FAQ
**Q: Can I install multiple variants on the same device?**
A: No, they share the same `applicationId`. Use debug builds with different IDs for testing.
**Q: Which variant should I use for local development?**
A: Use `fdroid` or `github` debug builds for full feature access during development.
**Q: How do I know which variant is installed?**
A: Check Settings → About → Build Info or check version suffix in logs.
**Q: Can users switch between variants?**
A: No, they must uninstall and reinstall a different variant. Data won't transfer.
**Q: Why not use separate apps with different package names?**
A: Single package name simplifies distribution across different channels.
---
## Related Documentation
- [Build Instructions](../wiki/Build-Instructions.md)
- [Contributing Guide](CONTRIBUTING.md)
---
*Last Updated: June 22, 2026*
*Rhythm Music Player Build System Documentation*