Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

react-native-splash-flow

Native animated splash screens for React Native — not a static picture.

  • Android 12+: drives the official SplashScreen API with an animated vector drawable icon (the Gmail-style launch), then slides the whole splash up off-screen to reveal your app already rendered underneath.
  • iOS: shows a SwiftUI animation in its own window above the app — ship a built-in animation or inject any SwiftUI view of your own; in Expo projects your Swift file lives in assets/ and the plugin injects it on every prebuild, so prebuild --clean never eats it.
  • JS: one call, SplashFlow.hide(), whose promise resolves only after the exit animation has fully finished, so you can sequence status-bar changes or entrance animations without racing the splash.
  • Pluggable exit: pick a built-in exit animation (slide-up, slide-down, fade, zoom-out, none) or supply a fully custom one in native code on either platform.
  • Expo: a config plugin wires up everything (MainActivity, themes, drawables, AppDelegate, asset catalog) on expo prebuild.
  • New-architecture TurboModule. No artificial delay: launch feels exactly as fast as your app actually is (a minimum display duration is opt-in).

How it works

Android iOS
Splash rendering System splash screen (API 31+) with your animated vector drawable icon, themed background color SwiftUI view hosted in a dedicated UIWindow above the main window
Waiting setKeepOnScreenCondition holds the system splash until JS calls hide() The overlay window stays up until JS calls hide()
Exit Splash view slides up over 450 ms with a sheet-dismissal cubic curve Splash window slides up over 500 ms with the same curve, with a soft drop shadow for depth
Below Android 12 Static splash: themed window background (no exit animation)
hide() promise Resolves after the exit animation and view removal (with a watchdog for OEM quirks) Resolves after the exit animation and window teardown

Deep dive into every file, the full launch-to-reveal lifecycle, and the design decisions: docs/architecture.md.

Installation

npm install react-native-splash-flow
# or
yarn add react-native-splash-flow

New architecture only (React Native ≥ 0.75, the default since 0.76).


Expo quick start

Requires a development build (expo-dev-client / expo run:*). It cannot work in Expo Go — it is a native module.

  1. Add the plugin to app.json / app.config.js:
{
  "expo": {
    "plugins": [
      [
        "react-native-splash-flow",
        {
          "android": {
            "icon": "./assets/splashflow-icon.xml",
            "backgroundColor": "#FFFFFF",
            "backgroundColorDark": "#000000",
            "animationDuration": 1000
          },
          "ios": {
            "customView": "./assets/MySplashView.swift"
          }
        }
      ]
    ]
  }
}
  1. If your app config still has the top-level "splash" field (or the expo-splash-screen plugin), remove it — two splash systems would fight over the launch theme. See docs/expo-plugin.md.

  2. Regenerate the native projects and run:

npx expo prebuild --clean
npx expo run:android   # or run:ios
  1. Hide the splash when your app is ready:
import SplashFlow from 'react-native-splash-flow';

useEffect(() => {
  bootstrap().finally(async () => {
    await SplashFlow.hide(); // resolves after the exit animation
  });
}, []);

All plugin options are documented in docs/expo-plugin.md.


Bare React Native setup

The plugin only automates the steps below — doing them by hand works in any RN ≥ 0.75 app.

Android

  1. MainActivity — install the splash before super.onCreate() and before any setTheme() call:
import com.splashflow.SplashFlowManager

class MainActivity : ReactActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    SplashFlowManager.install(this)
    // ... setTheme(R.style.AppTheme) if you have it ...
    super.onCreate(null)
  }
}
  1. Theme — create res/values-v31/splashflow.xml (and a values-night-v31 variant if you support dark mode):
<resources>
    <style name="Theme.SplashFlow" parent="Theme.AppCompat.DayNight.NoActionBar">
        <item name="android:windowSplashScreenBackground">@color/splashflow_background</item>
        <item name="android:windowSplashScreenAnimatedIcon">@drawable/splashflow_icon</item>
        <item name="android:windowSplashScreenAnimationDuration">1000</item>
        <item name="android:windowLightStatusBar">true</item>
    </style>
</resources>

Plus a base res/values/splashflow.xml fallback for Android < 12 (plain android:windowBackground), and the splashflow_background color in your colors resources.

  1. Manifest — point the launch activity at the theme:
<activity android:name=".MainActivity" android:theme="@style/Theme.SplashFlow" ...>
  1. Icon — drop your animated vector drawable at res/drawable/splashflow_icon.xml. Authoring guide: docs/android-avd.md.

iOS

In AppDelegate.swift, right after the main window is created:

import SplashFlow
import SwiftUI

// inside application(_:didFinishLaunchingWithOptions:)
SplashFlowManager.show(in: window)                                    // classic animation, logo image named "Icon"
SplashFlowManager.show(in: window, logoImageName: "SplashLogo")       // classic animation, your logo
SplashFlowManager.show(in: window, view: AnyView(EnergySplashFlowView())) // built-in code-drawn bolt animation
SplashFlowManager.show(in: window, view: AnyView(MySplashView()))     // your own SwiftUI view

The full custom-view guide is in docs/ios-custom-view.md.


Exit animations

Default exit is a slide-up reveal on both platforms. Change it:

Expo — plugin props: "android": { "exitAnimation": "fade" }, "ios": { "exitAnimation": "zoom-out" }.

Android (native) — next to install():

SplashFlowManager.setExitStyle(SplashFlowManager.ExitStyle.FADE)

// or fully custom:
SplashFlowManager.setExitAnimator(object : SplashFlowManager.ExitAnimator {
  override fun getDurationMs() = 600L  // feeds the stuck-animation watchdog
  override fun animate(splashView: View, onComplete: Runnable) {
    splashView.animate().alpha(0f).scaleX(1.3f).scaleY(1.3f)
      .setDuration(600).withEndAction(onComplete).start()
  }
})

iOS (native) — before hide() is called (e.g. next to show(in:)):

SplashFlowManager.exitStyle = .fade

// or fully custom — call the completion exactly once when done:
SplashFlowManager.customExitAnimation = { window, complete in
  UIView.animate(withDuration: 0.6, animations: {
    window.alpha = 0
    window.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
  }) { _ in complete() }
}

Available styles on both platforms: slide-up (default), slide-down, fade, zoom-out, none (instant).


JS API

import SplashFlow from 'react-native-splash-flow';

SplashFlow.hide(): Promise<string>

Hides the splash. The promise resolves after the exit animation has completely finished and the splash view/window is gone. Idempotent — concurrent and repeated callers share a single native call, so calling it from several places is safe.

SplashFlow.isReady(): Promise<boolean>

true once the configured minimum display duration has elapsed (always true with the default duration of 0).

On web or when the native module is missing, both calls resolve immediately (hide() with an informational string, isReady() with true).

Native API

Android — com.splashflow.SplashFlowManager

Member Purpose
install(Activity) Call at the very top of MainActivity.onCreate(), before super.onCreate()
setMinimumDuration(long ms) Optional minimum splash duration (default 0)
setExitStyle(ExitStyle) SLIDE_UP (default), SLIDE_DOWN, FADE, ZOOM_OUT, NONE
setExitAnimator(ExitAnimator) Fully custom exit animation (overrides the style)
hide() / hide(Runnable) Usually called via JS; the callback fires after the exit animation
canHide() Whether the minimum duration has elapsed

iOS — SplashFlowManager

Member Purpose
show(in:) Classic animation (logo image named "Icon", falling back to the app icon)
show(in:logoImageName:accentColor:secondaryAccentColor:) Classic animation, custom logo/colors
show(in:view:) Any AnyView you provide — full control (EnergySplashFlowView() is a built-in option)
minimumDuration Optional minimum splash duration in seconds (default 0), set before show
exitStyle .slideUp (default), .slideDown, .fade, .zoomOut, .none
customExitAnimation (UIWindow, @escaping () -> Void) -> Void — fully custom exit
hide(completion:) / canHide() Usually called via JS

Troubleshooting

  • Android < 12 shows a static splash — expected: the animated icon is an Android 12+ system feature; older versions get the themed background color and no exit animation.
  • The animated icon plays only partially — the system caps windowSplashScreenAnimationDuration at 1000 ms; design your AVD to land its pose within a second.
  • Expo: white flash or two splashes — remove the "splash" field / expo-splash-screen plugin from your app config so only SplashFlow controls the launch theme.
  • hide() resolves but you never saw the animation — the splash shows only on a cold launch; fully terminate the app and relaunch.
  • iOS shows the LaunchScreen storyboard for an instant first — normal: the storyboard is what iOS renders before your process runs; keep its background color aligned with your splash view so the handoff is invisible.

Example app

example/ is an Expo app (dev client) with the plugin configured, a sample animated vector drawable, and a demo screen that simulates startup work before calling hide(). From the repo root:

yarn
yarn example android   # or ios

Contributing

See the contributing guide to learn how to contribute to the repository and the development workflow.

License

MIT


Made with create-react-native-library

About

Native animated splash screens for React Native — Android 12+ SplashScreen API + SwiftUI launch animations, with Expo config plugin.

Topics

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages