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.
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:
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:
<?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:
<?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><?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:
<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
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:
@Composablefun 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
// You cannot do this - the API requires XML themeoverride 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
<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
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
<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 visibleThe 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:
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:
<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:
- Adding
androidx.core:core-splashscreendependency - Creating a minimal
ThemeSsplashScreenXML theme - Setting
postSplashScreenThemeto transition to your app - Installing the splash screen before
super.onCreate() - Letting your Compose
MaterialThemehandle 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:
- 👨💻 Reddit: Splash Screen API with Compose-only Theme
- 👨💻 Android Splash Screen API Documentation
- 👨💻 androidx.core:splashscreen Library
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments