Skip to content

Commit 79636d4

Browse files
author
Matthieu Gicquel
committed
fix: preventRecentScreenshots compatibility with iOS modals
- ensure it doesn't dismiss the modal when becoming active - ensure it shows up on top of a modal
1 parent 9078808 commit 79636d4

2 files changed

Lines changed: 44 additions & 12 deletions

File tree

example/App.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
1-
import { Button, StyleSheet, View } from "react-native";
1+
import { useState } from "react";
2+
import { Button, Modal, StyleSheet, View } from "react-native";
23

34
export default function App() {
5+
const [isModalVisible, setIsModalVisible] = useState(false);
6+
47
return (
58
<View style={styles.container}>
9+
<Modal visible={isModalVisible}>
10+
<View style={styles.modal}>
11+
<Button
12+
title="close modal"
13+
onPress={() => setIsModalVisible(false)}
14+
/>
15+
</View>
16+
</Modal>
17+
<Button title="open modal" onPress={() => setIsModalVisible(true)} />
618
<Button title="fetch - valid certificates" onPress={fetchValid} />
719
<Button title="fetch - invalid certificates" onPress={fetchInvalid} />
820
</View>
@@ -17,6 +29,12 @@ const styles = StyleSheet.create({
1729
justifyContent: "center",
1830
gap: 16,
1931
},
32+
modal: {
33+
flex: 1,
34+
alignItems: "center",
35+
justifyContent: "center",
36+
backgroundColor: "lightblue",
37+
},
2038
});
2139

2240
const fetchValid = async () => {

ios/RNASAppLifecyleDelegate.swift

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ import ExpoModulesCore
22
import UIKit
33

44
public class RNASAppLifecycleDelegate: ExpoAppDelegateSubscriber {
5+
private var launchScreenViewController: UIViewController?
6+
57
public func applicationDidFinishLaunching(_ application: UIApplication) {
68
if(!isPreventRecentScreenshotsEnabled()) {
79
return
810
}
9-
application.ignoreSnapshotOnNextApplicationLaunch()
11+
12+
application.ignoreSnapshotOnNextApplicationLaunch()
1013
}
1114

1215
public func applicationWillResignActive(_ application: UIApplication) {
@@ -15,20 +18,18 @@ public class RNASAppLifecycleDelegate: ExpoAppDelegateSubscriber {
1518
}
1619

1720
// https://developer.apple.com/documentation/uikit/app_and_environment/scenes/preparing_your_ui_to_run_in_the_background
18-
19-
// TODO: better error handling in case there's an issue with the splashscreen (instead of !)
20-
let launchScreen = UIStoryboard(name: "SplashScreen", bundle: nil).instantiateInitialViewController()!
21-
launchScreen.modalPresentationStyle = .overFullScreen
22-
23-
UIApplication.shared.windows.first?.rootViewController?.present(launchScreen, animated: false)
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+
}
2427
}
2528

2629
public func applicationDidBecomeActive(_ application: UIApplication) {
27-
if(!isPreventRecentScreenshotsEnabled()) {
28-
return
30+
launchScreenViewController?.dismiss(animated: false) {
31+
self.launchScreenViewController = nil
2932
}
30-
31-
UIApplication.shared.windows.first?.rootViewController?.dismiss(animated: false)
3233
}
3334
}
3435

@@ -39,3 +40,16 @@ func isPreventRecentScreenshotsEnabled() -> Bool {
3940
}
4041
return false
4142
}
43+
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)