Article published on Medium
In modern app development, the ability to update UI components without deploying new app versions is increasingly important. While solutions like React Native and Flutter offer this capability, they often require learning new frameworks or languages. Compose Remote Layout bridges this gap for Kotlin Multiplatform applications by enabling dynamic UI updates while staying within the Compose ecosystem.
This library was created to solve several key challenges:
- The need for rapid UI iterations without app store submissions
- A/B testing requirements for UI components
- Platform-specific UI customization from a central source
- Real-time UI updates for critical changes
The compose-remote-layout
module provides several core features:
-
Component System
- Built-in support for basic Compose components (Column, Row, Box, Text, Button, Card)
- All components can be defined and modified through JSON
- Component properties map directly to Compose parameters
-
Dynamic Updates
- Load layouts from remote sources (API, Firebase, local files)
- Update UI without app redeployment
- Handle layout changes in real-time
-
Value Binding
- Dynamic text updates using the BindsValue system
- Template-based value substitution
- Real-time value changes support
-
Modifier System
- Comprehensive modifier support matching Compose capabilities
- Scoped modifiers for specific component types
- JSON-based modifier definition
-
Custom Components
- Register custom Composable functions
- Map JSON definitions to custom UI elements
- Pass custom parameters and handle specific logic
-
iOS Support
- Independent iOS implementation using SwiftUI
- Swift Package Manager integration
0221.mp4
Add the dependencies to your build.gradle.kts
:
// Kotlin Multiplatform
implementation("io.github.utsmannn:compose-remote-layout:{version}")
// Choose platform-specific implementations as needed:
implementation("io.github.utsmannn:compose-remote-layout-android:{version}")
implementation("io.github.utsmannn:compose-remote-layout-jvm:{version}")
implementation("io.github.utsmannn:compose-remote-layout-iosx64:{version}")
implementation("io.github.utsmannn:compose-remote-layout-iosarm64:{version}")
implementation("io.github.utsmannn:compose-remote-layout-js:{version}")
For iOS projects without Kotlin Multiplatform, use Swift Package Manager:
Once you have your Swift package set up, adding ComposeRemoteLayoutSwift as a dependency is as easy as adding it to the dependencies value of your Package.swift or the Package list in Xcode.
dependencies: [
.package(url: "https://github.com/utsmannn/compose-remote-layout-swift.git", .upToNextMajor(from: "0.0.1-alpha05"))
]
Or add it via Xcode:
- Open your project in Xcode
- Go to File > Swift Packages > Add Package Dependency
- Enter the package URL:
https://github.com/utsmannn/compose-remote-layout-swift.git
- Select the version you want to use (0.0.1-alpha05)
- Click Finish
- Add
import ComposeRemoteLayoutSwift
to your Swift files - Build your project
See: compose-remote-layout-swift
Basic implementation using built-in components:
@Composable
fun MyScreen(layoutJson: String) {
val component = createLayoutComponent(layoutJson)
DynamicLayout(
component = component,
onClickHandler = { clickId ->
// Handle click events
}
)
}
Example JSON layout:
{
"column": {
"modifier": {
"base": {
"fillMaxWidth": true,
"padding": {
"all": 16
}
}
},
"children": [
{
"text": {
"content": "Hello World"
}
}
]
}
}
Create and register custom components:
// Register during app initialization
CustomNodes.register("banner") { param ->
Column(
modifier = param.modifier
) {
Text(
text = param.data["title"] ?: "unknown",
style = MaterialTheme.typography.h2
)
Spacer(Modifier.height(8.dp))
Text(
text = param.data["message"] ?: "unknown"
)
}
}
Use in JSON:
{
"banner": {
"title": "Welcome",
"message": "This is a custom banner",
"modifier": {
"base": {
"padding": {
"all": 16
}
}
}
}
}
The library supports extensive modifiers through JSON:
"modifier": {
"base": {
"width": 200,
"height": 100,
"padding": {
"all": 16
},
"background": {
"color": "#FF0000",
"shape": "roundedcorner",
"radius": 8
}
}
}
Different components support specific modifiers:
// Column-specific modifiers
{
"column": {
"modifier": {
"base": {
"fillMaxWidth": true
},
"verticalArrangement": "spaceBetween",
"horizontalAlignment": "center"
}
}
}
// Row-specific modifiers
{
"row": {
"modifier": {
"horizontalArrangement": "spaceBetween",
"verticalAlignment": "center"
}
}
}
The value binding system manages dynamic content updates:
@Composable
fun CounterExample() {
val bindsValue = remember { BindsValue() }
var counter by remember { mutableStateOf(0) }
LaunchedEffect(counter) {
bindsValue.setValue("counter", counter)
}
Column {
DynamicLayout(
component = createLayoutComponent(
"""
{
"text": {
"content": "{counter}"
}
}
"""
),
bindValue = bindsValue
)
Button(onClick = { counter++ }) {
Text("Increment")
}
}
}
The event system handles user interactions:
@Composable
fun ButtonExample() {
DynamicLayout(
component = createLayoutComponent(
"""
{
"button": {
"content": "Click Me",
"clickId": "main_button"
}
}
"""
),
onClickHandler = { clickId ->
when (clickId) {
"main_button" -> {
// Handle click
}
}
}
)
}
The repository includes a Firebase sample project demonstrating:
- Remote Config Setup: Integration with Firebase Remote Config
- Real-time Updates: Layout updates without app deployment
- Cross-platform Support: Implementation for Android and iOS
The jsonBuilderWeb
module provides a web interface for:
- Creating and editing layouts
- Real-time preview of changes
- Schema validation
- Url push config integration
To run the JSON builder:
./gradlew :jsonBuilderWeb:jsBrowserRun
The
remote-config-server
in
the jsonBuilderWeb
module provides:
- Local development server for testing
- Firebase Remote Config simulation
- API endpoints for layout updates
- Configuration management interface
To run the remote config server:
npm run start
This library can handle various scenarios:
-
A/B Testing
- Test different layouts with user segments
- Gather metrics on UI performance
- Quick iteration on designs
-
Dynamic Content
- Seasonal UI changes
- Feature announcements
- Promotional content
-
Platform Customization
- Platform-specific layouts
- Device-specific optimizations
- Regional variations
-
Rapid Iterations
- Quick fix for UI issues
- New feature rollouts
- Experimental features
This library is currently in alpha stage (version {version}) and has several important considerations:
- Production Use: Not recommended for production applications at this time
- API Stability: The API may change significantly between versions
- Performance: Not fully optimized for large-scale applications
- Testing: Limited real-world testing and validation
- Documentation: May be incomplete or subject to changes
We recommend:
- Using this library for experimental projects
- Contributing feedback and bug reports
- Waiting for stable releases before production use
- Testing thoroughly in your specific use case
Please report issues and suggestions through the GitHub repository.