Skip to content

Commit

Permalink
Install the RuntimeScheduler when the New Architecture is enabled (#3…
Browse files Browse the repository at this point in the history
…6209)

Summary:
Pull Request resolved: #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
  • Loading branch information
cipolleschi authored and facebook-github-bot committed Feb 21, 2023
1 parent 8be9dbf commit 3e88fd0
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 26 deletions.
23 changes: 15 additions & 8 deletions Libraries/AppDelegate/RCTAppDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@
#import <React/RCTSurfacePresenterBridgeAdapter.h>
#import <ReactCommon/RCTTurboModuleManager.h>
#import <react/config/ReactNativeConfig.h>
#import <react/renderer/runtimescheduler/RuntimeScheduler.h>
#import <react/renderer/runtimescheduler/RuntimeSchedulerCallInvoker.h>

static NSString *const kRNConcurrentRoot = @"concurrentRoot";

@interface RCTAppDelegate () <RCTTurboModuleManagerDelegate, RCTCxxBridgeDelegate> {
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
facebook::react::ContextContainer::Shared _contextContainer;
std::shared_ptr<facebook::react::RuntimeScheduler> _runtimeScheduler;
}
@end

Expand All @@ -35,6 +38,10 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
BOOL enableTM = NO;
#if RCT_NEW_ARCH_ENABLED
enableTM = self.turboModuleEnabled;

_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
#endif

RCTAppSetupPrepareApp(application, enableTM);
Expand All @@ -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<facebook::react::ContextContainer const>();
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
self.bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:self.bridge
contextContainer:_contextContainer];
self.bridge.surfacePresenter = self.bridgeAdapter.surfacePresenter;
Expand Down Expand Up @@ -112,13 +116,16 @@ - (UIViewController *)createRootViewController

#if RCT_NEW_ARCH_ENABLED
#pragma mark - RCTCxxBridgeDelegate

- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
{
self.turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
delegate:self
jsInvoker:bridge.jsCallInvoker];
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
_runtimeScheduler = _runtimeScheduler =
std::make_shared<facebook::react::RuntimeScheduler>(RCTRuntimeExecutorFromBridge(bridge));
std::shared_ptr<facebook::react::CallInvoker> callInvoker =
std::make_shared<facebook::react::RuntimeSchedulerCallInvoker>(_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
Expand Down
8 changes: 7 additions & 1 deletion Libraries/AppDelegate/RCTAppSetupUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,17 @@
#endif

#if RCT_NEW_ARCH_ENABLED
// Forward declaration to decrease compilation coupling
namespace facebook::react {
class RuntimeScheduler;
}

RCT_EXTERN id<RCTTurboModule> RCTAppSetupDefaultModuleFromClass(Class moduleClass);

std::unique_ptr<facebook::react::JSExecutorFactory> RCTAppSetupDefaultJsExecutorFactory(
RCTBridge *bridge,
RCTTurboModuleManager *turboModuleManager);
RCTTurboModuleManager *turboModuleManager,
std::shared_ptr<facebook::react::RuntimeScheduler> const &runtimeScheduler);
#endif

#endif // __cplusplus
Expand Down
25 changes: 16 additions & 9 deletions Libraries/AppDelegate/RCTAppSetupUtils.mm
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

// Fabric
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#import <react/renderer/runtimescheduler/RuntimeScheduler.h>
#import <react/renderer/runtimescheduler/RuntimeSchedulerBinding.h>
#endif

#ifdef FB_SONARKIT_ENABLED
Expand Down Expand Up @@ -96,7 +98,8 @@ void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled)

std::unique_ptr<facebook::react::JSExecutorFactory> RCTAppSetupDefaultJsExecutorFactory(
RCTBridge *bridge,
RCTTurboModuleManager *turboModuleManager)
RCTTurboModuleManager *turboModuleManager,
std::shared_ptr<facebook::react::RuntimeScheduler> const &runtimeScheduler)
{
// Necessary to allow NativeModules to lookup TurboModules
[bridge setRCTTurboModuleRegistry:turboModuleManager];
Expand All @@ -118,14 +121,18 @@ void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled)
#else
return std::make_unique<facebook::react::JSCExecutorFactory>(
#endif
facebook::react::RCTJSIExecutorRuntimeInstaller([turboModuleManager, bridge](facebook::jsi::Runtime &runtime) {
if (!bridge || !turboModuleManager) {
return;
}
facebook::react::RuntimeExecutor syncRuntimeExecutor =
[&](std::function<void(facebook::jsi::Runtime & runtime_)> &&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<void(facebook::jsi::Runtime & runtime_)> &&callback) { callback(runtime); };
[turboModuleManager installJSBindingWithRuntimeExecutor:syncRuntimeExecutor];
}));
}

#endif
37 changes: 29 additions & 8 deletions packages/rn-tester/RNTester/AppDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
#endif
#endif

#ifdef RCT_NEW_ARCH_ENABLED
#define RN_FABRIC_ENABLED
#endif

#if RCT_USE_HERMES
#import <reacthermes/HermesExecutorFactory.h>
#else
Expand Down Expand Up @@ -48,6 +52,9 @@
#import <React/RCTSurfacePresenterBridgeAdapter.h>

#import <react/config/ReactNativeConfig.h>
#import <react/renderer/runtimescheduler/RuntimeScheduler.h>
#import <react/renderer/runtimescheduler/RuntimeSchedulerBinding.h>
#import <react/renderer/runtimescheduler/RuntimeSchedulerCallInvoker.h>
#endif

#if DEBUG
Expand All @@ -70,6 +77,7 @@ @interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate>
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
facebook::react::ContextContainer::Shared _contextContainer;
std::shared_ptr<facebook::react::RuntimeScheduler> _runtimeScheduler;
#endif

RCTTurboModuleManager *_turboModuleManager;
Expand All @@ -84,17 +92,18 @@ - (BOOL)application:(__unused UIApplication *)application didFinishLaunchingWith
{
RCTEnableTurboModule(YES);

#ifdef RN_FABRIC_ENABLED
_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
_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<facebook::react::ContextContainer const>();
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();

_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);

_bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:_bridge contextContainer:_contextContainer];

_bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
Expand Down Expand Up @@ -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<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
{
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
delegate:self
jsInvoker:bridge.jsCallInvoker];
std::shared_ptr<facebook::react::CallInvoker> callInvoker = bridge.jsCallInvoker;

#ifdef RCT_NEW_ARCH_ENABLED
_runtimeScheduler = std::make_shared<facebook::react::RuntimeScheduler>(RCTRuntimeExecutorFromBridge(bridge));
_contextContainer->erase("RuntimeScheduler");
_contextContainer->insert("RuntimeScheduler", _runtimeScheduler);
callInvoker = std::make_shared<facebook::react::RuntimeSchedulerCallInvoker>(_runtimeScheduler);
#endif
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge delegate:self jsInvoker:callInvoker];
[bridge setRCTTurboModuleRegistry:_turboModuleManager];

#if RCT_DEV
Expand All @@ -190,6 +207,7 @@ - (void)loadSourceForBridge:(RCTBridge *)bridge
#endif

__weak __typeof(self) weakSelf = self;

#if RCT_USE_HERMES
return std::make_unique<facebook::react::HermesExecutorFactory>(
#else
Expand All @@ -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<void(facebook::jsi::Runtime & runtime_)> &&callback) { callback(runtime); };
Expand Down
62 changes: 62 additions & 0 deletions scripts/cocoapods/__tests__/utils-test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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 #
Expand Down
22 changes: 22 additions & 0 deletions scripts/cocoapods/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions scripts/react_native_pods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down

0 comments on commit 3e88fd0

Please sign in to comment.