Skip to content

Latest commit

 

History

History
222 lines (159 loc) · 7.3 KB

File metadata and controls

222 lines (159 loc) · 7.3 KB

Server-Driven UI on Android with Jetpack Compose

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

What This Project Demonstrates

  • 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

Tech Stack

  • Kotlin
  • Jetpack Compose
  • Material 3
  • Firebase Firestore
  • Hilt
  • Kotlin Flow / Coroutines
  • Room
  • Coil
  • Navigation Compose
  • KSP

Project Structure

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 presenstation is spelled that way in the current codebase and is not a typo in this README.
  • The app uses Hilt entry points from App.kt and MainActivity.kt.

Architecture Overview

The runtime flow is straightforward:

  1. MainActivity sets Compose content and obtains HomeViewModel.
  2. HomeViewModel requests five UI sections from the repository:
    • top app bar
    • featured image
    • article content
    • card links
    • footer
  3. RepositoryImpl bridges Firestore result types into app-level Resources.
  4. FirestoreDatasourceImpl listens to Firestore documents using addSnapshotListener(...).
  5. Compose collects StateFlow values and renders the UI accordingly.

Relevant files:

Firestore Data Model

The app reads from the home_screen collection and expects the following document IDs:

  • top_app_bar
  • featured_image
  • content
  • card_links
  • footer

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.

Requirements

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 = 24
  • targetSdk = 37
  • compileSdk = 37

Setup

1. Clone the repository

git clone <your-repo-url>
cd server-driven-ui

2. Install required Android SDK components

At minimum:

sdkmanager "platforms;android-37" "build-tools;37.0.0"

3. Configure Java 17

Ensure Gradle and Android Studio are using JDK 17.

4. Firebase setup

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_screen documents

5. Review signing config

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.

Running the App

From Android Studio:

  • Sync Gradle
  • Select a device or emulator
  • Run the app configuration

From the command line:

./gradlew :app:assembleDebug

Install on a connected device:

./gradlew :app:installDebug

Useful Gradle Commands

./gradlew help
./gradlew :app:assembleDebug
./gradlew :app:installDebug
./gradlew build --dry-run

Current Build Notes

  • 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
  • Firebase KTX migration has been updated in code to use APIs from the main modules.

UI Behavior

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.

Dependency Injection

Hilt modules are defined in:

They provide:

  • FirebaseFirestore
  • FirestoreDatasource
  • Repository

Limitations

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

Suggested Next Improvements

  • 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

License

No license file is currently included in this repository. If you intend to share or publish it, add an explicit license.