react-native
react-native copied to clipboard
feat(RCTAppDelegate): Implement `RCTRootViewFactory`
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):
- Store reference to
rootViewFactory
and toUIWindow
AppDelegate.h
:
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property(nonatomic, strong) UIWindow* window;
@property(nonatomic, strong) RCTRootViewFactory* rootViewFactory;
@end
- Create an initial configuration using
RCTRootViewFactoryConfiguration
and initializeRCTRootViewFactory
using it. Then you can use the factory to create a newRCTRootView
without worrying about old arch/new arch/bridgeless.
AppDelegate.mm
@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
Changelog:
[INTERNAL] [ADDED] - Implement RCTRootViewFactory
Test Plan:
Check if root view is properly created on app initialization
@cipolleschi Creating RCTRootViewFactory
would be the ideal solution but I didn't want to introduce too many changes. However I'm not re-creating key components every time with this approach: self.bridge
, _reactHost
and bridgeAdapter
are created only once on the first call (I accidentally pushed code without this change at first).
Also, I can work on implementing the RCTRootViewFactory
(if you are okay with having this)
Platform | Engine | Arch | Size (bytes) | Diff |
---|---|---|---|---|
android | hermes | arm64-v8a | 17,750,514 | +16 |
android | hermes | armeabi-v7a | n/a | -- |
android | hermes | x86 | n/a | -- |
android | hermes | x86_64 | n/a | -- |
android | jsc | arm64-v8a | 21,108,987 | -1 |
android | jsc | armeabi-v7a | n/a | -- |
android | jsc | x86 | n/a | -- |
android | jsc | x86_64 | n/a | -- |
Base commit: 496724fbdbc85e534572f1e12f89c4af9b88e8e6 Branch: main
@cipolleschi I decided to jump straight into it and implement this class, I think it will make initialization of RN a lot easier also in brownfield apps.
I tried to implement everything in a backward-compatible way
Hi, @cipolleschi would you be willing to take a look at this and let me know if you're interested in pursuing it? It may require some polish, but I'd like to know if you're open to moving forward with this idea or if I should explore alternative options for react-native-visionos
.
Thanks for your review @cipolleschi I think now it's much better the public interface is not changed except for the runtimeSchedulerEnabled
, bridge
and bridgeAdapter
but those are properties that users shouldn't override.
I also fixed those hardcoded values
@cipolleschi As discussed offline, I've refactored the implementation to drop the delegate pattern and now we pass a configuration object. I've also validated that this PR fixes a bug with RCTRootViewExample when running bridgeless mode. RCTRootViewFactory
is now decoupled from the RCTAppDelegate (so that we can move it). I've also added a short documentation to the PR description on brownfield integration using this class (tested it out on RNTester without RCTAppDelegate
). Let me know what you think 👍🏻
@cipolleschi has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.
Hey @cipolleschi, I've rebased the PR on top of the latest changes, is there anything I can do to help you get this merged?
Hi @okwasniewski, sorry for the delay. I was quite busy in the past couple of weeks dealing with other high priority tasks and I couldn't really spend some time on this.
I'll try to make this move forward this week. Thank you for your patience!
@cipolleschi merged this pull request in facebook/react-native@ec928d7a669fa2624bcf7da520041f140dd0fb03.