Skip to content

Commit

Permalink
Add view getter on RCTRootView / RCTFabricSurfaceHostingProxyRootView (
Browse files Browse the repository at this point in the history
…#37310)

Summary:
Hi 👋

During the [react-native-bootsplash](https://github.com/zoontek/react-native-bootsplash) implementation of the new architecture, I noticed a few thing regarding `RCTRootView` / `RCTFabricSurfaceHostingProxyRootView` compat.

Currently `RCTRootView` inherits from `UIView`, but `RCTFabricSurfaceHostingProxyRootView` does not, which this works:

```obj-c
- (UIView *)createRootViewWithBridge:(RCTBridge *)bridge
                          moduleName:(NSString *)moduleName
                           initProps:(NSDictionary *)initProps {
  RCTRootView *rootView = (RCTRootView *)
      [super createRootViewWithBridge:bridge moduleName:moduleName initProps:initProps];

  UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"LaunchScreen" bundle:nil];
  UIView *loadingView = [[storyboard instantiateInitialViewController] view];

  loadingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  loadingView.frame = rootView.bounds;
  loadingView.center = (CGPoint){CGRectGetMidX(rootView.bounds), CGRectGetMidY(rootView.bounds)};
  loadingView.hidden = NO;

  [rootView addSubview:loadingView];

  return rootView;
}
```

But this doesn't:

```obj-c
- (UIView *)createRootViewWithBridge:(RCTBridge *)bridge
                          moduleName:(NSString *)moduleName
                           initProps:(NSDictionary *)initProps {
  RCTFabricSurfaceHostingProxyRootView *rootView = (RCTFabricSurfaceHostingProxyRootView *)
      [super createRootViewWithBridge:bridge moduleName:moduleName initProps:initProps];

  UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"LaunchScreen" bundle:nil];
  UIView *loadingView = [[storyboard instantiateInitialViewController] view];

  loadingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  loadingView.frame = rootView.bounds;
  loadingView.center = (CGPoint){CGRectGetMidX(rootView.bounds), CGRectGetMidY(rootView.bounds)};
  loadingView.hidden = NO;

  [rootView addSubview:loadingView];

  return rootView;
}
```

Because `RCTFabricSurfaceHostingProxyRootView` is an imperfect proxy as it doesn't give access to the underlaying `UIView *`. As a solution, I added a prop on both: `UIView *view`

PS: I'm well aware that `setLoadingView` also exists in both files, but it's currently not usable as the current `isActivityIndicatorViewVisible` / `isSurfaceViewVisible` / `_activityIndicatorViewFactory` logic in `RCTSurfaceHostingView.mm` doesn't work: a situation where `isActivityIndicatorViewVisible == true && isSurfaceViewVisible == false && _activityIndicatorViewFactory != nil` never happen:

<img width="1162" alt="Screenshot_2023-05-06_at_18 10 18" src="https://user-images.githubusercontent.com/1902323/236883439-2256ddfb-7846-482a-b957-002a7d51a148.png">

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests

Pull Request resolved: #37310

Test Plan:
Add this block of code in `AppDelegate.mm`:

```obj-c
#import <React/RCTRootView.h>

#if __has_include(<React/RCTFabricSurfaceHostingProxyRootView.h>)
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#endif

// …

- (UIView *)createRootViewWithBridge:(RCTBridge *)bridge
                          moduleName:(NSString *)moduleName
                           initProps:(NSDictionary *)initProps {
#ifdef RCT_NEW_ARCH_ENABLED
  RCTFabricSurfaceHostingProxyRootView *rootView = (RCTFabricSurfaceHostingProxyRootView *)
#else
  RCTRootView *rootView = (RCTRootView *)
#endif
      [super createRootViewWithBridge:bridge moduleName:moduleName initProps:initProps];

  // accessing the "real" root view on both arch
  UIView *view = rootView.view;

  UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"LaunchScreen" bundle:nil];
  UIView *loadingView = [[storyboard instantiateInitialViewController] view];

  loadingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  loadingView.frame = view.bounds;
  loadingView.center = (CGPoint){CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds)};
  loadingView.hidden = NO;

  [view addSubview:loadingView];

  return rootView;
}
```

It should persist the splash screen on both old and new architecture.

Reviewed By: sammy-SC

Differential Revision: D45688644

Pulled By: cipolleschi

fbshipit-source-id: b6f2fc8091a15189ea2eceb8ea426593f62674cb
  • Loading branch information
zoontek authored and facebook-github-bot committed May 10, 2023
1 parent d2e446d commit 33e0521
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 0 deletions.
5 changes: 5 additions & 0 deletions packages/react-native/React/Base/RCTRootView.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ extern
*/
@property (nonatomic, weak, nullable) UIViewController *reactViewController;

/**
* The root view casted as UIView. Used by splash screen libraries.
*/
@property (nonatomic, strong, readonly) UIView *view;

/**
* The React-managed contents view of the root view.
*/
Expand Down
5 changes: 5 additions & 0 deletions packages/react-native/React/Base/RCTRootView.m
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ - (instancetype)initWithBundleURL:(NSURL *)bundleURL
RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)

- (UIView *)view
{
return self;
}

- (BOOL)hasBridge
{
return _bridge != nil;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, assign) RCTRootViewSizeFlexibility sizeFlexibility;
@property (nonatomic, weak) id<RCTRootViewDelegate> delegate;
@property (nonatomic, weak) UIViewController *reactViewController;
@property (nonatomic, strong, readonly) UIView *view;
@property (nonatomic, strong, readonly) UIView *contentView;
@property (nonatomic, strong) UIView *loadingView;
@property (nonatomic, assign) BOOL passThroughTouches;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ - (NSString *)moduleName
return super.surface.moduleName;
}

- (UIView *)view
{
return (UIView *)super.surface.view;
}

- (UIView *)contentView
{
return self;
Expand Down

3 comments on commit 33e0521

@abhayagrawal-fareye
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have this code in my node modules but still getting the error - 'React/RCTFabricSurfaceHostingProxyRootView.h' file not found - when I try to build my react-native app with - RCT_NEW_ARCH_ENABLED=1 pod install
React native version - 0.74.5

@VinodNdx
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@abhayagrawal-fareye , Im facing this same issue on 0.75.2. If you have any answer please drop here .

@Kotauror
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zoontek, I'm also facing the same issue after enabling the new architecture on RN 0.76.1.

Please sign in to comment.