From 3e88fd01cecfa9c627506c8ab0081d1e4865862a Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Tue, 21 Feb 2023 04:17:26 -0800 Subject: [PATCH] Install the RuntimeScheduler when the New Architecture is enabled (#36209) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/36209 ThisChange automatically enable the RuntimeScheduler when the new architecture is enabled, both on RNester and in the Template app. Note that no migration steps are required. ## Changelog [iOS][Changed] - Automatically install the RuntimeScheduler Reviewed By: sammy-SC Differential Revision: D43392059 fbshipit-source-id: 609ded9bdc3db13a0d54ff44d0d4687dfc8617a5 --- Libraries/AppDelegate/RCTAppDelegate.mm | 23 +++++--- Libraries/AppDelegate/RCTAppSetupUtils.h | 8 ++- Libraries/AppDelegate/RCTAppSetupUtils.mm | 25 +++++---- packages/rn-tester/RNTester/AppDelegate.mm | 37 ++++++++++--- scripts/cocoapods/__tests__/utils-test.rb | 62 ++++++++++++++++++++++ scripts/cocoapods/utils.rb | 22 ++++++++ scripts/react_native_pods.rb | 3 ++ 7 files changed, 154 insertions(+), 26 deletions(-) diff --git a/Libraries/AppDelegate/RCTAppDelegate.mm b/Libraries/AppDelegate/RCTAppDelegate.mm index 5b48b26545a..d211a8732c8 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 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot"; 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 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot"; 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 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot"; #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 06e12d7317c..990fb77ef1a 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 4d58caebfe2..c7701867ecf 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 @@ id RCTAppSetupDefaultModuleFromClass(Class moduleClass) 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 @@ std::unique_ptr RCTAppSetupDefaultJsExecutor #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 8fafba03430..a969c28201a 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 @@ RCTSurfacePresenterBridgeAdapter *_bridgeAdapter; std::shared_ptr _reactNativeConfig; facebook::react::ContextContainer::Shared _contextContainer; + std::shared_ptr _runtimeScheduler; #endif RCTTurboModuleManager *_turboModuleManager; @@ -84,17 +92,18 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot"; { 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 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot"; #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 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot"; #endif __weak __typeof(self) weakSelf = self; + #if RCT_USE_HERMES return std::make_unique( #else @@ -200,6 +218,9 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot"; 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 9bcf81b38f5..765c3426db3 100644 --- a/scripts/cocoapods/__tests__/utils-test.rb +++ b/scripts/cocoapods/__tests__/utils-test.rb @@ -597,6 +597,68 @@ class UtilsTests < Test::Unit::TestCase 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 bb784b42eda..b8d29042d9c 100644 --- a/scripts/cocoapods/utils.rb +++ b/scripts/cocoapods/utils.rb @@ -131,6 +131,28 @@ class ReactNativePodsUtils 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 7b66c7823d2..c83df4f397d 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"