Firebase & Cloud Services
Firebase is Google's backend-as-a-service platform — you get auth, a real-time database, file storage, push notifications, analytics, and crash reporting without spinning up servers. For solo developers and small teams shipping production apps, Firebase often replaces an entire backend.
Topic 1 · Authentication
Setup & configuration
- Create a Firebase project at console.firebase.google.com.
- Add your Android app — supply the package name and SHA-1.
- Download
google-services.jsonintoapp/(never commit it to public repos). - Apply plugins:
// settings.gradle.kts
plugins {
id("com.google.gms.google-services") version "4.4.2" apply false
id("com.google.firebase.crashlytics") version "3.0.2" apply false
}
// app/build.gradle.kts
plugins {
id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
}
dependencies {
implementation(platform("com.google.firebase:firebase-bom:33.5.0")) // BoM = consistent versions
implementation("com.google.firebase:firebase-auth-ktx")
implementation("com.google.firebase:firebase-firestore-ktx")
implementation("com.google.firebase:firebase-storage-ktx")
implementation("com.google.firebase:firebase-messaging-ktx")
implementation("com.google.firebase:firebase-analytics-ktx")
implementation("com.google.firebase:firebase-crashlytics-ktx")
implementation("com.google.firebase:firebase-config-ktx")
}
Email/password, Google Sign-In, Phone OTP
class AuthRepository @Inject constructor(
private val auth: FirebaseAuth
) {
val currentUser: Flow<FirebaseUser?> = callbackFlow {
val listener = FirebaseAuth.AuthStateListener { trySend(it.currentUser) }
auth.addAuthStateListener(listener)
awaitClose { auth.removeAuthStateListener(listener) }
}
suspend fun signUp(email: String, password: String): Result<FirebaseUser> = runCatching {
auth.createUserWithEmailAndPassword(email, password).await().user!!
}
suspend fun signIn(email: String, password: String): Result<FirebaseUser> = runCatching {
auth.signInWithEmailAndPassword(email, password).await().user!!
}
suspend fun signInWithGoogle(idToken: String): Result<FirebaseUser> = runCatching {
val credential = GoogleAuthProvider.getCredential(idToken, null)
auth.signInWithCredential(credential).await().user!!
}
fun signOut() = auth.signOut()
}
For Google Sign-In on Android, use the Credential Manager API (not
the deprecated GoogleSignInClient) — it integrates with passkeys and
Sign-In with Google in one flow.
For Phone OTP, Firebase handles SMS delivery, code verification, and auto-retrieval. Always require App Check in production to prevent abuse.
Topic 2 · Database & Storage
Cloud Firestore — CRUD, queries, real-time listeners
Firestore is a document-oriented NoSQL database with real-time sync, offline support, and granular security rules. Data lives in collections of documents:
users (collection)
└── userId123 (document)
├── name: "Aarav"
├── email: "a@x.com"
└── posts (subcollection)
└── postId456 (document)
├── title: "Hello"
└── createdAt: Timestamp
class PostRepository @Inject constructor(
private val db: FirebaseFirestore
) {
private val posts = db.collection("posts")
suspend fun create(post: Post): String {
val ref = posts.add(post.toMap()).await()
return ref.id
}
fun observeFeed(userId: String): Flow<List<Post>> = callbackFlow {
val sub = posts
.whereEqualTo("authorId", userId)
.orderBy("createdAt", Query.Direction.DESCENDING)
.limit(50)
.addSnapshotListener { snap, err ->
if (err != null) { close(err); return@addSnapshotListener }
trySend(snap?.documents.orEmpty().mapNotNull { it.toPost() })
}
awaitClose { sub.remove() }
}
}
Security rules are non-negotiable — they're your real backend authorization layer:
// firestore.rules
rules_version = '2';
service cloud.firestore {
match /databases/{db}/documents {
match /posts/{postId} {
allow read: if true; // public posts
allow create: if request.auth != null
&& request.resource.data.authorId == request.auth.uid;
allow update, delete: if resource.data.authorId == request.auth.uid;
}
}
}
Cloud Storage — file upload & download
class MediaRepository @Inject constructor(
private val storage: FirebaseStorage
) {
suspend fun uploadAvatar(userId: String, bytes: ByteArray): String {
val ref = storage.reference.child("avatars/$userId.jpg")
ref.putBytes(bytes).await()
return ref.downloadUrl.await().toString()
}
}
Apply Storage Security Rules just like Firestore — restrict who can read, write, and to which paths.
Topic 3 · Services
Push notifications with FCM
Firebase Cloud Messaging delivers messages to your app — both when the app is running and when it's not.
class AppMessagingService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
// Persist token in your backend so you can target this device
ServiceLocator.tokenSync.uploadToken(token)
}
override fun onMessageReceived(message: RemoteMessage) {
// Data-only payloads always reach this method.
// Notification payloads bypass it when the app is in background.
showNotification(
title = message.notification?.title ?: message.data["title"].orEmpty(),
body = message.notification?.body ?: message.data["body"].orEmpty(),
deepLink = message.data["deepLink"]
)
}
}
<!-- AndroidManifest.xml -->
<service
android:name=".messaging.AppMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
Analytics, Crashlytics, Remote Config
// Analytics — log custom events
Firebase.analytics.logEvent("checkout_started") {
param("cart_value", cart.totalCents.toLong())
param("item_count", cart.items.size.toLong())
}
// Crashlytics — capture non-fatal errors with context
Firebase.crashlytics.setUserId(currentUser.id)
Firebase.crashlytics.setCustomKey("subscription_tier", "pro")
runCatching { riskyOperation() }
.onFailure { Firebase.crashlytics.recordException(it) }
// Remote Config — change values without shipping a new APK
val remoteConfig = Firebase.remoteConfig.apply {
setConfigSettingsAsync(remoteConfigSettings { minimumFetchIntervalInSeconds = 3600 })
setDefaultsAsync(R.xml.remote_defaults)
}
remoteConfig.fetchAndActivate().await()
val showNewCheckout = remoteConfig.getBoolean("show_new_checkout")
Companion services
Email, phone, Google, Apple, Facebook, anonymous — managed for you with secure session handling.
Document store with offline cache, real-time listeners, and granular security rules.
Send to single devices, topics, or millions of users. Free at any scale.
Symbolicated stack traces, breadcrumbs, custom keys — see exactly what users hit.
A/B tests, feature flags, kill switches without a Play Store release.
Verify requests come from your real app via Play Integrity.
Key takeaways
Practice exercises
- 01
Email + Google sign-in
Build an auth screen with Firebase Auth + Credential Manager. Persist the FirebaseUser as a Flow in your AuthRepository.
- 02
Firestore feed
Build a real-time chat collection with security rules: anyone can read, only authenticated users can post their own messages.
- 03
Push deep link
Send an FCM message with a deepLink data field; tap the notification to open the matching screen.
Next module
Continue to Module 08 — Advanced Android Components to learn services, WorkManager, sensors, biometrics, and Glance widgets.