Skip to content

Commit fc19005

Browse files
committed
feat: refactor RCTKeyWindow to be more resilient and work in multi-window apps (facebook#42036)
Summary: This PRs refactors `RCTKeyWindow()` to be more resilient and work in multi-window apps. After my recent PR got merged (facebook#41935) it significantly reduced the number of calls to `RCTKeyWindow()` and now it's called only when necessary. So this PR makes this function a bit more resource intensive but it guarantees that we will find current scene's key window. This would also fix some brownfield scenarios where React Native is working in multi-window mode and in the future allow us to more easily adopt `UIWindowSceneDelegate` bypass-github-export-checks [IOS] [CHANGED] - refactor `RCTKeyWindow` to be more resilient and work in multi-window apps Pull Request resolved: facebook#42036 Test Plan: Checkout RNTester example for Alerts and LoadingView. https://github.com/facebook/react-native/assets/52801365/8cf4d698-db6d-4a12-8d8d-7a5acf34858b Reviewed By: huntie Differential Revision: D52431720 Pulled By: cipolleschi fbshipit-source-id: 0d6ef1d46b2428c30c9f64dae66b95dbc69f0a3b
1 parent c7a1f24 commit fc19005

3 files changed

Lines changed: 19 additions & 36 deletions

File tree

packages/react-native/React/Base/RCTUtils.m

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -548,12 +548,20 @@ BOOL RCTRunningInAppExtension(void)
548548
return nil;
549549
}
550550

551-
// TODO: replace with a more robust solution
552-
for (UIWindow *window in RCTSharedApplication().windows) {
553-
if (window.keyWindow) {
554-
return window;
551+
for (UIScene *scene in RCTSharedApplication().connectedScenes) {
552+
if (scene.activationState != UISceneActivationStateForegroundActive ||
553+
![scene isKindOfClass:[UIWindowScene class]]) {
554+
continue;
555+
}
556+
UIWindowScene *windowScene = (UIWindowScene *)scene;
557+
558+
for (UIWindow *window in windowScene.windows) {
559+
if (window.isKeyWindow) {
560+
return window;
561+
}
555562
}
556563
}
564+
557565
return nil;
558566
}
559567

packages/react-native/React/CoreModules/RCTAlertController.mm

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,7 @@ @implementation RCTAlertController
2020
- (UIWindow *)alertWindow
2121
{
2222
if (_alertWindow == nil) {
23-
_alertWindow = [self getUIWindowFromScene];
24-
25-
if (_alertWindow == nil) {
26-
UIWindow *keyWindow = RCTSharedApplication().keyWindow;
27-
if (keyWindow) {
28-
_alertWindow = [[UIWindow alloc] initWithFrame:keyWindow.bounds];
29-
} else {
30-
// keyWindow is nil, so we cannot create and initialize _alertWindow
31-
NSLog(@"Unable to create alert window: keyWindow is nil");
32-
}
33-
}
23+
_alertWindow = [[UIWindow alloc] initWithWindowScene:RCTKeyWindow().windowScene];
3424

3525
if (_alertWindow) {
3626
_alertWindow.rootViewController = [UIViewController new];
@@ -65,16 +55,4 @@ - (void)hide
6555
_alertWindow = nil;
6656
}
6757

68-
- (UIWindow *)getUIWindowFromScene
69-
{
70-
for (UIScene *scene in RCTSharedApplication().connectedScenes) {
71-
if (scene.activationState == UISceneActivationStateForegroundActive &&
72-
[scene isKindOfClass:[UIWindowScene class]]) {
73-
return [[UIWindow alloc] initWithWindowScene:(UIWindowScene *)scene];
74-
}
75-
}
76-
77-
return nil;
78-
}
79-
8058
@end

packages/react-native/React/CoreModules/RCTDevLoadingView.mm

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,14 @@ - (void)showMessage:(NSString *)message color:(UIColor *)color backgroundColor:(
113113

114114
dispatch_async(dispatch_get_main_queue(), ^{
115115
self->_showDate = [NSDate date];
116+
116117
if (!self->_window && !RCTRunningInTestEnvironment()) {
117-
CGSize screenSize = [UIScreen mainScreen].bounds.size;
118+
UIWindow *window = RCTKeyWindow();
119+
CGFloat windowWidth = window.bounds.size.width;
118120

119-
UIWindow *window = RCTSharedApplication().keyWindow;
120-
self->_window =
121-
[[UIWindow alloc] initWithFrame:CGRectMake(0, 0, screenSize.width, window.safeAreaInsets.top + 10)];
122-
self->_label =
123-
[[UILabel alloc] initWithFrame:CGRectMake(0, window.safeAreaInsets.top - 10, screenSize.width, 20)];
121+
self->_window = [[UIWindow alloc] initWithWindowScene:window.windowScene];
122+
self->_window.frame = CGRectMake(0, 0, windowWidth, window.safeAreaInsets.top + 10);
123+
self->_label = [[UILabel alloc] initWithFrame:CGRectMake(0, window.safeAreaInsets.top - 10, windowWidth, 20)];
124124
[self->_window addSubview:self->_label];
125125

126126
self->_window.windowLevel = UIWindowLevelStatusBar + 1;
@@ -136,9 +136,6 @@ - (void)showMessage:(NSString *)message color:(UIColor *)color backgroundColor:(
136136

137137
self->_window.backgroundColor = backgroundColor;
138138
self->_window.hidden = NO;
139-
140-
UIWindowScene *scene = (UIWindowScene *)RCTSharedApplication().connectedScenes.anyObject;
141-
self->_window.windowScene = scene;
142139
});
143140

144141
[self hideBannerAfter:15.0];

0 commit comments

Comments
 (0)