From 081be01a5dd24d0a398c6aa8297575502a17d5ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Kwas=CC=81niewski?= Date: Tue, 31 Dec 2024 07:45:25 -0800 Subject: [PATCH] feat: implement ReactNativeFactory (#46298) Summary: This PR implements ReactNativeFactory to encapsulate further the logic of creating an instance of React Native for iOS. This will remove the strong coupling on the RCTAppDelegate and allow us to support Scene Delegate in the future. The goal is to have a following API: ```objc self.reactNativeFactory = [[RCTReactNativeFactory alloc] initWithDelegate:self]; UIView *rootView = [self.reactNativeFactory.rootViewFactory viewWithModuleName:self.moduleName initialProperties:self.initialProps launchOptions:launchOptions]; // Standard iOS stuff here ``` ## Changelog: [IOS] [ADDED] - implement ReactNativeFactory Pull Request resolved: https://github.com/facebook/react-native/pull/46298 Test Plan: Test out all the methods of AppDelegate Reviewed By: huntie Differential Revision: D67451403 Pulled By: cipolleschi fbshipit-source-id: 9e73cd996ffc27ca1e3e058b45fc899b1637bdba --- .../AppDelegate/RCTAppDelegate+Protected.h | 16 -- .../Libraries/AppDelegate/RCTAppDelegate.h | 54 +--- .../Libraries/AppDelegate/RCTAppDelegate.mm | 224 +-------------- .../RCTDefaultReactNativeFactoryDelegate.h | 21 ++ .../RCTDefaultReactNativeFactoryDelegate.mm | 121 ++++++++ .../AppDelegate/RCTReactNativeFactory.h | 98 +++++++ .../AppDelegate/RCTReactNativeFactory.mm | 263 ++++++++++++++++++ packages/rn-tester/RNTester/AppDelegate.mm | 1 - 8 files changed, 514 insertions(+), 284 deletions(-) delete mode 100644 packages/react-native/Libraries/AppDelegate/RCTAppDelegate+Protected.h create mode 100644 packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.h create mode 100644 packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm create mode 100644 packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.h create mode 100644 packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.mm diff --git a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate+Protected.h b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate+Protected.h deleted file mode 100644 index 2321b43c4da971..00000000000000 --- a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate+Protected.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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. - */ - -#if defined(__cplusplus) - -#import -#import "RCTAppDelegate.h" - -@interface RCTAppDelegate () -@end - -#endif diff --git a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h index fa649f9f01bb55..6f9878e21fa75b 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h +++ b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h @@ -8,9 +8,9 @@ #import #import #import -#import "RCTArchConfiguratorProtocol.h" +#import "RCTDefaultReactNativeFactoryDelegate.h" +#import "RCTReactNativeFactory.h" #import "RCTRootViewFactory.h" -#import "RCTUIConfiguratorProtocol.h" @class RCTBridge; @protocol RCTBridgeDelegate; @@ -58,64 +58,22 @@ NS_ASSUME_NONNULL_BEGIN (const facebook::react::ObjCTurboModule::InitParams &)params * - (id)getModuleInstanceFromClass:(Class)moduleClass */ -@interface RCTAppDelegate : UIResponder < - UIApplicationDelegate, - UISceneDelegate, - RCTBridgeDelegate, - RCTUIConfiguratorProtocol, - RCTArchConfiguratorProtocol> +@interface RCTAppDelegate : RCTDefaultReactNativeFactoryDelegate /// The window object, used to render the UViewControllers @property (nonatomic, strong, nonnull) UIWindow *window; + @property (nonatomic, nullable) RCTBridge *bridge; @property (nonatomic, strong, nullable) NSString *moduleName; @property (nonatomic, strong, nullable) NSDictionary *initialProps; -@property (nonatomic, strong, nonnull) RCTRootViewFactory *rootViewFactory; -@property (nonatomic, strong) id dependencyProvider; +@property (nonatomic, strong) RCTReactNativeFactory *reactNativeFactory; /// If `automaticallyLoadReactNativeWindow` is set to `true`, the React Native window will be loaded automatically. @property (nonatomic, assign) BOOL automaticallyLoadReactNativeWindow; @property (nonatomic, nullable) RCTSurfacePresenterBridgeAdapter *bridgeAdapter; -/** - * It creates a `RCTBridge` using a delegate and some launch options. - * By default, it is invoked passing `self` as a delegate. - * You can override this function to customize the logic that creates the RCTBridge - * - * @parameter: delegate - an object that implements the `RCTBridgeDelegate` protocol. - * @parameter: launchOptions - a dictionary with a set of options. - * - * @returns: a newly created instance of RCTBridge. - */ -- (RCTBridge *)createBridgeWithDelegate:(id)delegate launchOptions:(NSDictionary *)launchOptions; - -/** - * It creates a `UIView` starting from a bridge, a module name and a set of initial properties. - * By default, it is invoked using the bridge created by `createBridgeWithDelegate:launchOptions` and - * the name in the `self.moduleName` variable. - * You can override this function to customize the logic that creates the Root View. - * - * @parameter: bridge - an instance of the `RCTBridge` object. - * @parameter: moduleName - the name of the app, used by Metro to resolve the module. - * @parameter: initProps - a set of initial properties. - * - * @returns: a UIView properly configured with a bridge for React Native. - */ -- (UIView *)createRootViewWithBridge:(RCTBridge *)bridge - moduleName:(NSString *)moduleName - initProps:(NSDictionary *)initProps; - -/// This method returns a map of Component Descriptors and Components classes that needs to be registered in the -/// new renderer. The Component Descriptor is a string which represent the name used in JS to refer to the native -/// component. The default implementation returns an empty dictionary. Subclasses can override this method to register -/// the required components. -/// -/// @return a dictionary that associate a component for the new renderer with his descriptor. -- (NSDictionary> *)thirdPartyFabricComponents; - -/// Return the bundle URL for the main bundle. -- (NSURL *__nullable)bundleURL; +- (RCTRootViewFactory *)rootViewFactory; @end diff --git a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm index 42e17ad9fda202..e9321dd8212093 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm @@ -6,7 +6,6 @@ */ #import "RCTAppDelegate.h" -#import #import #import #import @@ -14,10 +13,6 @@ #import #include #import -#import -#import -#import -#import "RCTAppDelegate+Protected.h" #import "RCTAppSetupUtils.h" #import "RCTDependencyProvider.h" @@ -37,9 +32,6 @@ using namespace facebook::react; -@interface RCTAppDelegate () -@end - @implementation RCTAppDelegate - (instancetype)init @@ -52,16 +44,7 @@ - (instancetype)init - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [self _setUpFeatureFlags]; - - RCTSetNewArchEnabled([self newArchEnabled]); - [RCTColorSpaceUtils applyDefaultColorSpace:self.defaultColorSpace]; - RCTAppSetupPrepareApp(application, self.turboModuleEnabled); - - self.rootViewFactory = [self createRCTRootViewFactory]; - if (self.newArchEnabled || self.fabricEnabled) { - [RCTComponentViewFactory currentComponentViewFactory].thirdPartyFabricComponentsProvider = self; - } + self.reactNativeFactory = [[RCTReactNativeFactory alloc] initWithDelegate:self]; if (self.automaticallyLoadReactNativeWindow) { [self loadReactNativeWindow:launchOptions]; @@ -84,45 +67,6 @@ - (void)loadReactNativeWindow:(NSDictionary *)launchOptions [_window makeKeyAndVisible]; } -- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge -{ - [NSException raise:@"RCTBridgeDelegate::sourceURLForBridge not implemented" - format:@"Subclasses must implement a valid sourceURLForBridge method"]; - return nil; -} - -- (RCTBridge *)createBridgeWithDelegate:(id)delegate launchOptions:(NSDictionary *)launchOptions -{ - return [[RCTBridge alloc] initWithDelegate:delegate launchOptions:launchOptions]; -} - -- (UIView *)createRootViewWithBridge:(RCTBridge *)bridge - moduleName:(NSString *)moduleName - initProps:(NSDictionary *)initProps -{ - BOOL enableFabric = self.fabricEnabled; - UIView *rootView = RCTAppSetupDefaultRootView(bridge, moduleName, initProps, enableFabric); - - rootView.backgroundColor = [UIColor systemBackgroundColor]; - - return rootView; -} - -- (UIViewController *)createRootViewController -{ - return [UIViewController new]; -} - -- (void)setRootView:(UIView *)rootView toRootViewController:(UIViewController *)rootViewController -{ - rootViewController.view = rootView; -} - -- (void)customizeRootView:(RCTRootView *)rootView -{ - // Override point for customization after application launch. -} - #pragma mark - UISceneDelegate - (void)windowScene:(UIWindowScene *)windowScene @@ -133,52 +77,11 @@ - (void)windowScene:(UIWindowScene *)windowScene [[NSNotificationCenter defaultCenter] postNotificationName:RCTWindowFrameDidChangeNotification object:self]; } -- (RCTColorSpace)defaultColorSpace -{ - return RCTColorSpaceSRGB; -} - -#pragma mark - New Arch Enabled settings - -- (BOOL)newArchEnabled -{ -#if RCT_NEW_ARCH_ENABLED - return YES; -#else - return NO; -#endif -} - -- (BOOL)turboModuleEnabled -{ - return [self newArchEnabled]; -} - -- (BOOL)fabricEnabled -{ - return [self newArchEnabled]; -} - -- (BOOL)bridgelessEnabled -{ - return [self newArchEnabled]; -} - -- (NSURL *)bundleURL -{ - [NSException raise:@"RCTAppDelegate::bundleURL not implemented" - format:@"Subclasses must implement a valid getBundleURL method"]; - return nullptr; -} - -#pragma mark - RCTHostDelegate - -- (void)hostDidStart:(RCTHost *)host +- (RCTRootViewFactory *)rootViewFactory { + return self.reactNativeFactory.rootViewFactory; } -#pragma mark - Bridge and Bridge Adapter properties - - (RCTBridge *)bridge { return self.rootViewFactory.bridge; @@ -191,129 +94,12 @@ - (RCTSurfacePresenterBridgeAdapter *)bridgeAdapter - (void)setBridge:(RCTBridge *)bridge { - self.rootViewFactory.bridge = bridge; + self.reactNativeFactory.rootViewFactory.bridge = bridge; } - (void)setBridgeAdapter:(RCTSurfacePresenterBridgeAdapter *)bridgeAdapter { - self.rootViewFactory.bridgeAdapter = bridgeAdapter; -} - -#pragma mark - RCTTurboModuleManagerDelegate - -- (Class)getModuleClassFromName:(const char *)name -{ -#if RN_DISABLE_OSS_PLUGIN_HEADER - return RCTTurboModulePluginClassProvider(name); -#else - return RCTCoreModulesClassProvider(name); -#endif -} - -- (std::shared_ptr)getTurboModule:(const std::string &)name - jsInvoker:(std::shared_ptr)jsInvoker -{ - return DefaultTurboModules::getTurboModule(name, jsInvoker); -} - -- (id)getModuleInstanceFromClass:(Class)moduleClass -{ - return RCTAppSetupDefaultModuleFromClass(moduleClass, self.dependencyProvider); -} - -#pragma mark - RCTComponentViewFactoryComponentProvider - -- (NSDictionary> *)thirdPartyFabricComponents -{ - return self.dependencyProvider ? self.dependencyProvider.thirdPartyFabricComponents : @{}; -} - -- (RCTRootViewFactory *)createRCTRootViewFactory -{ - __weak __typeof(self) weakSelf = self; - RCTBundleURLBlock bundleUrlBlock = ^{ - RCTAppDelegate *strongSelf = weakSelf; - return strongSelf.bundleURL; - }; - - RCTRootViewFactoryConfiguration *configuration = - [[RCTRootViewFactoryConfiguration alloc] initWithBundleURLBlock:bundleUrlBlock - newArchEnabled:self.fabricEnabled - turboModuleEnabled:self.turboModuleEnabled - bridgelessEnabled:self.bridgelessEnabled]; - - configuration.createRootViewWithBridge = ^UIView *(RCTBridge *bridge, NSString *moduleName, NSDictionary *initProps) { - return [weakSelf createRootViewWithBridge:bridge moduleName:moduleName initProps:initProps]; - }; - - configuration.createBridgeWithDelegate = ^RCTBridge *(id delegate, NSDictionary *launchOptions) { - return [weakSelf createBridgeWithDelegate:delegate launchOptions:launchOptions]; - }; - - configuration.customizeRootView = ^(UIView *_Nonnull rootView) { - [weakSelf customizeRootView:(RCTRootView *)rootView]; - }; - - configuration.sourceURLForBridge = ^NSURL *_Nullable(RCTBridge *_Nonnull bridge) - { - return [weakSelf sourceURLForBridge:bridge]; - }; - - if ([self respondsToSelector:@selector(extraModulesForBridge:)]) { - configuration.extraModulesForBridge = ^NSArray> *_Nonnull(RCTBridge *_Nonnull bridge) - { - return [weakSelf extraModulesForBridge:bridge]; - }; - } - - if ([self respondsToSelector:@selector(extraLazyModuleClassesForBridge:)]) { - configuration.extraLazyModuleClassesForBridge = - ^NSDictionary *_Nonnull(RCTBridge *_Nonnull bridge) - { - return [weakSelf extraLazyModuleClassesForBridge:bridge]; - }; - } - - if ([self respondsToSelector:@selector(bridge:didNotFindModule:)]) { - configuration.bridgeDidNotFindModule = ^BOOL(RCTBridge *_Nonnull bridge, NSString *_Nonnull moduleName) { - return [weakSelf bridge:bridge didNotFindModule:moduleName]; - }; - } - - return [[RCTRootViewFactory alloc] initWithTurboModuleDelegate:self hostDelegate:self configuration:configuration]; -} - -#pragma mark - Feature Flags - -class RCTAppDelegateBridgelessFeatureFlags : public ReactNativeFeatureFlagsDefaults { - public: - bool enableBridgelessArchitecture() override - { - return true; - } - bool enableFabricRenderer() override - { - return true; - } - bool useTurboModules() override - { - return true; - } - bool useNativeViewConfigsInBridgelessMode() override - { - return true; - } - bool enableFixForViewCommandRace() override - { - return true; - } -}; - -- (void)_setUpFeatureFlags -{ - if ([self bridgelessEnabled]) { - ReactNativeFeatureFlags::override(std::make_unique()); - } + self.reactNativeFactory.rootViewFactory.bridgeAdapter = bridgeAdapter; } @end diff --git a/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.h b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.h new file mode 100644 index 00000000000000..f5e12f7227e525 --- /dev/null +++ b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.h @@ -0,0 +1,21 @@ +/* + * 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 +#import "RCTReactNativeFactory.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Default delegate for RCTReactNativeFactory. + * Contains default implementation of RCTReactNativeFactoryDelegate methods. + */ + +@interface RCTDefaultReactNativeFactoryDelegate : UIResponder +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm new file mode 100644 index 00000000000000..710f00e3142c3f --- /dev/null +++ b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm @@ -0,0 +1,121 @@ +/* + * 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 "RCTDefaultReactNativeFactoryDelegate.h" +#import +#import "RCTAppSetupUtils.h" +#import "RCTDependencyProvider.h" + +#import + +@implementation RCTDefaultReactNativeFactoryDelegate + +@synthesize dependencyProvider; + +- (NSURL *_Nullable)sourceURLForBridge:(nonnull RCTBridge *)bridge +{ + [NSException raise:@"RCTBridgeDelegate::sourceURLForBridge not implemented" + format:@"Subclasses must implement a valid sourceURLForBridge method"]; + return nil; +} + +- (UIViewController *)createRootViewController +{ + return [UIViewController new]; +} + +- (RCTBridge *)createBridgeWithDelegate:(id)delegate launchOptions:(NSDictionary *)launchOptions +{ + return [[RCTBridge alloc] initWithDelegate:delegate launchOptions:launchOptions]; +} + +- (void)setRootView:(UIView *)rootView toRootViewController:(UIViewController *)rootViewController +{ + rootViewController.view = rootView; +} + +- (void)customizeRootView:(RCTRootView *)rootView +{ + // Override point for customization after application launch. +} + +- (UIView *)createRootViewWithBridge:(RCTBridge *)bridge + moduleName:(NSString *)moduleName + initProps:(NSDictionary *)initProps +{ + BOOL enableFabric = self.fabricEnabled; + UIView *rootView = RCTAppSetupDefaultRootView(bridge, moduleName, initProps, enableFabric); + + rootView.backgroundColor = [UIColor systemBackgroundColor]; + + return rootView; +} + +- (RCTColorSpace)defaultColorSpace +{ + return RCTColorSpaceSRGB; +} + +- (NSURL *_Nullable)bundleURL +{ + [NSException raise:@"RCTAppDelegate::bundleURL not implemented" + format:@"Subclasses must implement a valid getBundleURL method"]; + return nullptr; +} + +- (NSDictionary> *)thirdPartyFabricComponents +{ + return self.dependencyProvider ? self.dependencyProvider.thirdPartyFabricComponents : @{}; +} + +- (void)hostDidStart:(RCTHost *)host +{ +} + +- (std::shared_ptr)getTurboModule:(const std::string &)name + jsInvoker:(std::shared_ptr)jsInvoker +{ + return facebook::react::DefaultTurboModules::getTurboModule(name, jsInvoker); +} + +#pragma mark - RCTArchConfiguratorProtocol + +- (BOOL)newArchEnabled +{ +#if RCT_NEW_ARCH_ENABLED + return YES; +#else + return NO; +#endif +} + +- (BOOL)bridgelessEnabled +{ + return self.newArchEnabled; +} + +- (BOOL)fabricEnabled +{ + return self.newArchEnabled; +} + +- (BOOL)turboModuleEnabled +{ + return self.newArchEnabled; +} + +- (Class)getModuleClassFromName:(const char *)name +{ + return nullptr; +} + +- (id)getModuleInstanceFromClass:(Class)moduleClass +{ + return nullptr; +} + +@end diff --git a/packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.h b/packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.h new file mode 100644 index 00000000000000..43a31b4fede95b --- /dev/null +++ b/packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.h @@ -0,0 +1,98 @@ +/* + * 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 +#import +#import +#import "RCTArchConfiguratorProtocol.h" +#import "RCTDependencyProvider.h" +#import "RCTRootViewFactory.h" +#import "RCTUIConfiguratorProtocol.h" + +#if defined(__cplusplus) // Don't conform to protocols requiring C++ when it's not defined. +#import +#import +#import + +#endif + +@class RCTBridge; +@protocol RCTComponentViewProtocol; +@class RCTSurfacePresenterBridgeAdapter; + +NS_ASSUME_NONNULL_BEGIN + +@protocol RCTReactNativeFactoryDelegate < + RCTBridgeDelegate, + RCTUIConfiguratorProtocol, +#if defined(__cplusplus) // Don't conform to protocols requiring C++ when it's not defined. + RCTHostDelegate, + RCTTurboModuleManagerDelegate, + RCTComponentViewFactoryComponentProvider, +#endif + RCTArchConfiguratorProtocol> + +/// Return the bundle URL for the main bundle. +- (NSURL *__nullable)bundleURL; + +@property (nonatomic, strong) id dependencyProvider; + +@optional +/** + * It creates a `RCTBridge` using a delegate and some launch options. + * By default, it is invoked passing `self` as a delegate. + * You can override this function to customize the logic that creates the RCTBridge + * + * @parameter: delegate - an object that implements the `RCTBridgeDelegate` protocol. + * @parameter: launchOptions - a dictionary with a set of options. + * + * @returns: a newly created instance of RCTBridge. + */ +- (RCTBridge *)createBridgeWithDelegate:(id)delegate launchOptions:(NSDictionary *)launchOptions; + +/** + * It creates a `UIView` starting from a bridge, a module name and a set of initial properties. + * By default, it is invoked using the bridge created by `createBridgeWithDelegate:launchOptions` and + * the name in the `self.moduleName` variable. + * You can override this function to customize the logic that creates the Root View. + * + * @parameter: bridge - an instance of the `RCTBridge` object. + * @parameter: moduleName - the name of the app, used by Metro to resolve the module. + * @parameter: initProps - a set of initial properties. + * + * @returns: a UIView properly configured with a bridge for React Native. + */ +- (UIView *)createRootViewWithBridge:(RCTBridge *)bridge + moduleName:(NSString *)moduleName + initProps:(NSDictionary *)initProps; + +/// This method returns a map of Component Descriptors and Components classes that needs to be registered in the +/// new renderer. The Component Descriptor is a string which represent the name used in JS to refer to the native +/// component. The default implementation returns an empty dictionary. Subclasses can override this method to register +/// the required components. +/// +/// @return a dictionary that associate a component for the new renderer with his descriptor. +- (NSDictionary> *)thirdPartyFabricComponents; + +@end + +@interface RCTReactNativeFactory : NSObject + +- (instancetype)initWithDelegate:(id)delegate; + +@property (nonatomic, nullable) RCTBridge *bridge; +@property (nonatomic, strong, nullable) NSString *moduleName; +@property (nonatomic, strong, nullable) NSDictionary *initialProps; +@property (nonatomic, strong, nonnull) RCTRootViewFactory *rootViewFactory; + +@property (nonatomic, nullable) RCTSurfacePresenterBridgeAdapter *bridgeAdapter; + +@property (nonatomic, weak) id delegate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.mm b/packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.mm new file mode 100644 index 00000000000000..75c963a3a990c7 --- /dev/null +++ b/packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.mm @@ -0,0 +1,263 @@ +/* + * 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 "RCTReactNativeFactory.h" +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import "RCTAppSetupUtils.h" + +#if RN_DISABLE_OSS_PLUGIN_HEADER +#import +#else +#import +#endif +#import +#import +#if USE_HERMES +#import +#else +#import +#endif +#import + +#import "RCTDependencyProvider.h" + +using namespace facebook::react; + +@interface RCTReactNativeFactory () < + RCTComponentViewFactoryComponentProvider, + RCTHostDelegate, + RCTTurboModuleManagerDelegate> +@end + +@implementation RCTReactNativeFactory + +- (instancetype)initWithDelegate:(id)delegate +{ + if (self = [super init]) { + self.delegate = delegate; + [self _setUpFeatureFlags]; + + auto newArchEnabled = [self newArchEnabled]; + auto fabricEnabled = [self fabricEnabled]; + + RCTSetNewArchEnabled(newArchEnabled); + [RCTColorSpaceUtils applyDefaultColorSpace:[self defaultColorSpace]]; + RCTEnableTurboModule([self turboModuleEnabled]); + + self.rootViewFactory = [self createRCTRootViewFactory]; + + if (newArchEnabled || fabricEnabled) { + [RCTComponentViewFactory currentComponentViewFactory].thirdPartyFabricComponentsProvider = self; + } + } + + return self; +} + +#pragma mark - RCTUIConfiguratorProtocol + +- (RCTColorSpace)defaultColorSpace +{ + if ([_delegate respondsToSelector:@selector(defaultColorSpace)]) { + return [_delegate defaultColorSpace]; + } + + return RCTColorSpaceSRGB; +} + +- (NSURL *_Nullable)bundleURL +{ + if (![_delegate respondsToSelector:@selector(bundleURL)]) { + [NSException raise:@"RCTReactNativeFactoryDelegate::bundleURL not implemented" + format:@"Delegate must implement a valid getBundleURL method"]; + } + + return _delegate.bundleURL; +} + +#pragma mark - RCTArchConfiguratorProtocol + +- (BOOL)newArchEnabled +{ + if ([_delegate respondsToSelector:@selector(newArchEnabled)]) { + return _delegate.newArchEnabled; + } + +#if RCT_NEW_ARCH_ENABLED + return YES; +#else + return NO; +#endif +} + +- (BOOL)fabricEnabled +{ + if ([_delegate respondsToSelector:@selector(fabricEnabled)]) { + return _delegate.fabricEnabled; + } + + return [self newArchEnabled]; +} + +- (BOOL)turboModuleEnabled +{ + if ([_delegate respondsToSelector:@selector(turboModuleEnabled)]) { + return _delegate.turboModuleEnabled; + } + + return [self newArchEnabled]; +} + +- (BOOL)bridgelessEnabled +{ + if ([_delegate respondsToSelector:@selector(bridgelessEnabled)]) { + return _delegate.bridgelessEnabled; + } + + return [self newArchEnabled]; +} + +#pragma mark - RCTTurboModuleManagerDelegate + +- (Class)getModuleClassFromName:(const char *)name +{ +#if RN_DISABLE_OSS_PLUGIN_HEADER + return RCTTurboModulePluginClassProvider(name); +#else + return RCTCoreModulesClassProvider(name); +#endif +} + +- (std::shared_ptr)getTurboModule:(const std::string &)name + jsInvoker:(std::shared_ptr)jsInvoker +{ + if ([_delegate respondsToSelector:@selector(getTurboModule:jsInvoker:)]) { + return [_delegate getTurboModule:name jsInvoker:jsInvoker]; + } + + return facebook::react::DefaultTurboModules::getTurboModule(name, jsInvoker); +} + +- (id)getModuleInstanceFromClass:(Class)moduleClass +{ + return RCTAppSetupDefaultModuleFromClass(moduleClass, self.delegate.dependencyProvider); +} + +#pragma mark - RCTComponentViewFactoryComponentProvider + +- (NSDictionary> *)thirdPartyFabricComponents +{ + if ([_delegate respondsToSelector:@selector(thirdPartyFabricComponents)]) { + return _delegate.thirdPartyFabricComponents; + } + + return self.delegate.dependencyProvider ? self.delegate.dependencyProvider.thirdPartyFabricComponents : @{}; +} + +#pragma mark - RCTHostDelegate + +- (void)hostDidStart:(RCTHost *)host +{ + if ([_delegate respondsToSelector:@selector(hostDidStart:)]) { + [_delegate hostDidStart:host]; + } +} + +- (RCTRootViewFactory *)createRCTRootViewFactory +{ + __weak __typeof(self) weakSelf = self; + RCTBundleURLBlock bundleUrlBlock = ^{ + auto *strongSelf = weakSelf; + return strongSelf.bundleURL; + }; + + RCTRootViewFactoryConfiguration *configuration = + [[RCTRootViewFactoryConfiguration alloc] initWithBundleURLBlock:bundleUrlBlock + newArchEnabled:self.fabricEnabled + turboModuleEnabled:self.turboModuleEnabled + bridgelessEnabled:self.bridgelessEnabled]; + + configuration.createRootViewWithBridge = ^UIView *(RCTBridge *bridge, NSString *moduleName, NSDictionary *initProps) { + return [weakSelf.delegate createRootViewWithBridge:bridge moduleName:moduleName initProps:initProps]; + }; + + configuration.createBridgeWithDelegate = ^RCTBridge *(id delegate, NSDictionary *launchOptions) { + return [weakSelf.delegate createBridgeWithDelegate:delegate launchOptions:launchOptions]; + }; + + configuration.customizeRootView = ^(UIView *_Nonnull rootView) { + [weakSelf.delegate customizeRootView:(RCTRootView *)rootView]; + }; + + configuration.sourceURLForBridge = ^NSURL *_Nullable(RCTBridge *_Nonnull bridge) + { + return [weakSelf.delegate sourceURLForBridge:bridge]; + }; + + if ([self.delegate respondsToSelector:@selector(extraModulesForBridge:)]) { + configuration.extraModulesForBridge = ^NSArray> *_Nonnull(RCTBridge *_Nonnull bridge) + { + return [weakSelf.delegate extraModulesForBridge:bridge]; + }; + } + + if ([self.delegate respondsToSelector:@selector(extraLazyModuleClassesForBridge:)]) { + configuration.extraLazyModuleClassesForBridge = + ^NSDictionary *_Nonnull(RCTBridge *_Nonnull bridge) + { + return [weakSelf.delegate extraLazyModuleClassesForBridge:bridge]; + }; + } + + if ([self.delegate respondsToSelector:@selector(bridge:didNotFindModule:)]) { + configuration.bridgeDidNotFindModule = ^BOOL(RCTBridge *_Nonnull bridge, NSString *_Nonnull moduleName) { + return [weakSelf.delegate bridge:bridge didNotFindModule:moduleName]; + }; + } + + return [[RCTRootViewFactory alloc] initWithTurboModuleDelegate:self hostDelegate:self configuration:configuration]; +} + +#pragma mark - Feature Flags + +class RCTAppDelegateBridgelessFeatureFlags : public ReactNativeFeatureFlagsDefaults { + public: + bool enableBridgelessArchitecture() override + { + return true; + } + bool enableFabricRenderer() override + { + return true; + } + bool useTurboModules() override + { + return true; + } + bool useNativeViewConfigsInBridgelessMode() override + { + return true; + } +}; + +- (void)_setUpFeatureFlags +{ + if ([self bridgelessEnabled]) { + ReactNativeFeatureFlags::override(std::make_unique()); + } +} + +@end diff --git a/packages/rn-tester/RNTester/AppDelegate.mm b/packages/rn-tester/RNTester/AppDelegate.mm index c69b35ef677e27..a2d0ac54605ad3 100644 --- a/packages/rn-tester/RNTester/AppDelegate.mm +++ b/packages/rn-tester/RNTester/AppDelegate.mm @@ -9,7 +9,6 @@ #import -#import #import #import #import