Skip to content

How to Implement Android Splash Screen API in Jetpack Compose Apps

Problem

You’re building a Jetpack Compose app. You define your theme entirely in Kotlin code using MaterialTheme, avoiding XML themes entirely. Then you try to implement the Android 12 Splash Screen API, and suddenly you hit a wall: the API requires XML theme references.

The Confusion
My app theme is 100% Compose:
-> MaterialTheme defined in Kotlin
-> No XML themes anywhere
-> Colors, typography, shapes all in code
Splash Screen API wants:
-> Theme.SplashScreen in XML
-> postSplashScreenTheme reference
-> Theme inheritance from XML
What gives?

This post shows you exactly how to bridge this gap.

The Core Insight

A Reddit discussion on r/androiddev captured the key point:

“Use androidx support libraries even if your minSdk is Android 12+. The native Android UI layer (Activity/View system) is still XML-based, so the Splash Screen API needs XML theme references to function correctly.”

Even though Compose handles your UI, the splash screen operates at the Activity/View layer, which still expects XML themes. You cannot escape XML entirely for splash screens.

Why You Need the androidx Library

You might think: “My minSdk is 31 (Android 12), I can use the native API.”

Wrong. The androidx.core:core-splashscreen library provides backward compatibility and consistent behavior. More importantly, it handles edge cases that the native API doesn’t.

Add the dependency:

build.gradle.kts (Module: app)
dependencies {
implementation("androidx.core:core-splashscreen:1.0.1")
}

The Hybrid Solution: Minimal XML + Compose Theme

Here’s the complete implementation that bridges XML splash themes with your Compose-based app theme.

Step 1: Create the Splash Screen Theme (XML)

Create a minimal XML theme solely for splash screen purposes:

res/values/themes.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Splash screen theme - REQUIRED even for Compose apps -->
<style name="Theme.App.Splash" parent="Theme.SplashScreen">
<!-- Required: Set your app's main theme here -->
<item name="postSplashScreenTheme">@style/Theme.App</item>
<!-- Optional: Customize splash screen -->
<item name="windowSplashScreenBackground">@color/splash_background</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
<item name="windowSplashScreenAnimationDuration">500</item>
</style>
<!-- Minimal theme for post-splash transition -->
<!-- This doesn't define colors - your Compose theme does -->
<style name="Theme.App" parent="android:Theme.Material.NoActionBar">
<!-- Leave empty - your Compose MaterialTheme handles everything -->
</style>
</resources>

Step 2: Define Splash Resources

Create the drawable and color resources:

res/drawable/splash_icon.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="108dp"
android:height="108dp"
android:drawable="@mipmap/ic_launcher_round" />
</layer-list>
res/values/colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="splash_background">#FFFFFF</color>
</resources>

Step 3: Apply Theme to Launcher Activity

Update your AndroidManifest.xml:

AndroidManifest.xml
<application
android:theme="@style/Theme.App">
<!-- ... other attributes ... -->
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.App.Splash">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

The splash theme (Theme.App.Splash) is set on the activity, not the application. This ensures the splash screen shows before your Compose UI initializes.

Step 4: Install Splash Screen in MainActivity

MainActivity.kt
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Install splash screen BEFORE super.onCreate()
val splashScreen = installSplashScreen()
super.onCreate(savedInstanceState)
// Optional: Keep splash visible while loading data
var keepSplashOnScreen = true
splashScreen.setKeepOnScreenCondition { keepSplashOnScreen }
// Simulate loading (replace with your actual initialization)
lifecycleScope.launch {
// Initialize your app: database, preferences, etc.
initializeApp()
keepSplashOnScreen = false
}
setContent {
// Your Compose theme defined entirely in Kotlin
AppTheme {
NavHost(navController = rememberNavController()) {
// Your navigation graph
}
}
}
}
}

Step 5: Your Compose Theme (No Changes Needed)

Your existing Compose theme works as-is:

Theme.kt
@Composable
fun AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colorScheme = if (darkTheme) {
darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
)
} else {
lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
)
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
shapes = Shapes,
content = content
)
}

The postSplashScreenTheme in XML transitions to Theme.App, which is a minimal wrapper. Your AppTheme Composable then applies the actual visual styling.

Common Mistakes

Mistake 1: Skipping XML Entirely

WRONG: This won't work
// You cannot do this - the API requires XML theme
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen() // Crashes or does nothing
setContent {
AppTheme { /* ... */ }
}
}

The splash screen API reads theme attributes before your Compose code runs. No XML theme = no splash screen.

Mistake 2: Wrong Theme Hierarchy

WRONG: postSplashScreenTheme must reference XML theme
<style name="Theme.App.Splash" parent="ThemeSsplashScreen">
<!-- WRONG: Cannot reference Compose theme -->
<item name="postSplashScreenTheme">???</item>
</style>

You must have a real XML theme as the post-splash theme, even if it’s empty.

Mistake 3: Calling installSplashScreen() Late

WRONG: Must call before super.onCreate()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) // TOO LATE
installSplashScreen() // Won't work properly
setContent { /* ... */ }
}

Mistake 4: Ignoring OEM Quirks

Some device manufacturers modify the splash screen behavior. Test on multiple devices, especially Samsung, Xiaomi, and Huawei devices.

Mistake 5: Forgetting Animation Duration

WRONG: Animation duration applies to exit animation
<item name="windowSplashScreenAnimationDuration">0</item>

Setting this to 0 skips the exit animation entirely, which can feel jarring. A value of 200-500ms works well.

The Theme Transition Flow

Here’s what happens during app startup:

sequenceDiagram
participant System as Android System
participant Splash as Splash Screen
participant Activity as MainActivity
participant Compose as Compose UI
System->>Splash: Show Theme.App.Splash
Note over Splash: XML theme, before Activity
Splash->>Activity: Activity.onCreate()
Activity->>Activity: installSplashScreen()
Activity->>Activity: super.onCreate()
Note over Activity: Theme transitions to Theme.App
Activity->>Compose: setContent { AppTheme { } }
Note over Compose: MaterialTheme applied
Splash->>Compose: Splash exits with animation
Compose->>Compose: Your UI is visible

The XML theme (Theme.App.Splash) shows first, transitions to the minimal XML theme (Theme.App), then your Compose AppTheme takes over.

Handling Dynamic Colors (Android 12+)

If you use Material You dynamic colors:

MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
super.onCreate(savedInstanceState)
setContent {
val dynamicColor = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
val colorScheme = if (dynamicColor) {
dynamicColorScheme(this)
} else {
lightColorScheme()
}
MaterialTheme(
colorScheme = colorScheme,
content = { /* ... */ }
)
}
}

For the splash screen, use a static color that matches your brand:

res/values-31/themes.xml (Android 12+)
<style name="Theme.App.Splash" parent="ThemeSsplashScreen">
<item name="postSplashScreenTheme">@style/Theme.App</item>
<item name="windowSplashScreenBackground">@android:color/system_accent1_100</item>
</style>

Summary

In this post, I showed how to implement the Android Splash Screen API in a Jetpack Compose app. The key insight is that even with a 100% Compose-based theme, the splash screen API requires XML theme configuration because it operates at the Activity/View layer.

The solution involves:

  1. Adding androidx.core:core-splashscreen dependency
  2. Creating a minimal ThemeSsplashScreen XML theme
  3. Setting postSplashScreenTheme to transition to your app
  4. Installing the splash screen before super.onCreate()
  5. Letting your Compose MaterialTheme handle the actual visual styling

You cannot escape XML entirely for splash screens. Embrace the hybrid approach.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments