Skip to content

Commit c101457

Browse files
authored
Fix/alert above splashscreen ios (#24)
## Bug React Native alerts were displayed above the splashscreen when preventSnapshot feature was activated. This PR displays the native splashscreen in a window that has a windowLevel higher than the one used by React Native Alert. | Before | After | | -- | -- | | https://github.com/user-attachments/assets/3a6256aa-ff9c-489b-86d9-35537551fa9e| https://github.com/user-attachments/assets/9e449ba3-8ffb-4e56-be7d-4fe210eaaf11|
1 parent 4890a7a commit c101457

File tree

2 files changed

+12
-23
lines changed

2 files changed

+12
-23
lines changed

example/app/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { SafeKeyboardDetector } from "@bam.tech/react-native-app-security";
22
import { useRouter } from "expo-router";
33
import { useState } from "react";
4-
import { Button, Modal, Platform, StyleSheet, View } from "react-native";
4+
import { Alert, Button, Modal, Platform, StyleSheet, View } from "react-native";
55

66
export default function App() {
77
const [isModalVisible, setIsModalVisible] = useState(false);
@@ -11,6 +11,7 @@ export default function App() {
1111
<View style={styles.container}>
1212
<Modal visible={isModalVisible}>
1313
<View style={styles.modal}>
14+
<Button title="show an alert" onPress={() => Alert.alert("Hello")} />
1415
<Button
1516
title="close modal"
1617
onPress={() => setIsModalVisible(false)}

ios/RNASAppLifecyleDelegate.swift

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ import ExpoModulesCore
22
import UIKit
33

44
public class RNASAppLifecycleDelegate: ExpoAppDelegateSubscriber {
5-
private var launchScreenViewController: UIViewController?
5+
private lazy var launchScreenWindow: UIWindow? = {
6+
let window = UIWindow(frame: UIScreen.main.bounds)
7+
let launchScreen = UIStoryboard(name: "SplashScreen", bundle: nil).instantiateInitialViewController()!
8+
window.rootViewController = launchScreen
9+
window.windowLevel = .alert + 2 // React Native alert uses .alert + 1
10+
return window
11+
}()
612

713
public func applicationDidFinishLaunching(_ application: UIApplication) {
814
if(!isPreventRecentScreenshotsEnabled()) {
@@ -18,18 +24,12 @@ public class RNASAppLifecycleDelegate: ExpoAppDelegateSubscriber {
1824
}
1925

2026
// https://developer.apple.com/documentation/uikit/app_and_environment/scenes/preparing_your_ui_to_run_in_the_background
21-
22-
if let launchScreen = UIStoryboard(name: "SplashScreen", bundle: nil).instantiateInitialViewController() {
23-
launchScreen.modalPresentationStyle = .overFullScreen
24-
getTopMostViewController().present(launchScreen, animated: false)
25-
launchScreenViewController = launchScreen
26-
}
27+
28+
launchScreenWindow?.makeKeyAndVisible()
2729
}
2830

2931
public func applicationDidBecomeActive(_ application: UIApplication) {
30-
launchScreenViewController?.dismiss(animated: false) {
31-
self.launchScreenViewController = nil
32-
}
32+
launchScreenWindow?.isHidden = true
3333
}
3434
}
3535

@@ -41,15 +41,3 @@ func isPreventRecentScreenshotsEnabled() -> Bool {
4141
return false
4242
}
4343

44-
45-
func getTopMostViewController() -> UIViewController {
46-
// We want to display the overlay over any content currently presented, including modals
47-
48-
var topController: UIViewController = UIApplication.shared.windows.first!.rootViewController!
49-
50-
while (topController.presentedViewController != nil) {
51-
topController = topController.presentedViewController!
52-
}
53-
54-
return topController
55-
}

0 commit comments

Comments
 (0)