Since Android 12 the system draws the launch screen itself, a background color and a centered icon taken from the activity's theme, before your code runs. The expo-splash-screen config plugin generates that theme: after prebuild, MainActivity uses Theme.App.SplashScreen, with its color in values/colors.xml (and values-night/colors.xml for dark) and its icon as splashscreen_logo.png drawables, one per density.
[
"expo-splash-screen",
{
"image": "./assets/splash-icon.png",
"imageWidth": 160,
"backgroundColor": "#1565c0",
"dark": { "backgroundColor": "#0b1320" }
}
]By default the splash hides as soon as React 7,897 renders its first frame. preventAutoHideAsync(), called at module scope, keeps it up until you call hideAsync(), so a blank frame never shows between splash and app:
SplashScreen.preventAutoHideAsync(); // module scope: runs before the first render
SplashScreen.setOptions({ duration: 400, fade: true }); // fade is iOS-only
export default function App() {
useEffect(() => {
SplashScreen.hideAsync(); // the first frame is committed: swap splash for the app
}, []);If the first screen needs fonts or a saved session, hide the splash once they are ready. Never wait for network data: the splash cannot show progress or an error, so that belongs to the in-app states of Loading States in BookNest. Test splashes in a release build, because Expo Go 6,418 shows your app icon instead and development builds skip some options.
icon is a 1024 x 1024 PNG. On Android, android.adaptiveIcon supplies foreground and background layers that the launcher masks to its own shape, plus a monochromeImage for Android 13's themed icons; iOS takes dark and tinted variants, or since SDK 54 an .icon file from Apple's macOS-only Icon Composer. Icons and Metadata prepares the final store artwork.