react-native-bootsplash: NSInvalidArgumentException: Application tried to present modally an active controller

Bug report

Summary

I’ve been seeing reports from sentry that show this error NSInvalidArgumentException: Application tried to present modally an active controller. Stack traces point to this line of code -[RNBootSplash show:] node_modules/react-native-bootsplash/ios/RNBootSplash.m:102.

Environment info

react-native info output:

System:
    OS: macOS 10.15.7
    CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
    Memory: 193.54 MB / 16.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 12.18.3 - /usr/local/opt/node@12/bin/node
    Yarn: 1.22.4 - /usr/local/bin/yarn
    npm: 6.14.6 - /usr/local/opt/node@12/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.9.3 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 14.0, DriverKit 19.0, macOS 10.15, tvOS 14.0, watchOS 7.0
    Android SDK:
      API Levels: 28, 29
      Build Tools: 28.0.3, 29.0.2, 29.0.3
      System Images: android-28 | Intel x86 Atom_64, android-28 | Google APIs Intel x86 Atom, android-29 | Google APIs Intel x86 Atom
      Android NDK: Not Found
  IDEs:
    Android Studio: 4.0 AI-193.6911.18.40.6626763
    Xcode: 12.0.1/12A7300 - /usr/bin/xcodebuild
  Languages:
    Java: 1.8.0_242 - /usr/bin/javac
    Python: 2.7.16 - /usr/bin/python
  npmPackages:
    @react-native-community/cli: Not Found
    react: 16.13.1 => 16.13.1 
    react-native: 0.63.3 => 0.63.3 
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Library version: 2.2.5

Steps to reproduce

I can’t reproduce this issue locally, tried with simulator and physical device, but no luck. From what I understood, somehow this line of code is being called [_presentedViewController presentViewController:_splashViewController animated:false completion:nil];, while _splashViewController is already being shown. _visible flag should prevent this, but maybe, i guess, presentViewController or dismissViewControllerAnimated are called asynchronously.

Describe what you expected to happen:

Not to crash app

Reproducible sample code

I don’t have steps to reproduce, but I can show how I’m using this library to hide content of the app when user opens recent apps, or puts app in the background. I’m using this hook to listen to app state, and show/hide splash screen

import { useEffect } from 'react';
import { AppState } from 'react-native';
import RNBootSplash from 'react-native-bootsplash';

export default () => {
    useEffect(() => {
        const handleAppStateChange: Parameters<typeof AppState.addEventListener>[1] = (
            nextAppState
        ) => {
            if (['background', 'inactive'].includes(nextAppState)) {
                RNBootSplash.show();
            } else if (nextAppState === 'active') {
                RNBootSplash.hide({ duration: 250 });
            }
        };

        const setupAppStateChangeEventListener = () =>
            AppState.addEventListener('change', handleAppStateChange);

        setupAppStateChangeEventListener();
        return () => AppState.removeEventListener('change', handleAppStateChange);
    }, []);
};

Also, i have useEffect in the root of the app to hide splash screen on initial mount

    useEffect(() => {
        RNBootSplash.hide({ duration: 250 });
    }, []);

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 22 (10 by maintainers)

Most upvoted comments

As this is a recurring wanted feature and using AppState is not perfect since the JS execution might be paused in some cases, I think about adding a new method + a hook:

  • setPrivateModeEnabled(boolean)
  • usePrivateMode() to protect some screens / some components (with a LIFO, similar to RN StatusBar module).

Does this seems like a nice solution to you?

RPReplay_Final1605603898