/server-driven-compose

🧙 Server Driven Compose showcases server-driven UI approaches in Jetpack Compose with Firebase.

Primary LanguageKotlinApache License 2.0Apache-2.0

Server Driven Compose

License API Build Status Profile

🧙 Server Driven Compose showcases server-driven UI approaches in Jetpack Compose with Firebase.

The purpose of this repository is to demonstrate the following:

  • Implementing server-driven UI using Jetpack Compose and Firebase Realtime Database.
  • Defining rendering protocols (such as layout nodes, action handlers, and versioning) and consuming them as composable functions in Jetpack Compose.
  • Establishing component design systems for consuming rendering protocols on the client side, along with versioning systems for these design components.
  • Gaining a deeper understanding of the Firebase Realtime Database system.

✍️ Technical Content

If you're interested in the overall design systems and the implementation details of this project, check out the blog post below:

Tech stack & Open-source libraries

  • Minimum SDK level 21.
  • Kotlin based, utilizing Coroutines + Flow for asynchronous operations.
  • Jetpack Libraries:
    • Jetpack Compose: Android’s modern toolkit for declarative UI development.
    • Lifecycle: Observes Android lifecycles and manages UI states upon lifecycle changes.
    • ViewModel: Manages UI-related data and is lifecycle-aware, ensuring data survival through configuration changes.
    • Navigation: Facilitates screen navigation, complemented by Hilt Navigation Compose for dependency injection.
    • Hilt: Facilitates dependency injection.
  • Architecture:
    • MVVM Architecture (View - ViewModel - Model): Facilitates separation of concerns and promotes maintainability.
    • Repository Pattern: Acts as a mediator between different data sources and the application's business logic.
  • Firebase Android KTX: Kotlin & Compose-friendly Firebase extensions designed to help you focus on your business logic.
  • Retrofit2 & OkHttp3: Constructs REST APIs and facilitates paging network data retrieval.
  • ksp: Kotlin Symbol Processing API for code generation and analysis.
  • Landscapist Glide, animation, placeholder: A pluggable, highly optimized Jetpack Compose and Kotlin Multiplatform image loading library that fetches and displays network images with Glide, Coil, and Fresco.

Runing This Project on Your Side

You can run this project on your side following the guidelines below:

  1. First things first, download the following JSON file on your local PC: Gist: JSON demo for Timeline UI.

  2. Following the Firebase setup guidelines, download the google-services.json and place it into the app directory on this project.

  3. Next, set up the Firebase Realtime Database in your Firebase dashboard. Once that's done, you can import the JSON file like the image below:

import

  1. Next, create a file named secrets.properties in the root directory of this project, and copy & paste your Realtime Database URL into it, as shown in the example below:

import

REALTIME_DATABASE_URL=https://server-driven-compose-default-rtdb.asia-southeast1.firebasedatabase.app/
  1. Build the project.

Architecture

Server Driven Compose fetches data from Firebase Realtime Database and makes it an observable flow in the data layer. The presentation layer then takes this data and assembles it into components, which are formatted to be consumed by UIs as composable functions.

architecture

Component Design System

Server Driven Compose retrieves all rendering information from the backend (Firebase Realtime Database), allowing the client to focus solely on consuming the layout details. This approach lets you concentrate on "how to do (rendering)" rather than "what to do," a decision typically made by the product manager.

The code below shows how the main (timeline) screen is implemented in Jetpack Compose, showcasing its simplicity. It observes the UI component information from the backend server and consumes it according to the pre-built component design system. This makes the screen implementation very passive, allowing you to focus on how each component is rendered rather than deciding what to render.

Column(
  modifier = Modifier
    .background(ServerDrivenTheme.colors.background)
    .fillMaxSize()
    .padding(12.dp)
    .verticalScroll(state = rememberScrollState()),
  verticalArrangement = Arrangement.spacedBy(12.dp)
) {
  timelineUi.components.forEach { uiComponent ->
    uiComponent.Consume(
      version = timelineUi.version,
      navigator = { clickedComponent ->
        navigateToDetails.invoke(clickedComponent, timelineUi.version)
      }
    )
  }
}

Component Versioning

Server Driven Compose demonstrates a versioning system for each component and how to synchronize them with the application in real-time.

Design Patterns

Server Driven Compose adheres to the MVVM architecture and implements the Repository pattern, aligning with Google's official architecture guidance.

The architecture of Server Driven Compose is structured into two distinct layers: the UI layer and the data layer. Each layer fulfills specific roles and responsibilities, outlined as follows:

Server Driven Compose follows the principles outlined in the Guide to app architecture, making it an exemplary demonstration of architectural concepts in practical application.

Architecture Overview

architecture

  • Each layer adheres to the principles of unidirectional event/data flow: the UI layer sends user events to the data layer, and the data layer provides data streams to other layers.
  • The data layer operates autonomously from other layers, maintaining purity without dependencies on external layers.

This loosely coupled architecture enhances component reusability and app scalability, facilitating seamless development and maintenance.

UI Layer

architecture

The UI layer encompasses UI elements responsible for configuring screens for user interaction, alongside the ViewModel, which manages app states and restores data during configuration changes.

  • UI elements observe the data flow, ensuring synchronization with the underlying data layer.

Modularization

Server Driven Compose adopted modularization strategies below:

  • Reusability: Modulizing reusable codes properly enable opportunities for code sharing and limits code accessibility in other modules at the same time.
  • Parallel Building: Each module can be run in parallel and it reduces the build time.
  • Strict visibility control: Modules restrict to expose dedicated components and access to other layers, so it prevents they're being used outside the module
  • Decentralized focusing: Each developer team can assign their dedicated module and they can focus on their own modules.

For more information, check out the Guide to Android app modularization.

Find this repository useful? ❤️

Support it by joining stargazers for this repository. ⭐
Also, follow me on GitHub for my next creations! 🤩

License

Designed and developed by 2024 skydoves (Jaewoong Eum)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.