Firebase Remote Config — Complete Guide
In this tutorial, you'll learn about Firebase Remote Config. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
The Problem
Your Remote Config values are always default, or the feature flag takes too long to update after changing in the console.
Wrong Approach ❌
// Fetching but never activating
val remoteConfig = FirebaseRemoteConfig.getInstance()
remoteConfig.fetch(cacheExpiration = 3600) // Fetched but not activated!
val flag = remoteConfig.getBoolean("feature_enabled") // Returns default always
Output: feature_enabled always returns false (the default). Fetch has no effect.
Right Approach ✅
class FeatureFlagManager(context: Context) {
private val remoteConfig = FirebaseRemoteConfig.getInstance().apply {
// Set defaults — used when no fetched values exist
setDefaultsAsync(
mapOf(
"feature_enabled" to false,
"welcome_message" to "Welcome!",
"max_items" to 20L,
"button_color" to "#6200EE"
)
)
// Configure fetch interval
val configSettings = FirebaseRemoteConfigSettings.Builder()
.setMinimumFetchIntervalInSeconds(
if (BuildConfig.DEBUG) 0 else 3600 // 0 for debug, 1 hour for release
)
.build()
setConfigSettingsAsync(configSettings)
}
// Fetch and activate in one call
suspend fun fetchAndActivate(): Boolean {
return try {
remoteConfig.fetchAndActivate().await()
} catch (e: Exception) {
Log.e("RemoteConfig", "Fetch failed", e)
false
}
}
fun isFeatureEnabled(feature: String): Boolean {
return remoteConfig.getBoolean(feature)
}
fun getStringValue(key: String): String {
return remoteConfig.getString(key)
}
fun getLongValue(key: String): Long {
return remoteConfig.getLong(key)
}
// Real-time updates (Firebase Remote Config 21.4.0+)
fun observeUpdates() {
remoteConfig.addOnConfigUpdateListener { configUpdate ->
if (configUpdate.updatedKeys.contains("feature_enabled")) {
remoteConfig.activate().addOnCompleteListener {
// Feature flag updated — apply new value
}
}
}
}
}
// Usage in Compose
@Composable
fun FeatureFlagContent(flagManager: FeatureFlagManager) {
val featureEnabled = remember { mutableStateOf(flagManager.isFeatureEnabled("new_ui")) }
LaunchedEffect(Unit) {
flagManager.fetchAndActivate()
featureEnabled.value = flagManager.isFeatureEnabled("new_ui")
}
if (featureEnabled.value) {
NewUI()
} else {
LegacyUI()
}
}
Output: Remote Config values update promptly with proper defaults.
Prevention
- Always call
fetchAndActivate()and wait for completion. - Set sensible defaults with
setDefaultsAsync(). - Use 0-second fetch interval in debug builds for testing.
- Use
addOnConfigUpdateListenerfor real-time feature flag updates.
Common Mistakes with Firebase remote config
- Forgetting
deriving (Show, Eq)on custom data types needed for debugging - Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
- Using
headandtailinstead of pattern matching, causing runtime errors on empty lists
These mistakes appear frequently in real-world Android code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro