From 51a3c731c2d9dd0f78dc4232685f7049e9c4eeff Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Mon, 10 Mar 2025 07:25:40 -0700 Subject: [PATCH 1/2] Deprecate RCT_NEW_ARCH_ENABLED (#49924) Summary: This change deprecates the RCT_NEW_ARCH_ENABLEd flag to toggle the New Architecture. The new approach bring iOS closer to Android: to diasable the New Architecture, user needs to modify the App's Info.plist and add a `RCTNewArchEnabled` boolean entry and set it to `NO`. The absence of the entry implies that the New Arch is enabled. (Defaults to enabled) This also deprecates the `RCTSetNewArchEnabled` function because it makes no sense now ## Context The RCT_NEW_ARCH_ENABLE flag is a compile time flag we used for almost two years to configure the iOS apps and to determine whether the app should build with the New Arch or not. However, given that we are looking into prebuilding React Native, we have to get rid of all the compilation flags, because they would require us to prebuild a combinatorial number of artifacts for react native. For example: - New Arch / Hermes - Old Arch / Hermes - New Arch / JSC - Old Arch / JSC - ... ## Backward compatibility We are going to keep adding the RCT_NEW_ARCH_ENABLED flag in all the dependencies, through the cocoapods inrastructure, so libraries, which are not prebuilt, will be build for the right architecture by the app itself. ## Changelog: [iOS][Deprecated] - deprecate the `RCT_NEW_ARCH_ENABLED` and the `RCTSetNewArchEnabled` Reviewed By: cortinico Differential Revision: D70885454 --- .../AppDelegate/RCTArchConfiguratorProtocol.h | 8 ++++---- .../RCTDefaultReactNativeFactoryDelegate.mm | 6 +----- .../Libraries/AppDelegate/RCTReactNativeFactory.mm | 8 +------- packages/react-native/React/Base/RCTUtils.h | 4 +++- packages/react-native/React/Base/RCTUtils.m | 12 ++++++++---- 5 files changed, 17 insertions(+), 21 deletions(-) diff --git a/packages/react-native/Libraries/AppDelegate/RCTArchConfiguratorProtocol.h b/packages/react-native/Libraries/AppDelegate/RCTArchConfiguratorProtocol.h index 888b7a7d8997c0..98882f0c202554 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTArchConfiguratorProtocol.h +++ b/packages/react-native/Libraries/AppDelegate/RCTArchConfiguratorProtocol.h @@ -15,22 +15,22 @@ NS_ASSUME_NONNULL_BEGIN /// /// @note: This is required to be rendering on Fabric (i.e. on the New Architecture). /// @return: `true` if the Turbo Native Module are enabled. Otherwise, it returns `false`. -- (BOOL)turboModuleEnabled __attribute__((deprecated("Use newArchEnabled instead"))); +- (BOOL)turboModuleEnabled __attribute__((deprecated("Use RCTIsNewArchEnabled instead"))); /// This method controls whether the App will use the Fabric renderer of the New Architecture or not. /// /// @return: `true` if the Fabric Renderer is enabled. Otherwise, it returns `false`. -- (BOOL)fabricEnabled __attribute__((deprecated("Use newArchEnabled instead"))); +- (BOOL)fabricEnabled __attribute__((deprecated("Use RCTIsNewArchEnabled instead"))); /// This method controls whether React Native's new initialization layer is enabled. /// /// @return: `true` if the new initialization layer is enabled. Otherwise returns `false`. -- (BOOL)bridgelessEnabled __attribute__((deprecated("Use newArchEnabled instead"))); +- (BOOL)bridgelessEnabled __attribute__((deprecated("Use RCTIsNewArchEnabled instead"))); /// This method controls whether React Native uses new Architecture. /// /// @return: `true` if the new architecture is enabled. Otherwise returns `false`. -- (BOOL)newArchEnabled; +- (BOOL)newArchEnabled __attribute__((deprecated("Use RCTIsNewArchEnabled instead"))); @end NS_ASSUME_NONNULL_END diff --git a/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm index 1c9da8919e7054..e0ef7d1ea9853b 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm @@ -108,11 +108,7 @@ - (void)hostDidStart:(RCTHost *)host - (BOOL)newArchEnabled { -#if RCT_NEW_ARCH_ENABLED - return YES; -#else - return NO; -#endif + return RCTIsNewArchEnabled(); } - (BOOL)bridgelessEnabled diff --git a/packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.mm b/packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.mm index 5d3a894c064e33..333197ee1de678 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.mm @@ -55,7 +55,6 @@ - (instancetype)initWithDelegate:(id)delegate rel auto newArchEnabled = [self newArchEnabled]; auto fabricEnabled = [self fabricEnabled]; - RCTSetNewArchEnabled(newArchEnabled); [RCTColorSpaceUtils applyDefaultColorSpace:[self defaultColorSpace]]; RCTEnableTurboModule([self turboModuleEnabled]); @@ -130,12 +129,7 @@ - (BOOL)newArchEnabled if ([_delegate respondsToSelector:@selector(newArchEnabled)]) { return _delegate.newArchEnabled; } - -#if RCT_NEW_ARCH_ENABLED - return YES; -#else - return NO; -#endif + return RCTIsNewArchEnabled(); } - (BOOL)fabricEnabled diff --git a/packages/react-native/React/Base/RCTUtils.h b/packages/react-native/React/Base/RCTUtils.h index 313ffc2f7f90fc..ca53b7b93bb9d5 100644 --- a/packages/react-native/React/Base/RCTUtils.h +++ b/packages/react-native/React/Base/RCTUtils.h @@ -18,7 +18,9 @@ NS_ASSUME_NONNULL_BEGIN // Whether the New Architecture is enabled or not RCT_EXTERN BOOL RCTIsNewArchEnabled(void); -RCT_EXTERN void RCTSetNewArchEnabled(BOOL enabled); +RCT_EXTERN void RCTSetNewArchEnabled(BOOL enabled) __attribute__((deprecated( + "This function is now no-op. You need to modify the Info.plist adding a RCTNewArchEnabled bool property to control whether the New Arch is enabled or not"))); +; // JSON serialization/deserialization RCT_EXTERN NSString *__nullable RCTJSONStringify(id __nullable jsonObject, NSError **error); diff --git a/packages/react-native/React/Base/RCTUtils.m b/packages/react-native/React/Base/RCTUtils.m index 7a3172bccbd53f..7ee4e0265588b7 100644 --- a/packages/react-native/React/Base/RCTUtils.m +++ b/packages/react-native/React/Base/RCTUtils.m @@ -37,14 +37,18 @@ static BOOL _newArchEnabled = false; BOOL RCTIsNewArchEnabled(void) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSNumber *rctNewArchEnabled = (NSNumber *)[[NSBundle mainBundle] objectForInfoDictionaryKey:@"RCTNewArchEnabled"]; + _newArchEnabled = rctNewArchEnabled == nil || rctNewArchEnabled.boolValue; + }); return _newArchEnabled; } void RCTSetNewArchEnabled(BOOL enabled) { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - _newArchEnabled = enabled; - }); + // This function is now deprecated and will be removed in the future. + // This function is now no-op. You need to modify the Info.plist adding a `RCTNewArchEnabled` bool property to control + // whether the New Arch is enabled or not. } static NSString *__nullable _RCTJSONStringifyNoRetry(id __nullable jsonObject, NSError **error) From 7ed07925e8a882d23db7fc793bde0d4ca95995e7 Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Mon, 10 Mar 2025 07:25:40 -0700 Subject: [PATCH 2/2] Automate setting the `RCTNewArchEnabled` flag (#49927) Summary: This change automates updating App's Info.plist with the new `RCTNewArchEnabled` boolean entry. The value depends on how the pod install is set up. In this way, we maintain the previous UX to enable/disable the New Arch. ## Context The RCT_NEW_ARCH_ENABLE flag is a compile time flag we used for almost two years to configure the iOS apps and to determine whether the app should build with the New Arch or not. However, given that we are looking into prebuilding React Native, we have to get rid of all the compilation flags, because they would require us to prebuild a combinatorial number of artifacts for react native. For example: - New Arch / Hermes - Old Arch / Hermes - New Arch / JSC - Old Arch / JSC - ... ## Backward compatibility We are going to keep adding the RCT_NEW_ARCH_ENABLED flag in all the dependencies, through the cocoapods inrastructure, so libraries, which are not prebuilt, will be build for the right architecture by the app itself. ## Changelog: [iOS][Added] - Reviewed By: cortinico Differential Revision: D70888212 --- .../scripts/cocoapods/new_architecture.rb | 37 +++++++++++++++++++ .../react-native/scripts/react_native_pods.rb | 1 + 2 files changed, 38 insertions(+) diff --git a/packages/react-native/scripts/cocoapods/new_architecture.rb b/packages/react-native/scripts/cocoapods/new_architecture.rb index 6354cd5a984c7f..97c91d14c282e1 100644 --- a/packages/react-native/scripts/cocoapods/new_architecture.rb +++ b/packages/react-native/scripts/cocoapods/new_architecture.rb @@ -9,6 +9,7 @@ require_relative "./helpers.rb" require_relative "./jsengine.rb" + class NewArchitectureHelper @@NewArchWarningEmitted = false # Used not to spam warnings to the user. @@ -159,4 +160,40 @@ def self.extract_react_native_version(react_native_path, file_manager: File, jso def self.new_arch_enabled return ENV["RCT_NEW_ARCH_ENABLED"] == '0' ? false : true end + + def self.set_RCTNewArchEnabled_in_info_plist(installer, new_arch_enabled) + projectPaths = installer.aggregate_targets + .map{ |t| t.user_project } + .uniq{ |p| p.path } + .map{ |p| p.path } + + excluded_info_plist = ["/Pods", "Tests", "metainternal", ".bundle"] + projectPaths.each do |projectPath| + projectFolderPath = File.dirname(projectPath) + infoPlistFiles = `find #{projectFolderPath} -name "Info.plist"` + infoPlistFiles = infoPlistFiles.split("\n").map { |f| f.strip } + + infoPlistFiles.each do |infoPlistFile| + # If infoPlistFile contains Pods or tests, skip it + should_skip = false + excluded_info_plist.each do |excluded| + if infoPlistFile.include? excluded + should_skip = true + end + end + next if should_skip + + # Read the file as a plist + info_plist = Xcodeproj::Plist.read_from_path(infoPlistFile) + # Check if it contains the RCTNewArchEnabled key + if info_plist["RCTNewArchEnabled"] and info_plist["RCTNewArchEnabled"] == new_arch_enabled + next + end + + # Add the key and value to the plist + info_plist["RCTNewArchEnabled"] = new_arch_enabled ? true : false + Xcodeproj::Plist.write_to_path(info_plist, infoPlistFile) + end + end + end end diff --git a/packages/react-native/scripts/react_native_pods.rb b/packages/react-native/scripts/react_native_pods.rb index 3b47cf5187e49a..c221e0c5726d65 100644 --- a/packages/react-native/scripts/react_native_pods.rb +++ b/packages/react-native/scripts/react_native_pods.rb @@ -451,6 +451,7 @@ def react_native_post_install( NewArchitectureHelper.set_clang_cxx_language_standard_if_needed(installer) NewArchitectureHelper.modify_flags_for_new_architecture(installer, NewArchitectureHelper.new_arch_enabled) + NewArchitectureHelper.set_RCTNewArchEnabled_in_info_plist(installer, NewArchitectureHelper.new_arch_enabled) if ENV['USE_HERMES'] == '0' && ENV['USE_THIRD_PARTY_JSC'] != '1' print_jsc_removal_message()