Back to skills
extension
Category: Development & EngineeringNo API key required

android-firebase

Firebase integration patterns for Android - Crashlytics, Analytics, Remote Config, FCM. Use when setting up crash reporting, analytics events, remote configuration, or push notifications.

personAuthor: jakexiaohubgithub

Android Firebase Skill

Firebase integration patterns: Crashlytics, Analytics, Remote Config, FCM.

When to Use

  • Setting up Firebase SDK
  • Implementing crash reporting
  • Adding analytics events
  • Using Remote Config
  • Setting up FCM (Push Notifications)

Setup

Dependencies

[versions]
firebase-bom = "33.8.0"

[libraries]
firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebase-bom" }
firebase-analytics = { module = "com.google.firebase:firebase-analytics-ktx" }
firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics-ktx" }
firebase-config = { module = "com.google.firebase:firebase-config-ktx" }
firebase-messaging = { module = "com.google.firebase:firebase-messaging-ktx" }

Initialization

// In Application class
FirebaseApp.initializeApp(this)

Crashlytics

// Log non-fatal exception
Firebase.crashlytics.recordException(exception)

// Custom keys for debugging
Firebase.crashlytics.setCustomKey("user_id", userId)
Firebase.crashlytics.setCustomKey("screen", currentScreen)

// Log message
Firebase.crashlytics.log("User clicked purchase button")

// Set user identifier
Firebase.crashlytics.setUserId(userId)

// Force crash (for testing)
throw RuntimeException("Test Crash")

Analytics

// Log standard event
Firebase.analytics.logEvent(FirebaseAnalytics.Event.SELECT_ITEM) {
    param(FirebaseAnalytics.Param.ITEM_ID, itemId)
    param(FirebaseAnalytics.Param.ITEM_NAME, itemName)
}

// Custom event
Firebase.analytics.logEvent("game_completed") {
    param("score", finalScore.toLong())
    param("level", currentLevel.toLong())
    param("time_spent", timeInSeconds.toLong())
}

// Screen tracking
Firebase.analytics.logEvent(FirebaseAnalytics.Event.SCREEN_VIEW) {
    param(FirebaseAnalytics.Param.SCREEN_NAME, screenName)
    param(FirebaseAnalytics.Param.SCREEN_CLASS, screenClass)
}

// User properties
Firebase.analytics.setUserProperty("premium_user", "true")
Firebase.analytics.setUserId(userId)

Remote Config

val remoteConfig = Firebase.remoteConfig
remoteConfig.setConfigSettingsAsync(remoteConfigSettings {
    minimumFetchIntervalInSeconds = 3600 // 1 hour
})

// Set defaults
remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults)

// Fetch and activate
remoteConfig.fetchAndActivate().addOnCompleteListener { task ->
    if (task.isSuccessful) {
        val featureEnabled = remoteConfig.getBoolean("new_feature_enabled")
        val welcomeMessage = remoteConfig.getString("welcome_message")
        val maxRetries = remoteConfig.getLong("max_retries")
    }
}

// Real-time config (auto-update)
remoteConfig.addOnConfigUpdateListener(object : ConfigUpdateListener {
    override fun onUpdate(configUpdate: ConfigUpdate) {
        remoteConfig.activate()
    }
    override fun onError(error: FirebaseRemoteConfigException) {}
})

FCM (Push Notifications)

class MyFirebaseMessagingService : FirebaseMessagingService() {
    override fun onNewToken(token: String) {
        // Send token to server
        sendTokenToServer(token)
    }

    override fun onMessageReceived(message: RemoteMessage) {
        // Handle notification
        message.notification?.let { notification ->
            showNotification(notification.title, notification.body)
        }

        // Handle data payload
        message.data.let { data ->
            handleDataPayload(data)
        }
    }
}

// Get current token
Firebase.messaging.token.addOnCompleteListener { task ->
    if (task.isSuccessful) {
        val token = task.result
    }
}

// Subscribe to topic
Firebase.messaging.subscribeToTopic("news")

Version Compatibility

| Firebase BOM | Min SDK | Compile SDK | |--------------|---------|-------------| | 33.8.0 | 21 | 35 | | 33.0.0 | 21 | 34 | | 32.0.0 | 19 | 33 |

Error Handling

// Remote Config error handling
remoteConfig.fetchAndActivate()
    .addOnSuccessListener { activated ->
        if (activated) Timber.d("Config activated")
        else Timber.d("Config already up to date")
    }
    .addOnFailureListener { e ->
        when (e) {
            is FirebaseRemoteConfigException ->
                Timber.w("Remote config fetch failed: ${e.code}")
            else -> Timber.e("Unexpected error: ${e.message}")
        }
        // Use cached/default values
    }

// Crashlytics non-fatal reporting
try {
    riskyOperation()
} catch (e: Exception) {
    Firebase.crashlytics.recordException(e)
    // Handle gracefully
}

Troubleshooting

| Issue | Solution | |-------|----------| | Events not showing | Wait 24h or use DebugView | | Crashes not reporting | Check google-services.json | | FCM not receiving | Verify token registration | | Config not updating | Check fetch interval |

Security Checklist

  • [ ] Disable Crashlytics in debug builds (optional)
  • [ ] No PII in crash logs or analytics
  • [ ] Validate FCM token before use
  • [ ] Use App Check for backend protection
  • [ ] Review analytics data retention settings

Best Practices

  • Enable Crashlytics in release builds only
  • Use custom events sparingly (500 limit per app)
  • Cache Remote Config values locally
  • Handle FCM token refresh
  • Set user ID consistently across services
  • Use DebugView for testing analytics

References

Use Firebase for robust analytics and crash reporting.