
Automates native splash asset generation and creates a matching runtime transition layer to eliminate startup flicker; single-build config, project file patching and dark‑mode support.
Professional Splash Screens for Compose Multiplatform, configured in seconds.
Creating a seamless startup experience in Compose Multiplatform is notoriously difficult. Between the native Android SplashScreen API and iOS UILaunchScreen, developers often face a "white flash" gap between the native boot sequence and the Jetpack Compose Multiplatform runtime.
KMP Splash bridges this gap. It automates the generation of native splash assets and provides a Compose-ready transition layer, ensuring your app feels premium from the very first pixel.
build.gradle.kts.Assets.xcassets for iOS and themes.xml for Android.SplashConfig composable to prevent the flicker when shifting from native boot to Compose UI..pbxproj and Info.plist automatically. No more Storyboards.androidx.core:core-splashscreen 1.2.0+
UILaunchScreen plist key)Ensure you have mavenCentral() in your settings.gradle.kts:
pluginManagement {
repositories {
google()
gradlePluginPortal()
mavenCentral()
}
}
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}In your gradle/libs.versions.toml:
[versions]
kmpSplash = "0.2.1"
[libraries]
kmpSplash-runtime = { module = "io.github.kmpbits:splash-runtime", version.ref = "kmpSplash" }
[plugins]
kmpSplash = { id = "io.github.kmpbits.splash", version.ref = "kmpSplash" }In your Compose App module build.gradle.kts:
plugins {
alias(libs.plugins.kmpSplash)
}
splashScreen {
backgroundColor = SplashColor.hex("#FFFFFF") // Light mode background
backgroundColorNight = SplashColor.hex("#1A1A2E") // Optional: dark mode background
logo = SplashLogo.resource("logo.png") // File in composeResources/drawable/
logoDark = SplashLogo.resource("logo_dark.png") // Optional: dark mode logo
iosProjectPath = "iosApp/iosApp" // Optional: defaults to "iosApp/iosApp"
}SplashColor.hex("#FFFFFF") // Hex string — accepts both #RRGGBB and RRGGBB
SplashColor.rgb(255, 255, 255) // RGB values (0–255 each)
SplashColor.white // Named constant
SplashColor.black // Named constantSplashLogo.resource("logo.png") // File in composeResources/drawable/
SplashLogo.path("src/commonMain/composeResources/drawable/logo.png") // Custom path relative to module
iosProjectPathshould point to the inner folder that containsInfo.plistandAssets.xcassets— typicallyiosApp/iosApp, not the rootiosAppfolder.
In your Compose App module build.gradle.kts:
commonMain.dependencies {
implementation(libs.kmpSplash.runtime)
}
androidMain.dependencies {
implementation("androidx.core:core-splashscreen:1.2.0")
}KMP Splash is integrated into the Gradle build process. On both Android and iOS, the splash assets are generated automatically when you build or run your app.
If you ever want to trigger the generation manually, you can run:
# Generate iOS assets (Info.plist, pbxproj, xcassets)
./gradlew generateLaunchScreen
# Generate Android assets (themes.xml, logo)
./gradlew generateAndroidSplash[!IMPORTANT] iOS Simulator Caching: iOS heavily caches the launch screen. If you change the background color or logo and don't see the changes in the simulator, you must restart the simulator (or sometimes even delete and reinstall the app) for the new assets to be reflected.
Extend SplashActivity in your MainActivity:
class MainActivity : SplashActivity() {
override suspend fun isReady(): Boolean {
delay(1000) // Load data, check auth, etc.
return true
}
override fun onFinished() {
setContent {
App()
}
}
}Call SplashConfig in your MainViewController:
fun MainViewController() = ComposeUIViewController {
var isAppReady by remember { mutableStateOf(false) }
if (!isAppReady) {
SplashConfig(
isReady = {
delay(1500) // Your initialization logic
true
},
onFinished = { isAppReady = true }
)
} else {
App()
}
}Colors and logo are picked up automatically from your Gradle configuration — no extra parameters needed.
| Platform | Native (Booting) | Compose (Loading) |
|---|---|---|
| Android | Generates themes.xml and values-night. Uses installSplashScreen(). |
Controlled by SplashActivity. |
| iOS | Patches Info.plist with UILaunchScreen, generates SplashBackground color asset and logo imageset in Assets.xcassets. |
SplashConfig uses isSystemInDarkTheme() to match the native screen exactly. |
When a KMP app starts on iOS, the OS displays the native launch screen immediately. Once the Kotlin runtime and Compose initialize (which can take 500ms+), the screen usually flashes white or black before your first Composable is rendered.
KMP Splash ensures the SplashConfig composable is visually identical to the native launch screen, providing seamless continuity that keeps your branding on screen until the app is actually ready.
App-level dark mode overrides
If your app has its own appearance setting (e.g. a dark mode toggle independent of the system setting), the native splash screen will not respect it. Both iOS UILaunchScreen and Android's SplashScreen API are rendered by the OS before any app code runs, they read the system dark mode setting directly. There is no way for any library to work around this.
The Compose layer (SplashConfig / SplashActivity) does run app code, so it can respond to your app's own preference. For the native layer, the options are:
This is a system limitation, not a bug in the library.
Contributions are welcome! If you find a bug or have a feature request, please open an issue or a pull request.
Copyright 2026 KMP Bits
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
Professional Splash Screens for Compose Multiplatform, configured in seconds.
Creating a seamless startup experience in Compose Multiplatform is notoriously difficult. Between the native Android SplashScreen API and iOS UILaunchScreen, developers often face a "white flash" gap between the native boot sequence and the Jetpack Compose Multiplatform runtime.
KMP Splash bridges this gap. It automates the generation of native splash assets and provides a Compose-ready transition layer, ensuring your app feels premium from the very first pixel.
build.gradle.kts.Assets.xcassets for iOS and themes.xml for Android.SplashConfig composable to prevent the flicker when shifting from native boot to Compose UI..pbxproj and Info.plist automatically. No more Storyboards.androidx.core:core-splashscreen 1.2.0+
UILaunchScreen plist key)Ensure you have mavenCentral() in your settings.gradle.kts:
pluginManagement {
repositories {
google()
gradlePluginPortal()
mavenCentral()
}
}
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}In your gradle/libs.versions.toml:
[versions]
kmpSplash = "0.2.1"
[libraries]
kmpSplash-runtime = { module = "io.github.kmpbits:splash-runtime", version.ref = "kmpSplash" }
[plugins]
kmpSplash = { id = "io.github.kmpbits.splash", version.ref = "kmpSplash" }In your Compose App module build.gradle.kts:
plugins {
alias(libs.plugins.kmpSplash)
}
splashScreen {
backgroundColor = SplashColor.hex("#FFFFFF") // Light mode background
backgroundColorNight = SplashColor.hex("#1A1A2E") // Optional: dark mode background
logo = SplashLogo.resource("logo.png") // File in composeResources/drawable/
logoDark = SplashLogo.resource("logo_dark.png") // Optional: dark mode logo
iosProjectPath = "iosApp/iosApp" // Optional: defaults to "iosApp/iosApp"
}SplashColor.hex("#FFFFFF") // Hex string — accepts both #RRGGBB and RRGGBB
SplashColor.rgb(255, 255, 255) // RGB values (0–255 each)
SplashColor.white // Named constant
SplashColor.black // Named constantSplashLogo.resource("logo.png") // File in composeResources/drawable/
SplashLogo.path("src/commonMain/composeResources/drawable/logo.png") // Custom path relative to module
iosProjectPathshould point to the inner folder that containsInfo.plistandAssets.xcassets— typicallyiosApp/iosApp, not the rootiosAppfolder.
In your Compose App module build.gradle.kts:
commonMain.dependencies {
implementation(libs.kmpSplash.runtime)
}
androidMain.dependencies {
implementation("androidx.core:core-splashscreen:1.2.0")
}KMP Splash is integrated into the Gradle build process. On both Android and iOS, the splash assets are generated automatically when you build or run your app.
If you ever want to trigger the generation manually, you can run:
# Generate iOS assets (Info.plist, pbxproj, xcassets)
./gradlew generateLaunchScreen
# Generate Android assets (themes.xml, logo)
./gradlew generateAndroidSplash[!IMPORTANT] iOS Simulator Caching: iOS heavily caches the launch screen. If you change the background color or logo and don't see the changes in the simulator, you must restart the simulator (or sometimes even delete and reinstall the app) for the new assets to be reflected.
Extend SplashActivity in your MainActivity:
class MainActivity : SplashActivity() {
override suspend fun isReady(): Boolean {
delay(1000) // Load data, check auth, etc.
return true
}
override fun onFinished() {
setContent {
App()
}
}
}Call SplashConfig in your MainViewController:
fun MainViewController() = ComposeUIViewController {
var isAppReady by remember { mutableStateOf(false) }
if (!isAppReady) {
SplashConfig(
isReady = {
delay(1500) // Your initialization logic
true
},
onFinished = { isAppReady = true }
)
} else {
App()
}
}Colors and logo are picked up automatically from your Gradle configuration — no extra parameters needed.
| Platform | Native (Booting) | Compose (Loading) |
|---|---|---|
| Android | Generates themes.xml and values-night. Uses installSplashScreen(). |
Controlled by SplashActivity. |
| iOS | Patches Info.plist with UILaunchScreen, generates SplashBackground color asset and logo imageset in Assets.xcassets. |
SplashConfig uses isSystemInDarkTheme() to match the native screen exactly. |
When a KMP app starts on iOS, the OS displays the native launch screen immediately. Once the Kotlin runtime and Compose initialize (which can take 500ms+), the screen usually flashes white or black before your first Composable is rendered.
KMP Splash ensures the SplashConfig composable is visually identical to the native launch screen, providing seamless continuity that keeps your branding on screen until the app is actually ready.
App-level dark mode overrides
If your app has its own appearance setting (e.g. a dark mode toggle independent of the system setting), the native splash screen will not respect it. Both iOS UILaunchScreen and Android's SplashScreen API are rendered by the OS before any app code runs, they read the system dark mode setting directly. There is no way for any library to work around this.
The Compose layer (SplashConfig / SplashActivity) does run app code, so it can respond to your app's own preference. For the native layer, the options are:
This is a system limitation, not a bug in the library.
Contributions are welcome! If you find a bug or have a feature request, please open an issue or a pull request.
Copyright 2026 KMP Bits
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