Home / Articles

Adding a Splash Screen to a React Native App on iOS and Android

A React Native splash screen on iOS and Android: an Xcode launch screen, Android themes and layouts, and react-native-splash-screen to kill the white flash.

Publisher: REACTAPP.TOP6 min read1406 words

This article is published in English.

Sources: How to Add a Splash Screen to a React Native App (iOS and Android)

Getting a React Native app into the stores involves more than building it. Before review you need icons, descriptions and a splash screen, and the splash screen is where native code gets involved. The steps below cover iOS and Android in their platform IDEs, with a small amount of native code. The instructions come from the react-native-splash-screen era (the 3.0.6 release and react-native link), so newer React Native versions may handle linking differently.

Projects created with Expo or Create React Native App don't need any of this, because their own documentation covers splash screens in a few lines.

A fresh project is a good starting point, for example react-native init SplashExample. Put it under source control before changing anything. That makes mistakes easy to revert and shows exactly which files a splash screen touches.

Designing the assets

An older approach used one big image as the splash screen, and it scaled badly across the growing range of screen resolutions. A better plan starts from a simple square image resembling the app icon, for two reasons.

  1. It creates the impression that the icon you tapped grows to fill the screen, which makes the transition feel continuous.
  2. It stays simple. A splash screen should be visible for a few milliseconds, so it shouldn't carry information. It's a loading screen, after all.

Export the square at three sizes: 200 px for @1x, 400 px for @2x and 600 px for @3x.

A background that makes flashes obvious

If you've tried a splash screen in React Native before, you may have seen a white flash before your content appears. On an app with a white background it's hard to spot, but it's still annoying. To make any flash impossible to miss, give the demo app a dark background: set the background color to #4F6D7A, the text color to #F5FCFF and switch the status bar to light text, all in App.js.

iOS

Open the project in Xcode:

open ios/SplashExample.xcodeproj

First add an image asset. In the left navigator, go to SplashExample, then SplashExample again, then Images.xcassets, and press the plus button in the second navigator column. Name the asset SplashIcon. Drop in the three images, and Xcode assigns each to the right pixel density automatically.

Next open LaunchScreen.xib from the left navigator. It contains two text elements, the project name and "Powered by React Native". Select both and delete them.

Set the background of the View. Select View in the second navigator, then choose Background in the right-hand panel to open the color picker. A tip that takes a while to discover: pick the second tab in the picker, then "RGB Sliders", and a field appears where a hex value can be typed. Enter #4F6D7A.

Now add an Image View. Open the object library (the third icon at the bottom right of the utilities panel), search for "image" and drag the Image View onto the colored View. In the top-right attributes panel, choose SplashIcon as the image. Set Content Mode to Aspect Fit, which sits second from the top in that panel, so proportions stay right.

To keep the icon centered on any device, open the ruler tab (the fifth icon at the top of the right-hand panel). In the Autoresizing box, turn off the outer red lines and turn on the inner red arrows. The image will remain centered whatever the screen size.

That yields a splash screen, but the white flash is still there.

Why the flash happens

When the app launches, iOS shows the launch screen right away. Then React Native needs time to start up: the JavaScript is loading and the bridge is initializing. During that gap the native launch screen is gone and nothing has rendered yet, so you see white. The cure is to hold the splash screen a little longer than the default, until JavaScript is ready. The react-native-splash-screen package does that.

Install it and link it:

yarn add react-native-splash-screen@3.0.6
react-native link react-native-splash-screen

Then configure the native side. In Xcode, open AppDelegate.m, add the package's header import SplashScreen.h alongside the other imports and call [SplashScreen show]; directly above return YES; inside didFinishLaunchingWithOptions.

On the JavaScript side, tell the splash screen to disappear once the app is ready. Call the package's hide method from componentDidMount in App.js.

The result looks good, with one small nitpick left: the status bar color while the splash is up. In Info.plist, add a row with the key UIStatusBarStyle and the string value UIStatusBarStyleLightContent. After that, the iOS side is done.

Android

Android is a little more involved because two separate splash screens are needed. One belongs to react-native-splash-screen, and the other shows before the app inflates its views.

Assets

Copy the images into the mipmap folders under android/app/src/main/res. Android names its density buckets differently from iOS, so the files need to be mapped:

  • mipmap-mdpi gets the 1x image.
  • mipmap-hdpi gets the 2x image.
  • mipmap-xhdpi gets the 3x image.
  • mipmap-xxhdpi also gets the 3x image.

Inside each folder, rename the file to icon.png.

The cold-start splash

The first screen appears when the app starts from a cold state. The approach follows a well-known Big Nerd Ranch article on doing splash screens the right way, which explains the reasoning in more depth.

  1. Create background_splash.xml in android/app/src/main/res/drawable. You'll probably have to create the drawable directory. The file defines a layer-list, which is a stack of layers. The first layer fills with the background color (defined in a moment) and the second renders the icon, 200dp wide and tall and centered.
  2. Create colors.xml in android/app/src/main/res/values and define the blue, the same one the app uses.
  3. In styles.xml in the same folder, define a SplashTheme. It uses background_splash as the window background and the blue for the status bar, which mimics the real app as closely as possible, status bar change included. Also make sure the default theme's status bar color is set correctly.
  4. In AndroidManifest.xml, make the app use SplashTheme first. Inside <application>, register a new SplashActivity as the launcher, and adjust MainActivity so it's no longer the launcher entry. Pay attention to android:exported="true", which has to be set where required on newer Android versions.
  5. Create SplashActivity.java. Its only job is to forward immediately to MainActivity, the actual React Native app.

Run the app, quit it so the next launch is a cold start, and open it again. The splash appears instantly, followed by the same white flash. Fixing it takes a little more work than on iOS, but not a lot.

Holding the splash until JavaScript is ready

If it isn't installed yet, add the package and link it:

yarn add react-native-splash-screen@3.0.6
react-native link

Configure the native Android side by adding the package's initialization call in MainActivity.java. In App.js, make sure the splash gets closed as soon as the app loads, as on iOS.

Then create launch_screen.xml in android/app/src/main/res/layout. The name matters, because the library looks for it. Use a LinearLayout as the root element. Android Studio has a visual editor similar to Xcode's Interface Builder, but editing the XML directly is simpler here. Set the layout's gravity to center and its background to the blue, leaving the rest at defaults. Inside it, add an ImageView that renders the icon.

The ImageView properties:

  • android:layout_width and android:layout_height set the size, matching what background_splash.xml uses.
  • android:layout_marginTop equals the status bar height. Leave it out and the icon lands in a slightly different place than in the first splash screen, producing a visible jump when one replaces the other.
  • android:src="@mipmap/icon" points to the image.

Last, colors.xml needs one more entry:

<color name="primary_dark">#4F6D7A</color>

Skip it and the app crashes on launch. The cause is a defect inside react-native-splash-screen itself, so a later release might make the entry unnecessary.

With both pieces in place, the app launches with a continuous, flash-free splash screen on iOS and on Android.