Android Applications
Complete guide to integrating Chassis design tokens into Android applications using XML resources, Gradle, Maven, and platform-specific best practices.
This documentation was generated with AI assistance and has not been fully tested in production environments. While the content is based on standard platform practices and design token conventions, specific implementation details, code examples, or integration steps may require adjustments for your project setup.
If you encounter issues or inaccuracies, please report them via our issue tracker or refer to the official platform documentation for verification.
Overview
Chassis design tokens for Android are generated as XML resource files that integrate seamlessly with the Android resource system. Tokens are automatically converted to appropriate Android resource types (color, dimen, string, integer) and support theme overlays for light/dark modes.
Key Benefits:
- Native Resources: Standard Android XML resources (colors.xml, dimens.xml)
- Resource References: Automatic
@color,@dimenreferences - Theme Support: Built-in light/dark mode with theme overlays
- Type Safe: Compile-time resource validation
- IDE Support: Android Studio autocomplete and preview
- Gradle Integration: Easy dependency management
- Material Design: Compatible with Material Design Components
This guide covers integration using Git submodules, Gradle dependencies, Maven, and manual resource inclusion.
Token Output Format
Tokens are generated as Android XML resource files:
<?xml version="1.0" encoding="UTF-8"?>
<!-- main.xml -->
<resources>
<dimen name="cx_space_base_8">8dp</dimen>
<dimen name="cx_space_base_16">16dp</dimen>
<dimen name="cx_border_radius_base_8">8dp</dimen>
<dimen name="cx_size_button_medium_height">44dp</dimen>
<string name="cx_typography_font_family_text">Inter</string>
<string name="cx_typography_font_weight_text_normal">regular</string>
</resources>
<?xml version="1.0" encoding="UTF-8"?>
<!-- color-light.xml -->
<resources>
<color name="cx_color_context_default_bg_main">#FFFFFFFF</color>
<color name="cx_color_context_default_fg_main">#FF1C2021</color>
<color name="cx_color_context_primary_bg_solid">#FF00A4CC</color>
<color name="cx_color_context_primary_fg_solid">#FFFFFFFF</color>
</resources>
Generated Files:
main.xml- Base tokens (dimensions, strings)string.xml- String-only tokens (fonts, assets)color-light.xml- Light theme colorscolor-dark.xml- Dark theme colorsnumber-large.xml- Large screen dimensionsnumber-medium.xml- Medium screen dimensionsnumber-small.xml- Small screen dimensions
Installation Methods
Method 1: Git Submodule (Recommended)
Add the tokens repository as a Git submodule:
# Navigate to your Android project directory
cd YourApp
# Add tokens as submodule
git submodule add https://github.com/chassis-ui/tokens.git submodules/chassis-tokens
# Initialize and update
git submodule update --init --recursive
Build tokens for Android:
cd submodules/chassis-tokens
npm install -g pnpm
pnpm install
pnpm tokens --brand chassis --app yourapp --platform android
Generated files will be in submodules/chassis-tokens/dist/android/yourapp/chassis/.
Configure Gradle to use tokens:
// app/build.gradle
android {
sourceSets {
main {
res.srcDirs += [
'../submodules/chassis-tokens/dist/android/yourapp/chassis'
]
}
}
}
Update submodule:
cd submodules/chassis-tokens
git pull origin main
pnpm tokens --brand chassis --app yourapp --platform android
Method 2: Gradle Dependency (AAR)
Publish tokens as an Android Library (AAR):
1. Create library module:
# In your tokens repository
mkdir -p android-library/tokens/src/main/res/values
cp dist/android/yourapp/chassis/*.xml android-library/tokens/src/main/res/values/
2. Create build.gradle:
// android-library/tokens/build.gradle
plugins {
id 'com.android.library'
}
android {
namespace 'com.chassis.tokens'
compileSdk 34
defaultConfig {
minSdk 21
targetSdk 34
}
buildTypes {
release {
minifyEnabled false
}
}
}
3. Add to your app:
// settings.gradle
include ':tokens'
project(':tokens').projectDir = new File('../chassis-tokens/android-library/tokens')
// app/build.gradle
dependencies {
implementation project(':tokens')
}
Method 3: Maven Local
Publish tokens to local Maven repository:
// tokens/build.gradle
apply plugin: 'maven-publish'
publishing {
publications {
release(MavenPublication) {
from components.release
groupId = 'com.chassis'
artifactId = 'tokens'
version = '0.1.0'
}
}
repositories {
mavenLocal()
}
}
Publish:
./gradlew publishToMavenLocal
Use in your app:
// app/build.gradle
repositories {
mavenLocal()
}
dependencies {
implementation 'com.chassis:tokens:0.1.0'
}
Method 4: Manual Resource Copy
For simple projects, copy XML files directly:
- Build tokens:
pnpm tokens --platform android - Copy all
.xmlfiles fromdist/android/yourapp/chassis/toapp/src/main/res/values/ - Sync Gradle
- Rebuild when tokens change
Manual copying requires rebuilding when tokens change. Use submodules or Gradle dependencies for better workflow.
Using Tokens in XML Layouts
Colors
<!-- activity_main.xml -->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/cx_color_context_default_bg_main">
<TextView
android:id="@+id/titleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World"
android:textColor="@color/cx_color_context_default_fg_main"
android:textSize="@dimen/cx_typography_font_size_text_3xlarge"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_margin="@dimen/cx_space_base_16" />
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardBackgroundColor="@color/cx_color_context_default_bg_evident"
app:cardCornerRadius="@dimen/cx_border_radius_base_8"
app:cardElevation="@dimen/cx_space_base_4"
android:layout_margin="@dimen/cx_space_base_16"
app:layout_constraintTop_toBottomOf="@id/titleText">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Card content"
android:padding="@dimen/cx_space_base_16"
android:textColor="@color/cx_color_context_default_fg_main" />
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>
Buttons
<!-- Custom button style -->
<com.google.android.material.button.MaterialButton
android:id="@+id/primaryButton"
android:layout_width="wrap_content"
android:layout_height="@dimen/cx_size_button_medium_height"
android:text="Click Me"
android:textColor="@color/cx_color_context_primary_fg_solid"
app:backgroundTint="@color/cx_color_context_primary_bg_solid"
app:cornerRadius="@dimen/cx_border_radius_button_main"
android:paddingStart="@dimen/cx_space_button_padding_inline"
android:paddingEnd="@dimen/cx_space_button_padding_inline"
app:strokeWidth="@dimen/cx_border_width_button_main"
app:strokeColor="@color/cx_color_context_primary_border_main" />
Using Tokens in Kotlin/Java
Accessing Resources in Kotlin
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Access colors
val bgColor = ContextCompat.getColor(this, R.color.cx_color_context_default_bg_main)
val fgColor = ContextCompat.getColor(this, R.color.cx_color_context_default_fg_main)
// Access dimensions
val spacing = resources.getDimension(R.dimen.cx_space_base_16)
val radius = resources.getDimension(R.dimen.cx_border_radius_base_8)
// Access strings
val fontFamily = resources.getString(R.string.cx_typography_font_family_text)
// Apply to views
findViewById<TextView>(R.id.titleText).apply {
setTextColor(fgColor)
textSize = resources.getDimension(R.dimen.cx_typography_font_size_text_xlarge)
setPadding(
spacing.toInt(),
spacing.toInt(),
spacing.toInt(),
spacing.toInt()
)
}
}
}
Custom View with Tokens
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.View
import androidx.core.content.ContextCompat
class CustomCardView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = ContextCompat.getColor(context, R.color.cx_color_context_default_bg_evident)
style = Paint.Style.FILL
}
private val cornerRadius = resources.getDimension(R.dimen.cx_border_radius_base_8)
private val padding = resources.getDimension(R.dimen.cx_space_base_16)
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawRoundRect(
padding, padding,
width - padding, height - padding,
cornerRadius, cornerRadius,
paint
)
}
}
Java Example
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Access resources
int bgColor = ContextCompat.getColor(this, R.color.cx_color_context_default_bg_main);
float spacing = getResources().getDimension(R.dimen.cx_space_base_16);
// Apply to view
TextView titleText = findViewById(R.id.titleText);
titleText.setTextColor(ContextCompat.getColor(this, R.color.cx_color_context_default_fg_main));
titleText.setPadding(
(int) spacing,
(int) spacing,
(int) spacing,
(int) spacing
);
}
}
Using Tokens in Jetpack Compose
Create Theme Extension
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.sp
object ChassisTokens {
// Colors
val ColorBgMain @Composable get() = colorResource(R.color.cx_color_context_default_bg_main)
val ColorFgMain @Composable get() = colorResource(R.color.cx_color_context_default_fg_main)
val ColorPrimaryBg @Composable get() = colorResource(R.color.cx_color_context_primary_bg_solid)
val ColorPrimaryFg @Composable get() = colorResource(R.color.cx_color_context_primary_fg_solid)
// Spacing
val Spacing8 @Composable get() = dimensionResource(R.dimen.cx_space_base_8)
val Spacing16 @Composable get() = dimensionResource(R.dimen.cx_space_base_16)
val Spacing24 @Composable get() = dimensionResource(R.dimen.cx_space_base_24)
// Border Radius
val Radius8 @Composable get() = dimensionResource(R.dimen.cx_border_radius_base_8)
// Typography
val FontSizeMedium @Composable get() = dimensionResource(R.dimen.cx_typography_font_size_text_medium).value.sp
val FontSizeLarge @Composable get() = dimensionResource(R.dimen.cx_typography_font_size_text_large).value.sp
}
Using in Composables
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@Composable
fun CardExample() {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(ChassisTokens.Spacing16)
.clip(RoundedCornerShape(ChassisTokens.Radius8))
.background(ChassisTokens.ColorBgMain)
) {
Text(
text = "Card Title",
color = ChassisTokens.ColorFgMain,
fontSize = ChassisTokens.FontSizeLarge,
modifier = Modifier.padding(ChassisTokens.Spacing16)
)
Button(
onClick = { /* Handle click */ },
colors = ButtonDefaults.buttonColors(
containerColor = ChassisTokens.ColorPrimaryBg,
contentColor = ChassisTokens.ColorPrimaryFg
),
modifier = Modifier
.padding(ChassisTokens.Spacing16)
.height(dimensionResource(R.dimen.cx_size_button_medium_height))
) {
Text("Click Me")
}
}
}
Theme Support (Light/Dark Mode)
Using Resource Qualifiers
Android automatically handles theme switching using resource qualifiers:
res/
├── values/
│ ├── main.xml # Base tokens
│ └── colors.xml # Light mode colors (rename color-light.xml)
└── values-night/
└── colors.xml # Dark mode colors (rename color-dark.xml)
Setup:
- Copy
color-light.xmltores/values/colors.xml - Copy
color-dark.xmltores/values-night/colors.xml - Android will automatically use the appropriate file based on system theme
Material Theme Integration
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.colorResource
@Composable
fun ChassisTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colorScheme = if (darkTheme) {
darkColorScheme(
primary = colorResource(R.color.cx_color_context_primary_bg_solid),
onPrimary = colorResource(R.color.cx_color_context_primary_fg_solid),
background = colorResource(R.color.cx_color_context_default_bg_main),
onBackground = colorResource(R.color.cx_color_context_default_fg_main)
)
} else {
lightColorScheme(
primary = colorResource(R.color.cx_color_context_primary_bg_solid),
onPrimary = colorResource(R.color.cx_color_context_primary_fg_solid),
background = colorResource(R.color.cx_color_context_default_bg_main),
onBackground = colorResource(R.color.cx_color_context_default_fg_main)
)
}
MaterialTheme(
colorScheme = colorScheme,
content = content
)
}
Force Theme Mode
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Force light mode
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
// Force dark mode
// AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
// Follow system
// AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
setContentView(R.layout.activity_main)
}
}
Responsive Design
Screen Size Qualifiers
Organize tokens by screen size:
res/
├── values/ # Default (small screens)
│ └── dimens.xml # number-small.xml
├── values-sw600dp/ # Tablets (7")
│ └── dimens.xml # number-medium.xml
└── values-sw720dp/ # Large tablets (10")
└── dimens.xml # number-large.xml
Dimension Resources
<!-- res/values/dimens.xml (small screens) -->
<resources>
<dimen name="cx_space_container_padding">12dp</dimen>
<dimen name="cx_typography_font_size_heading">24sp</dimen>
</resources>
<!-- res/values-sw600dp/dimens.xml (tablets) -->
<resources>
<dimen name="cx_space_container_padding">16dp</dimen>
<dimen name="cx_typography_font_size_heading">28sp</dimen>
</resources>
<!-- res/values-sw720dp/dimens.xml (large tablets) -->
<resources>
<dimen name="cx_space_container_padding">24dp</dimen>
<dimen name="cx_typography_font_size_heading">32sp</dimen>
</resources>
Best Practices
Do's
✅ Use resource references: Always use @color, @dimen references
✅ Follow naming conventions: Maintain consistent cx_ prefix
✅ Support dark mode: Use values-night for dark theme
✅ Organize by screen size: Use qualifier directories for responsive design
✅ Version control tokens: Use Git submodules or Maven versioning
✅ Automate builds: Set up CI/CD for token generation
Don'ts
❌ Don't hardcode values: Always use tokens, never magic numbers
❌ Don't modify generated files: Changes will be overwritten
❌ Don't mix token versions: Keep tokens synchronized
❌ Don't skip resource qualifiers: Implement proper theme and size variants
❌ Don't ignore accessibility: Use tokens with proper contrast
Troubleshooting
Resource Not Found
Problem: Resources$NotFoundException
Solution: Ensure tokens are properly included in build:
android {
sourceSets {
main.res.srcDirs += 'path/to/tokens'
}
}
Run: ./gradlew clean build
Color Format Issues
Problem: Colors appear incorrect
Solution: Verify ARGB format in XML:
<!-- Correct format: #AARRGGBB -->
<color name="cx_color_primary">#FF00A4CC</color>
Dimension Conversion
Problem: dp/sp values don't scale properly
Solution: Use proper units:
dpfor dimensions, margins, paddingspfor text sizespxonly when needed (rare)
Build Performance
Problem: Slow builds with many token files
Solution: Split tokens and use only needed resources:
android {
defaultConfig {
resConfigs "en", "xxhdpi"
}
}
Example Project Structure
YourApp/
├── app/
│ ├── build.gradle
│ └── src/
│ └── main/
│ ├── java/
│ ├── res/
│ │ ├── layout/
│ │ ├── values/
│ │ │ └── colors.xml (from color-light.xml)
│ │ └── values-night/
│ │ └── colors.xml (from color-dark.xml)
│ └── AndroidManifest.xml
├── submodules/
│ └── chassis-tokens/
│ └── dist/
│ └── android/
│ └── yourapp/
│ └── chassis/
│ ├── main.xml
│ ├── string.xml
│ ├── color-light.xml
│ ├── color-dark.xml
│ └── number-large.xml
├── build.gradle
└── settings.gradle
CI/CD Integration
Automate token generation in your CI pipeline:
# .github/workflows/android-build.yml
name: Android CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install pnpm
run: npm install -g pnpm
- name: Generate Tokens
run: |
cd submodules/chassis-tokens
pnpm install
pnpm tokens --platform android --brand chassis --app yourapp
- name: Setup JDK
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '17'
- name: Build Android App
run: ./gradlew assembleDebug
Next Steps
- Learn about token structure and naming
- Explore design token categories
- Understand token transformation and build process
- See cross-platform consistency