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