This repository is a sample Android application that renders a home/news-style screen from server-provided UI data stored in Firebase Firestore. The goal is to demonstrate a simple Server-Driven UI (SDUI) approach in a modern Android stack using Jetpack Compose, Hilt, Kotlin Flow, and Firestore snapshot listeners.
Slide deck: https://speakerdeck.com/arrazyfathan/building-dynamic-interfaces-implementing-server-driven-ui-on-android
- A Compose screen whose content and presentation values are driven by Firestore documents
- Real-time UI updates via Firestore listeners and
Flow - A lightweight layered architecture: presentation -> domain -> data
- Dependency injection with Hilt
- A modern Android toolchain based on AGP 9.x, Gradle 9.x, Java 17, and Compose
- Kotlin
- Jetpack Compose
- Material 3
- Firebase Firestore
- Hilt
- Kotlin Flow / Coroutines
- Room
- Coil
- Navigation Compose
- KSP
The project currently uses a single app module with the following package layout:
app/src/main/java/com/arrazyfathan/serverdrivenui
├── data
│ ├── datasource
│ └── datasource/remote/firestore
├── di
├── domain
├── presenstation
└── utils
Notes:
- The package name
presenstationis spelled that way in the current codebase and is not a typo in this README. - The app uses Hilt entry points from
App.ktandMainActivity.kt.
The runtime flow is straightforward:
MainActivitysets Compose content and obtainsHomeViewModel.HomeViewModelrequests five UI sections from the repository:- top app bar
- featured image
- article content
- card links
- footer
RepositoryImplbridges Firestore result types into app-levelResources.FirestoreDatasourceImpllistens to Firestore documents usingaddSnapshotListener(...).- Compose collects
StateFlowvalues and renders the UI accordingly.
Relevant files:
The app reads from the home_screen collection and expects the following document IDs:
top_app_barfeatured_imagecontentcard_linksfooter
These constants are defined in Constants.kt.
Each document maps to a Kotlin model under data/datasource/model. The app also includes fallback/default content for some visual sections when server data is absent.
To build this project as it exists today, use:
- Android Studio with recent AGP 9.x support
- JDK 17
- Android SDK Platform 37 installed
- Gradle 9.5.0
- Android Gradle Plugin 9.2.1
The app module is currently configured with:
minSdk = 24targetSdk = 37compileSdk = 37
git clone <your-repo-url>
cd server-driven-uiAt minimum:
sdkmanager "platforms;android-37" "build-tools;37.0.0"Ensure Gradle and Android Studio are using JDK 17.
This project expects Firebase configuration through google-services.json in the app/ directory.
Checklist:
- Create a Firebase project
- Add an Android app with package name
com.arrazyfathan.serverdrivenui - Download
google-services.json - Place it at:
app/google-services.json - Enable Cloud Firestore
- Create the expected
home_screendocuments
The current release signing configuration in app/build.gradle.kts points to a local keystore path and sample credentials. Replace or remove it for your own environment before producing a release build.
From Android Studio:
- Sync Gradle
- Select a device or emulator
- Run the
appconfiguration
From the command line:
./gradlew :app:assembleDebugInstall on a connected device:
./gradlew :app:installDebug./gradlew help
./gradlew :app:assembleDebug
./gradlew :app:installDebug
./gradlew build --dry-run- Configuration cache is enabled in
gradle.properties. - The project has already been migrated to:
- Gradle
9.5.0 - AGP
9.2.1 - Kotlin Compose plugin
2.3.21
- Gradle
- Firebase KTX migration has been updated in code to use APIs from the main modules.
The sample screen includes:
- a top app bar
- a featured image and title block
- author and date metadata
- expandable article body text
- a footer that can render either:
- a card link component
- a carousel component
The footer behavior is controlled by Firestore data, which makes it the clearest example of the server-driven approach in this sample.
Hilt modules are defined in:
They provide:
FirebaseFirestoreFirestoreDatasourceRepository
This is a sample project, so a few tradeoffs are intentional or still rough:
- The SDUI model is section-based rather than a generalized component renderer
- The project is single-module
- Some fallback content is hardcoded in the client
- The current release signing config is sample/local-machine specific
- There is no formal test suite documenting the server contract yet
- Move dependency versions into a version catalog
- Add screenshots or a GIF to the README
- Document the Firestore document schema field-by-field
- Add tests for repository and ViewModel behavior
- Extract a more generic server-driven component model
- Clean up naming inconsistencies such as
presenstation
No license file is currently included in this repository. If you intend to share or publish it, add an explicit license.