diff --git a/Libraries/AppDelegate/RCTAppDelegate.mm b/Libraries/AppDelegate/RCTAppDelegate.mm index 5b48b26545a673..d211a8732c8f33 100644 --- a/Libraries/AppDelegate/RCTAppDelegate.mm +++ b/Libraries/AppDelegate/RCTAppDelegate.mm @@ -17,12 +17,15 @@ #import #import #import +#import +#import static NSString *const kRNConcurrentRoot = @"concurrentRoot"; @interface RCTAppDelegate () { std::shared_ptr _reactNativeConfig; facebook::react::ContextContainer::Shared _contextContainer; + std::shared_ptr _runtimeScheduler; } @end @@ -35,6 +38,10 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( BOOL enableTM = NO; #if RCT_NEW_ARCH_ENABLED enableTM = self.turboModuleEnabled; + + _contextContainer = std::make_shared(); + _reactNativeConfig = std::make_shared(); + _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); #endif RCTAppSetupPrepareApp(application, enableTM); @@ -43,9 +50,6 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( self.bridge = [self createBridgeWithDelegate:self launchOptions:launchOptions]; } #if RCT_NEW_ARCH_ENABLED - _contextContainer = std::make_shared(); - _reactNativeConfig = std::make_shared(); - _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); self.bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:self.bridge contextContainer:_contextContainer]; self.bridge.surfacePresenter = self.bridgeAdapter.surfacePresenter; @@ -112,13 +116,16 @@ - (UIViewController *)createRootViewController #if RCT_NEW_ARCH_ENABLED #pragma mark - RCTCxxBridgeDelegate - - (std::unique_ptr)jsExecutorFactoryForBridge:(RCTBridge *)bridge { - self.turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge - delegate:self - jsInvoker:bridge.jsCallInvoker]; - return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager); + _runtimeScheduler = _runtimeScheduler = + std::make_shared(RCTRuntimeExecutorFromBridge(bridge)); + std::shared_ptr callInvoker = + std::make_shared(_runtimeScheduler); + self.turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge delegate:self jsInvoker:callInvoker]; + _contextContainer->erase("RuntimeScheduler"); + _contextContainer->insert("RuntimeScheduler", _runtimeScheduler); + return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager, _runtimeScheduler); } #pragma mark RCTTurboModuleManagerDelegate diff --git a/Libraries/AppDelegate/RCTAppSetupUtils.h b/Libraries/AppDelegate/RCTAppSetupUtils.h index 06e12d7317c421..990fb77ef1a224 100644 --- a/Libraries/AppDelegate/RCTAppSetupUtils.h +++ b/Libraries/AppDelegate/RCTAppSetupUtils.h @@ -31,11 +31,17 @@ #endif #if RCT_NEW_ARCH_ENABLED +// Forward declaration to decrease compilation coupling +namespace facebook::react { +class RuntimeScheduler; +} + RCT_EXTERN id RCTAppSetupDefaultModuleFromClass(Class moduleClass); std::unique_ptr RCTAppSetupDefaultJsExecutorFactory( RCTBridge *bridge, - RCTTurboModuleManager *turboModuleManager); + RCTTurboModuleManager *turboModuleManager, + std::shared_ptr const &runtimeScheduler); #endif #endif // __cplusplus diff --git a/Libraries/AppDelegate/RCTAppSetupUtils.mm b/Libraries/AppDelegate/RCTAppSetupUtils.mm index 4d58caebfe2e13..c7701867ecf9c7 100644 --- a/Libraries/AppDelegate/RCTAppSetupUtils.mm +++ b/Libraries/AppDelegate/RCTAppSetupUtils.mm @@ -21,6 +21,8 @@ // Fabric #import +#import +#import #endif #ifdef FB_SONARKIT_ENABLED @@ -96,7 +98,8 @@ void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled) std::unique_ptr RCTAppSetupDefaultJsExecutorFactory( RCTBridge *bridge, - RCTTurboModuleManager *turboModuleManager) + RCTTurboModuleManager *turboModuleManager, + std::shared_ptr const &runtimeScheduler) { // Necessary to allow NativeModules to lookup TurboModules [bridge setRCTTurboModuleRegistry:turboModuleManager]; @@ -118,14 +121,18 @@ void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled) #else return std::make_unique( #endif - facebook::react::RCTJSIExecutorRuntimeInstaller([turboModuleManager, bridge](facebook::jsi::Runtime &runtime) { - if (!bridge || !turboModuleManager) { - return; - } - facebook::react::RuntimeExecutor syncRuntimeExecutor = - [&](std::function &&callback) { callback(runtime); }; - [turboModuleManager installJSBindingWithRuntimeExecutor:syncRuntimeExecutor]; - })); + facebook::react::RCTJSIExecutorRuntimeInstaller( + [turboModuleManager, bridge, runtimeScheduler](facebook::jsi::Runtime &runtime) { + if (!bridge || !turboModuleManager) { + return; + } + if (runtimeScheduler) { + facebook::react::RuntimeSchedulerBinding::createAndInstallIfNeeded(runtime, runtimeScheduler); + } + facebook::react::RuntimeExecutor syncRuntimeExecutor = + [&](std::function &&callback) { callback(runtime); }; + [turboModuleManager installJSBindingWithRuntimeExecutor:syncRuntimeExecutor]; + })); } #endif diff --git a/packages/rn-tester/RNTester/AppDelegate.mm b/packages/rn-tester/RNTester/AppDelegate.mm index 8fafba034302ba..a969c28201ae62 100644 --- a/packages/rn-tester/RNTester/AppDelegate.mm +++ b/packages/rn-tester/RNTester/AppDelegate.mm @@ -15,6 +15,10 @@ #endif #endif +#ifdef RCT_NEW_ARCH_ENABLED +#define RN_FABRIC_ENABLED +#endif + #if RCT_USE_HERMES #import #else @@ -48,6 +52,9 @@ #import #import +#import +#import +#import #endif #if DEBUG @@ -70,6 +77,7 @@ @interface AppDelegate () RCTSurfacePresenterBridgeAdapter *_bridgeAdapter; std::shared_ptr _reactNativeConfig; facebook::react::ContextContainer::Shared _contextContainer; + std::shared_ptr _runtimeScheduler; #endif RCTTurboModuleManager *_turboModuleManager; @@ -84,17 +92,18 @@ - (BOOL)application:(__unused UIApplication *)application didFinishLaunchingWith { RCTEnableTurboModule(YES); +#ifdef RN_FABRIC_ENABLED + _contextContainer = std::make_shared(); + _reactNativeConfig = std::make_shared(); + _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); +#endif + _bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; // Appetizer.io params check NSDictionary *initProps = [self prepareInitialProps]; #ifdef RN_FABRIC_ENABLED - _contextContainer = std::make_shared(); - _reactNativeConfig = std::make_shared(); - - _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); - _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:_bridge contextContainer:_contextContainer]; _bridge.surfacePresenter = _bridgeAdapter.surfacePresenter; @@ -174,11 +183,19 @@ - (void)loadSourceForBridge:(RCTBridge *)bridge #pragma mark - RCTCxxBridgeDelegate +// This function is called during +// `[[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];` - (std::unique_ptr)jsExecutorFactoryForBridge:(RCTBridge *)bridge { - _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge - delegate:self - jsInvoker:bridge.jsCallInvoker]; + std::shared_ptr callInvoker = bridge.jsCallInvoker; + +#ifdef RCT_NEW_ARCH_ENABLED + _runtimeScheduler = std::make_shared(RCTRuntimeExecutorFromBridge(bridge)); + _contextContainer->erase("RuntimeScheduler"); + _contextContainer->insert("RuntimeScheduler", _runtimeScheduler); + callInvoker = std::make_shared(_runtimeScheduler); +#endif + _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge delegate:self jsInvoker:callInvoker]; [bridge setRCTTurboModuleRegistry:_turboModuleManager]; #if RCT_DEV @@ -190,6 +207,7 @@ - (void)loadSourceForBridge:(RCTBridge *)bridge #endif __weak __typeof(self) weakSelf = self; + #if RCT_USE_HERMES return std::make_unique( #else @@ -200,6 +218,9 @@ - (void)loadSourceForBridge:(RCTBridge *)bridge return; } __typeof(self) strongSelf = weakSelf; + if (strongSelf && strongSelf->_runtimeScheduler) { + facebook::react::RuntimeSchedulerBinding::createAndInstallIfNeeded(runtime, strongSelf->_runtimeScheduler); + } if (strongSelf) { facebook::react::RuntimeExecutor syncRuntimeExecutor = [&](std::function &&callback) { callback(runtime); }; diff --git a/scripts/cocoapods/__tests__/utils-test.rb b/scripts/cocoapods/__tests__/utils-test.rb index 9bcf81b38f58d6..765c3426db35e5 100644 --- a/scripts/cocoapods/__tests__/utils-test.rb +++ b/scripts/cocoapods/__tests__/utils-test.rb @@ -597,6 +597,68 @@ def test_updateSearchPaths_whenNotUseFrameworks_addsSearchPaths end end +# ============================= # +# Test - Apply Flags For Fabric # +# ============================= # +def test_applyFlagsForFabric_whenFabricEnabled_addsTheFlag + # Arrange + first_target = prepare_target("FirstTarget") + second_target = prepare_target("SecondTarget") + third_target = prepare_target("ThirdTarget", "com.apple.product-type.bundle") + user_project_mock = UserProjectMock.new("a/path", [ + prepare_config("Debug"), + prepare_config("Release"), + ], + :native_targets => [ + first_target, + second_target + ] + ) + pods_projects_mock = PodsProjectMock.new([third_target], {"hermes-engine" => {}}) + installer = InstallerMock.new(pods_projects_mock, [ + AggregatedProjectMock.new(user_project_mock) + ]) + + # Act + ReactNativePodsUtils.apply_flags_for_fabric(installer, fabric_enabled: true) + + # Assert + user_project_mock.build_configurations.each do |config| + received_cflags = config.build_settings["OTHER_CFLAGS"] + expected_cflags = "$(inherited) -DRN_FABRIC_ENABLED" + assert_equal(received_cflags, expected_cflags) + end + +end + +def test_applyFlagsForFabric_whenFabricDisabled_doNothing + # Arrange + first_target = prepare_target("FirstTarget") + second_target = prepare_target("SecondTarget") + third_target = prepare_target("ThirdTarget", "com.apple.product-type.bundle") + user_project_mock = UserProjectMock.new("a/path", [ + prepare_config("Debug"), + prepare_config("Release"), + ], + :native_targets => [ + first_target, + second_target + ] + ) + pods_projects_mock = PodsProjectMock.new([third_target], {"hermes-engine" => {}}) + installer = InstallerMock.new(pods_projects_mock, [ + AggregatedProjectMock.new(user_project_mock) + ]) + + # Act + ReactNativePodsUtils.apply_flags_for_fabric(installer, fabric_enabled: false) + + # Assert + user_project_mock.build_configurations.each do |config| + assert_nil(config.build_settings["OTHER_CFLAGS"]) + end +end + # ===== # # UTILS # diff --git a/scripts/cocoapods/utils.rb b/scripts/cocoapods/utils.rb index bb784b42edab20..b8d29042d9c81a 100644 --- a/scripts/cocoapods/utils.rb +++ b/scripts/cocoapods/utils.rb @@ -131,6 +131,28 @@ def self.apply_mac_catalyst_patches(installer) end end + def self.apply_flags_for_fabric(installer, fabric_enabled: false) + return if !fabric_enabled + + fabric_flag = "-DRN_FABRIC_ENABLED" + projects = installer.aggregate_targets + .map{ |t| t.user_project } + .uniq{ |p| p.path } + .push(installer.pods_project) + + projects.each do |project| + project.build_configurations.each do |config| + cflags = config.build_settings["OTHER_CFLAGS"] ? config.build_settings["OTHER_CFLAGS"] : "$(inherited)" + + if !cflags.include?(fabric_flag) + cflags = "#{cflags} #{fabric_flag}" + end + config.build_settings["OTHER_CFLAGS"] = cflags + end + project.save() + end + end + private def self.fix_library_search_path(config) diff --git a/scripts/react_native_pods.rb b/scripts/react_native_pods.rb index 7b66c7823d23ca..c83df4f397d29a 100644 --- a/scripts/react_native_pods.rb +++ b/scripts/react_native_pods.rb @@ -212,10 +212,13 @@ def react_native_post_install(installer, react_native_path = "../node_modules/re flipper_post_install(installer) end + fabric_enabled = ReactNativePodsUtils.has_pod(installer, 'React-Fabric') + ReactNativePodsUtils.exclude_i386_architecture_while_using_hermes(installer) ReactNativePodsUtils.fix_library_search_paths(installer) ReactNativePodsUtils.update_search_paths(installer) ReactNativePodsUtils.set_node_modules_user_settings(installer, react_native_path) + ReactNativePodsUtils.apply_flags_for_fabric(installer, fabric_enabled: fabric_enabled) NewArchitectureHelper.set_clang_cxx_language_standard_if_needed(installer) is_new_arch_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == "1"