1# Copyright (c) Meta Platforms, Inc. and affiliates. 2# 3# This source code is licensed under the MIT license found in the 4# LICENSE file in the root directory of this source tree. 5 6require 'json' 7require 'open3' 8require 'pathname' 9require_relative './react_native_pods_utils/script_phases.rb' 10require_relative './cocoapods/jsengine.rb' 11require_relative './cocoapods/flipper.rb' 12require_relative './cocoapods/fabric.rb' 13require_relative './cocoapods/codegen.rb' 14require_relative './cocoapods/codegen_utils.rb' 15require_relative './cocoapods/utils.rb' 16require_relative './cocoapods/new_architecture.rb' 17require_relative './cocoapods/local_podspec_patch.rb' 18 19$ABI49_0_0CODEGEN_OUTPUT_DIR = 'versioned-react-native/ABI49_0_0/ReactNative/codegen/ios' 20$CODEGEN_COMPONENT_DIR = 'react/renderer/components' 21$CODEGEN_MODULE_DIR = '.' 22$FOLLY_VERSION = '2021.07.22.00' 23 24$START_TIME = Time.now.to_i 25 26# `@react-native-community/cli-platform-ios/native_modules` defines 27# use_native_modules. We use node to resolve its path to allow for 28# different packager and workspace setups. This is reliant on 29# `@react-native-community/cli-platform-ios` being a direct dependency 30# of `react-native`. 31require Pod::Executable.execute_command('node', ['-p', 32 'require.resolve( 33 "@react-native-community/cli-platform-ios/native_modules.rb", 34 {paths: [process.argv[1]]}, 35 )', __dir__]).strip 36 37# This function returns the min iOS version supported by React Native 38# By using this function, you won't have to manually change your Podfile 39# when we change the minimum version supported by the framework. 40def min_ios_version_supported 41 return '12.4' 42end 43 44# This function prepares the project for React Native, before processing 45# all the target exposed by the framework. 46def prepare_react_native_project! 47 # Temporary solution to suppress duplicated GUID error. 48 # Can be removed once we move to generate files outside pod install. 49 install! 'cocoapods', :deterministic_uuids => false 50 51 ReactNativePodsUtils.create_xcode_env_if_missing 52end 53 54# Function that setup all the react native dependencies 55# 56# Parameters 57# - path: path to react_native installation. 58# - fabric_enabled: whether fabric should be enabled or not. 59# - new_arch_enabled: whether the new architecture should be enabled or not. 60# - production: whether the dependencies must be installed to target a Debug or a Release build. 61# - hermes_enabled: whether Hermes should be enabled or not. 62# - flipper_configuration: The configuration to use for flipper. 63# - app_path: path to the React Native app. Required by the New Architecture. 64# - config_file_dir: directory of the `package.json` file, required by the New Architecture. 65# - ios_folder: the folder where the iOS code base lives. For a template app, it is `ios`, the default. For RNTester, it is `.`. 66def use_react_native_ABI49_0_0! ( 67 path: "../node_modules/react-native", 68 fabric_enabled: false, 69 new_arch_enabled: ENV['RCT_NEW_ARCH_ENABLED'] == '1', 70 production: ENV['PRODUCTION'] == '1', 71 hermes_enabled: ENV['USE_HERMES'] && ENV['USE_HERMES'] == '0' ? false : true, 72 flipper_configuration: FlipperConfiguration.disabled, 73 app_path: '..', 74 config_file_dir: '', 75 ios_folder: 'ios' 76) 77 78 # Set the app_path as env variable so the podspecs can access it. 79 ENV['APP_PATH'] = app_path 80 ENV['REACT_NATIVE_PATH'] = path 81 82 # Current target definition is provided by Cocoapods and it refers to the target 83 # that has invoked the `use_react_native!` function. 84 ReactNativePodsUtils.detect_use_frameworks(current_target_definition) 85 86 87 # We are relying on this flag also in third parties libraries to proper install dependencies. 88 # Better to rely and enable this environment flag if the new architecture is turned on using flags. 89 ENV['RCT_NEW_ARCH_ENABLED'] = new_arch_enabled ? "1" : "0" 90 fabric_enabled = fabric_enabled || new_arch_enabled 91 ENV['RCT_FABRIC_ENABLED'] = fabric_enabled ? "1" : "0" 92 ENV['USE_HERMES'] = hermes_enabled ? "1" : "0" 93 94 prefix = path 95 96 ReactNativePodsUtils.warn_if_not_on_arm64() 97 98 # The Pods which should be included in all projects 99 pod 'ABI49_0_0FBLazyVector', :path => "#{prefix}/Libraries/FBLazyVector", :project_name => 'ABI49_0_0' 100 pod 'ABI49_0_0FBReactNativeSpec', :path => "#{prefix}/React/FBReactNativeSpec", :project_name => 'ABI49_0_0' if !new_arch_enabled 101 pod 'ABI49_0_0RCTRequired', :path => "#{prefix}/Libraries/RCTRequired", :project_name => 'ABI49_0_0' 102 pod 'ABI49_0_0RCTTypeSafety', :path => "#{prefix}/Libraries/TypeSafety", :project_name => 'ABI49_0_0', :modular_headers => true 103 pod 'ABI49_0_0React', :path => "#{prefix}/", :project_name => 'ABI49_0_0' 104 pod 'ABI49_0_0React-Core', :path => "#{prefix}/", :project_name => 'ABI49_0_0' 105 pod 'ABI49_0_0React-CoreModules', :path => "#{prefix}/React/CoreModules", :project_name => 'ABI49_0_0' 106 pod 'ABI49_0_0React-RCTAppDelegate', :path => "#{prefix}/Libraries/AppDelegate", :project_name => 'ABI49_0_0' 107 pod 'ABI49_0_0React-RCTActionSheet', :path => "#{prefix}/Libraries/ActionSheetIOS", :project_name => 'ABI49_0_0' 108 pod 'ABI49_0_0React-RCTAnimation', :path => "#{prefix}/Libraries/NativeAnimation", :project_name => 'ABI49_0_0' 109 pod 'ABI49_0_0React-RCTBlob', :path => "#{prefix}/Libraries/Blob", :project_name => 'ABI49_0_0' 110 pod 'ABI49_0_0React-RCTImage', :path => "#{prefix}/Libraries/Image", :project_name => 'ABI49_0_0' 111 pod 'ABI49_0_0React-RCTLinking', :path => "#{prefix}/Libraries/LinkingIOS", :project_name => 'ABI49_0_0' 112 pod 'ABI49_0_0React-RCTNetwork', :path => "#{prefix}/Libraries/Network", :project_name => 'ABI49_0_0' 113 pod 'ABI49_0_0React-RCTSettings', :path => "#{prefix}/Libraries/Settings", :project_name => 'ABI49_0_0' 114 pod 'ABI49_0_0React-RCTText', :path => "#{prefix}/Libraries/Text", :project_name => 'ABI49_0_0' 115 pod 'ABI49_0_0React-RCTVibration', :path => "#{prefix}/Libraries/Vibration", :project_name => 'ABI49_0_0' 116 pod 'ABI49_0_0React-Core/RCTWebSocket', :path => "#{prefix}/", :project_name => 'ABI49_0_0' 117 pod 'ABI49_0_0React-rncore', :path => "#{prefix}/ReactCommon", :project_name => 'ABI49_0_0' 118 pod 'ABI49_0_0React-cxxreact', :path => "#{prefix}/ReactCommon/cxxreact", :project_name => 'ABI49_0_0' 119 pod 'ABI49_0_0React-debug', :path => "#{prefix}/ReactCommon/react/debug", :project_name => 'ABI49_0_0' 120 pod 'ABI49_0_0React-utils', :path => "#{prefix}/ReactCommon/react/utils", :project_name => 'ABI49_0_0' 121 122 if hermes_enabled 123 setup_hermes_ABI49_0_0!(:react_native_path => prefix, :fabric_enabled => fabric_enabled) 124 else 125 setup_jsc_ABI49_0_0!(:react_native_path => prefix, :fabric_enabled => fabric_enabled) 126 end 127 128 pod 'ABI49_0_0React-jsiexecutor', :path => "#{prefix}/ReactCommon/jsiexecutor", :project_name => 'ABI49_0_0' 129 pod 'ABI49_0_0React-jsinspector', :path => "#{prefix}/ReactCommon/jsinspector", :project_name => 'ABI49_0_0' 130 131 pod 'ABI49_0_0React-callinvoker', :path => "#{prefix}/ReactCommon/callinvoker", :project_name => 'ABI49_0_0' 132 pod 'ABI49_0_0React-runtimeexecutor', :path => "#{prefix}/ReactCommon/runtimeexecutor", :project_name => 'ABI49_0_0' 133 pod 'ABI49_0_0React-runtimescheduler', :path => "#{prefix}/ReactCommon/react/renderer/runtimescheduler", :project_name => 'ABI49_0_0' 134 pod 'ABI49_0_0React-perflogger', :path => "#{prefix}/ReactCommon/reactperflogger", :project_name => 'ABI49_0_0' 135 pod 'ABI49_0_0React-logger', :path => "#{prefix}/ReactCommon/logger", :project_name => 'ABI49_0_0' 136 pod 'ABI49_0_0ReactCommon/turbomodule/core', :path => "#{prefix}/ReactCommon", :project_name => 'ABI49_0_0', :modular_headers => true 137 pod 'ABI49_0_0React-NativeModulesApple', :path => "#{prefix}/ReactCommon/react/nativemodule/core/platform/ios", :project_name => 'ABI49_0_0', :modular_headers => true 138 pod 'ABI49_0_0Yoga', :path => "#{prefix}/ReactCommon/yoga", :project_name => 'ABI49_0_0', :modular_headers => true 139 140 # pod 'ABI49_0_0DoubleConversion', :podspec => "#{prefix}/third-party-podspecs/DoubleConversion.podspec" 141 # pod 'ABI49_0_0glog', :podspec => "#{prefix}/third-party-podspecs/glog.podspec" 142 # pod 'ABI49_0_0boost', :podspec => "#{prefix}/third-party-podspecs/boost.podspec" 143 # pod 'ABI49_0_0RCT-Folly', :podspec => "#{prefix}/third-party-podspecs/RCT-Folly.podspec", :modular_headers => true 144 145 run_codegen_ABI49_0_0!( 146 app_path, 147 config_file_dir, 148 :new_arch_enabled => new_arch_enabled, 149 :disable_codegen => ENV['DISABLE_CODEGEN'] == '1', 150 :react_native_path => prefix, 151 :fabric_enabled => fabric_enabled, 152 :hermes_enabled => hermes_enabled, 153 :codegen_output_dir => $ABI49_0_0CODEGEN_OUTPUT_DIR, 154 :package_json_file => File.join(__dir__, "..", "package.json"), 155 :folly_version => $FOLLY_VERSION 156 ) 157 158 pod 'ABI49_0_0React-Codegen', :path => $ABI49_0_0CODEGEN_OUTPUT_DIR, :modular_headers => true 159 160 if fabric_enabled 161 checkAndGenerateEmptyThirdPartyProvider!(prefix, new_arch_enabled) 162 setup_fabric!(:react_native_path => prefix, new_arch_enabled: new_arch_enabled) 163 else 164 relative_installation_root = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd) 165 166 end 167 168 # CocoaPods `configurations` option ensures that the target is copied only for the specified configurations, 169 # but those dependencies are still built. 170 # Flipper doesn't currently compile for release https://github.com/facebook/react-native/issues/33764 171 # Setting the production flag to true when build for production make sure that we don't install Flipper in the app in the first place. 172 if flipper_configuration.flipper_enabled && !production 173 install_flipper_dependencies(prefix) 174 use_flipper_pods(flipper_configuration.versions, :configurations => flipper_configuration.configurations) 175 end 176 177 pods_to_update = LocalPodspecPatch.pods_to_update(:react_native_path => prefix) 178 if !pods_to_update.empty? 179 if Pod::Lockfile.public_instance_methods.include?(:detect_changes_with_podfile) 180 Pod::Lockfile.prepend(LocalPodspecPatch) 181 else 182 Pod::UI.warn "Automatically updating #{pods_to_update.join(", ")} has failed, please run `pod update #{pods_to_update.join(" ")} --no-repo-update` manually to fix the issue." 183 end 184 end 185end 186 187# Getter to retrieve the folly flags in case contributors need to apply them manually. 188# 189# Returns: the folly compiler flags 190def folly_flags() 191 return NewArchitectureHelper.folly_compiler_flags 192end 193 194# This function can be used by library developer to prepare their modules for the New Architecture. 195# It passes the Folly Flags to the module, it configures the search path and installs some New Architecture specific dependencies. 196# 197# Parameters: 198# - spec: The spec that has to be configured with the New Architecture code 199# - new_arch_enabled: Whether the module should install dependencies for the new architecture 200def install_modules_dependencies(spec, new_arch_enabled: ENV['RCT_NEW_ARCH_ENABLED'] == "1") 201 NewArchitectureHelper.install_modules_dependencies(spec, new_arch_enabled, $FOLLY_VERSION) 202end 203 204# It returns the default flags. 205def get_default_flags() 206 return ReactNativePodsUtils.get_default_flags() 207end 208 209# It installs the flipper dependencies into the project. 210# 211# Parameters 212# - versions: a dictionary of Flipper Library -> Versions that can be used to customize which version of Flipper to install. 213# - configurations: an array of configuration where to install the dependencies. 214def use_flipper!(versions = {}, configurations: ['Debug']) 215 Pod::UI.warn "use_flipper is deprecated, use the flipper_configuration option in the use_react_native function" 216 use_flipper_pods(versions, :configurations => configurations) 217end 218 219# Function that executes after React Native has been installed to configure some flags and build settings. 220# 221# Parameters 222# - installer: the Cocoapod object that allows to customize the project. 223# - react_native_path: path to React Native. 224# - mac_catalyst_enabled: whether we are running the Pod on a Mac Catalyst project or not. 225# - enable_hermes_profiler: whether the hermes profiler should be turned on in Release mode 226def react_native_post_install( 227 installer, 228 react_native_path = "../node_modules/react-native", 229 mac_catalyst_enabled: false 230) 231 ReactNativePodsUtils.turn_off_resource_bundle_react_core(installer) 232 233 ReactNativePodsUtils.apply_mac_catalyst_patches(installer) if mac_catalyst_enabled 234 235 if ReactNativePodsUtils.has_pod(installer, 'Flipper') 236 flipper_post_install(installer) 237 end 238 239 fabric_enabled = ReactNativePodsUtils.has_pod(installer, 'React-Fabric') 240 241 ReactNativePodsUtils.exclude_i386_architecture_while_using_hermes(installer) 242 ReactNativePodsUtils.fix_library_search_paths(installer) 243 ReactNativePodsUtils.update_search_paths(installer) 244 ReactNativePodsUtils.set_node_modules_user_settings(installer, react_native_path) 245 ReactNativePodsUtils.apply_flags_for_fabric(installer, fabric_enabled: fabric_enabled) 246 ReactNativePodsUtils.apply_xcode_15_patch(installer) 247 248 NewArchitectureHelper.set_clang_cxx_language_standard_if_needed(installer) 249 is_new_arch_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == "1" 250 NewArchitectureHelper.modify_flags_for_new_architecture(installer, is_new_arch_enabled) 251 252 Pod::UI.puts "Pod install took #{Time.now.to_i - $START_TIME} [s] to run".green 253end 254 255# === LEGACY METHOD === 256# We need to keep this while we continue to support the old architecture. 257# ===================== 258def use_react_native_codegen_ABI49_0_0!(spec, options={}) 259 return if ENV['RCT_NEW_ARCH_ENABLED'] == "1" 260 # TODO: Once the new codegen approach is ready for use, we should output a warning here to let folks know to migrate. 261 262 # The prefix to react-native 263 react_native_path = options[:react_native_path] ||= ".." 264 265 # Library name (e.g. FBReactNativeSpec) 266 library_name = options[:library_name] ||= "#{spec.name.gsub('_','-').split('-').collect(&:capitalize).join}Spec" 267 Pod::UI.puts "[Codegen] Found #{library_name}" 268 269 relative_installation_root = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd) 270 output_dir = options[:output_dir] ||= $ABI49_0_0CODEGEN_OUTPUT_DIR 271 output_dir_module = "#{output_dir}/#{$CODEGEN_MODULE_DIR}" 272 output_dir_component = "#{output_dir}/#{$CODEGEN_COMPONENT_DIR}" 273 274 codegen_config = { 275 "modules" => { 276 :js_srcs_pattern => "Native*.js", 277 :generated_dir => "#{relative_installation_root}/#{output_dir_module}/#{library_name}", 278 :generated_files => [ 279 "#{library_name}.h", 280 "#{library_name}-generated.mm" 281 ] 282 }, 283 "components" => { 284 :js_srcs_pattern => "*NativeComponent.js", 285 :generated_dir => "#{relative_installation_root}/#{output_dir_component}/#{library_name}", 286 :generated_files => [ 287 "ComponentDescriptors.h", 288 "EventEmitters.cpp", 289 "EventEmitters.h", 290 "Props.cpp", 291 "Props.h", 292 "States.cpp", 293 "States.h", 294 "RCTComponentViewHelpers.h", 295 "ShadowNodes.cpp", 296 "ShadowNodes.h" 297 ] 298 } 299 } 300 301 # The path to JavaScript files 302 js_srcs_dir = options[:js_srcs_dir] ||= "./" 303 library_type = options[:library_type] 304 305 if library_type 306 if !codegen_config[library_type] 307 raise "[Codegen] invalid library_type: #{library_type}. Check your podspec to make sure it's set to 'modules' or 'components'. Removing the option will generate files for both" 308 end 309 js_srcs_pattern = codegen_config[library_type][:js_srcs_pattern] 310 end 311 312 if library_type 313 generated_dirs = [ codegen_config[library_type][:generated_dir] ] 314 generated_files = codegen_config[library_type][:generated_files].map { |filename| "#{codegen_config[library_type][:generated_dir]}/#{filename}" } 315 else 316 generated_dirs = [ codegen_config["modules"][:generated_dir], codegen_config["components"][:generated_dir] ] 317 generated_files = codegen_config["modules"][:generated_files].map { |filename| "#{codegen_config["modules"][:generated_dir]}/#{filename}" } 318 generated_files = generated_files.concat(codegen_config["components"][:generated_files].map { |filename| "#{codegen_config["components"][:generated_dir]}/#{filename}" }) 319 end 320 321 if js_srcs_pattern 322 file_list = `find #{js_srcs_dir} -type f -name #{js_srcs_pattern}`.split("\n").sort 323 input_files = file_list.map { |filename| "${PODS_TARGET_SRCROOT}/#{filename}" } 324 else 325 input_files = [ js_srcs_dir ] 326 end 327 328 # Prepare filesystem by creating empty files that will be picked up as references by CocoaPods. 329 prepare_command = "mkdir -p #{generated_dirs.join(" ")} && touch -a #{generated_files.join(" ")}" 330 system(prepare_command) # Always run prepare_command when a podspec uses the codegen, as CocoaPods may skip invoking this command in certain scenarios. Replace with pre_integrate_hook after updating to CocoaPods 1.11 331 spec.prepare_command = prepare_command 332 333 env_files = ["$PODS_ROOT/../.xcode.env.local", "$PODS_ROOT/../.xcode.env"] 334 335 spec.script_phase = { 336 :name => 'Generate Specs', 337 :input_files => input_files + env_files, # This also needs to be relative to Xcode 338 :output_files => ["${DERIVED_FILE_DIR}/codegen-#{library_name}.log"].concat(generated_files.map { |filename| "${PODS_TARGET_SRCROOT}/#{filename}"} ), 339 # The final generated files will be created when this script is invoked at Xcode build time. 340 :script => get_script_phases_no_codegen_discovery_ABI49_0_0( 341 react_native_path: react_native_path, 342 codegen_output_dir: output_dir, 343 codegen_module_dir: output_dir_module, 344 codegen_component_dir: output_dir_component, 345 library_name: library_name, 346 library_type: library_type, 347 js_srcs_pattern: js_srcs_pattern, 348 js_srcs_dir: js_srcs_dir, 349 file_list: file_list 350 ), 351 :execution_position => :before_compile, 352 :show_env_vars_in_log => true 353 } 354end 355 356# This provides a post_install workaround for build issues related Xcode 12.5 and Apple Silicon (M1) machines. 357# Call this in the app's main Podfile's post_install hook. 358# See https://github.com/facebook/react-native/issues/31480#issuecomment-902912841 for more context. 359# Actual fix was authored by https://github.com/mikehardy. 360# New app template will call this for now until the underlying issue is resolved. 361def __apply_Xcode_12_5_M1_post_install_workaround(installer) 362 # Flipper podspecs are still targeting an older iOS deployment target, and may cause an error like: 363 # "error: thread-local storage is not supported for the current target" 364 # The most reliable known workaround is to bump iOS deployment target to match react-native (iOS 11 now). 365 installer.pods_project.targets.each do |target| 366 target.build_configurations.each do |config| 367 # ensure IPHONEOS_DEPLOYMENT_TARGET is at least 11.0 368 deployment_target = config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'].to_f 369 should_upgrade = deployment_target < 11.0 && deployment_target != 0.0 370 if should_upgrade 371 config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' 372 end 373 end 374 end 375 376 # But... doing so caused another issue in Flipper: 377 # "Time.h:52:17: error: typedef redefinition with different types" 378 # We need to make a patch to RCT-Folly - remove the `__IPHONE_OS_VERSION_MIN_REQUIRED` check. 379 # See https://github.com/facebook/flipper/issues/834 for more details. 380 time_header = "#{Pod::Config.instance.installation_root.to_s}/Pods/RCT-Folly/folly/portability/Time.h" 381 `sed -i -e $'s/ && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0)//' '#{time_header}'` 382end 383