Files
react-native/packages/rn-tester/RNTester/NativeExampleViews/UpdatePropertiesExampleView.mm
Oskar Kwaśniewski ec928d7a66 feat(RCTAppDelegate): Implement RCTRootViewFactory (#42263)
Summary:
This PR implements `RCTRootViewFactory` a utility class (suggested by cipolleschi) that returns proper RCTRootView based on the current environment state (new arch/old arch/bridgeless). This class aims to preserve background compatibility by implementing a configuration class forwarding necessary class to RCTAppDelegate.

### Brownfield use case

This PR leverages the `RCTRootViewFactory` in `RCTAppDelegate` for the default initialization of React Native (greenfield).

Here is an example of creating a Brownfield integration (without RCTAppDelegate) using this class (can be later added to docs):

1. Store reference to `rootViewFactory` and to `UIWindow`

`AppDelegate.h`:
```objc
interface AppDelegate : UIResponder <UIApplicationDelegate>

property(nonatomic, strong) UIWindow* window;
property(nonatomic, strong) RCTRootViewFactory* rootViewFactory;

end
```

2. Create an initial configuration using `RCTRootViewFactoryConfiguration` and initialize `RCTRootViewFactory` using it. Then you can use the factory to create a new `RCTRootView` without worrying about old arch/new arch/bridgeless.

 `AppDelegate.mm`
```objc
implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey,id> *)launchOptions {

  // Create configuration
 RCTRootViewFactoryConfiguration *configuration = [[RCTRootViewFactoryConfiguration alloc] initWithBundleURL:self.bundleURL
                                                                                                 newArchEnabled:self.fabricEnabled
                                                                                             turboModuleEnabled:self.turboModuleEnabled
                                                                                              bridgelessEnabled:self.bridgelessEnabled];

  // Initialize RCTRootViewFactory
  self.rootViewFactory = [[RCTRootViewFactory alloc] initWithConfiguration:configuration];

  // Create main root view
  UIView *rootView = [self.rootViewFactory viewWithModuleName:@"RNTesterApp" initialProperties:@{} launchOptions:launchOptions];

  // Set main window as you prefer for your Brownfield integration.
  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];

  // Later in the codebase you can initialize more rootView's using rootViewFactory.

  return YES;
}
end
```
bypass-github-export-checks

## Changelog:

[INTERNAL] [ADDED] - Implement RCTRootViewFactory

Pull Request resolved: https://github.com/facebook/react-native/pull/42263

Test Plan: Check if root view is properly created on app initialization

Reviewed By: dmytrorykun

Differential Revision: D53179625

Pulled By: cipolleschi

fbshipit-source-id: 9bc850965ba30d84ad3e67d91dd888f0547c2136
2024-03-04 10:14:44 -08:00

89 lines
2.3 KiB
Plaintext

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "UpdatePropertiesExampleView.h"
#import <React/RCTRootView.h>
#import <React/RCTViewManager.h>
#import "AppDelegate.h"
@interface UpdatePropertiesExampleViewManager : RCTViewManager
@end
@implementation UpdatePropertiesExampleViewManager
RCT_EXPORT_MODULE();
- (UIView *)view
{
return [UpdatePropertiesExampleView new];
}
@end
@implementation UpdatePropertiesExampleView {
RCTRootView *_rootView;
UIButton *_button;
BOOL _beige;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_beige = YES;
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
_rootView = (RCTRootView *)[appDelegate.rootViewFactory viewWithModuleName:@"SetPropertiesExampleApp"
initialProperties:@{@"color" : @"beige"}];
_button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_button setTitle:@"Native Button" forState:UIControlStateNormal];
[_button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_button setBackgroundColor:[UIColor grayColor]];
[_button addTarget:self action:@selector(changeColor) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_button];
[self addSubview:_rootView];
}
return self;
}
- (void)layoutSubviews
{
float spaceHeight = 20;
float buttonHeight = 40;
float rootViewWidth = self.bounds.size.width;
float rootViewHeight = self.bounds.size.height - spaceHeight - buttonHeight;
[_rootView setFrame:CGRectMake(0, 0, rootViewWidth, rootViewHeight)];
[_button setFrame:CGRectMake(0, rootViewHeight + spaceHeight, rootViewWidth, buttonHeight)];
}
- (void)changeColor
{
_beige = !_beige;
NSMutableDictionary *newProperties = [_rootView.appProperties mutableCopy];
newProperties[@"color"] = _beige ? @"beige" : @"purple";
[_rootView setAppProperties:newProperties];
}
- (NSArray<UIView<RCTComponent> *> *)reactSubviews
{
// this is to avoid unregistering our RCTRootView when the component is removed from RN hierarchy
(void)[super reactSubviews];
return @[];
}
@end