first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

View File

@@ -0,0 +1,212 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require 'json'
require 'pathname'
require 'cocoapods'
require_relative './autolinking_utils.rb'
require_relative '../react_native_pods.rb'
# Your project will have to depend on the @react-native-community/cli if you use this method
# for listing React native modules.
#
# Parameters:
# - config_command: the command to run to get the application's current config, e.g. ['npx', '@react-native-community/cli', 'config']
def list_native_modules!(config_command)
if !(config_command.is_a? Array and config_command.size > 0)
Pod::UI.warn "Expected a list_native_modules! to be called with a config command", [
"Unable to autolink if no config is provided for the current project."
]
exit(1)
end
# Ignore stderr output, we're only interested in stdout and the return code. Libraries can output warnings to
# stderr which create problems for JSON deserializing.
json, _, status = Pod::Executable.capture_command(config_command[0], config_command[1..], capture: :both)
if not status.success?
Pod::UI.warn "The command: '#{config_command.join(" ").bold.yellow}' returned a status code of #{status.exitstatus.to_s.bold.red}", [
"In order to autolink using Cocoapods, this framework uses @react-native-community/cli to discover React Native native modules",
"Please either add it: yarn add -D @react-native-community/cli or consult your framework's documentation."
]
exit(status.exitstatus)
end
config = JSON.parse(json)
packages = config["dependencies"]
ios_project_root = Pathname.new(config["project"]["ios"]["sourceDir"])
react_native_path = Pathname.new(config["reactNativePath"])
codegen_output_path = ios_project_root.join("build/generated/autolinking/autolinking.json")
# Write autolinking react-native-config output to codegen folder
FileUtils.mkdir_p(File.dirname(codegen_output_path))
File.write(codegen_output_path, json)
found_pods = []
packages.each do |package_name, package|
next unless package_config = package["platforms"]["ios"]
name = package["name"]
podspec_path = package_config["podspecPath"]
script_phases = package_config["scriptPhases"]
configurations = package_config["configurations"]
# Add a warning to the queue and continue to the next dependency if the podspec_path is nil/empty
if podspec_path.nil? || podspec_path.empty?
Pod::UI.warn("list_native_modules! skipped the react-native dependency '#{name}'. No podspec file was found.",
[
"Check to see if there is an updated version that contains the necessary podspec file",
"Contact the library maintainers or send them a PR to add a podspec. The react-native-webview podspec is a good example of a package.json driven podspec. See https://github.com/react-native-community/react-native-webview/blob/master/react-native-webview.podspec",
"If necessary, you can disable autolinking for the dependency and link it manually. See https://github.com/react-native-community/cli/blob/main/docs/autolinking.md#how-can-i-disable-autolinking-for-unsupported-library"
])
next
end
spec = Pod::Specification.from_file(podspec_path)
# Skip pods that do not support the platform of the current target.
next unless AutolinkingUtils.is_platform_supported?(current_target_definition, spec)
podspec_dir_path = Pathname.new(File.dirname(podspec_path))
relative_path = podspec_dir_path.relative_path_from ios_project_root
found_pods.push({
"configurations": configurations,
"name": name,
"root": package["root"],
"path": relative_path.to_path,
"podspec_path": podspec_path,
"script_phases": script_phases
})
end
if found_pods.size > 0
pods = found_pods.map { |p| p[:name] }.sort.to_sentence
Pod::UI.puts "Found #{found_pods.size} #{"module".pluralize(found_pods.size)} for target `#{current_target_definition.name}`"
end
return {
"ios_packages": found_pods,
"ios_project_root_path": ios_project_root.to_s,
"react_native_path": react_native_path.relative_path_from(ios_project_root).to_s
}
end
# Your project will have to depend on the @react-native-community/cli if you use this method
# for listing React native modules.
#
# Parameters:
# - config:
# - :ios_packages - Array of React Native iOS packages, e.g. [{ package_name: "Foo", package: { .. }}, ...]
# - :ios_project_root_path - Absolute path to the react_native project's ios folder, e.g. /Users/foobar/project/rn_project/ios
# - :react_native_path - Relative path to the react_native from the project, e.g. ./node_modules/react-native
def link_native_modules!(config)
Pod::UI.puts "link_native_modules! #{config}"
if !(
config[:ios_packages].is_a? Array and
config[:ios_project_root_path].is_a? String and
config[:react_native_path].is_a? String
)
Pod::UI.warn("link_native_modules! has been called with a malformed 'config' parameter",
[
"This is the config argument passed: #{config.inspect}",
]);
exit(1)
end
ios_project_root = config[:ios_project_root_path]
packages = config[:ios_packages]
found_pods = []
packages.each do |package|
podspec_path = package[:podspec_path]
configurations = package[:configurations]
# Add a warning to the queue and continue to the next dependency if the podspec_path is nil/empty
if podspec_path.nil? || podspec_path.empty?
Pod::UI.warn("use_native_modules! skipped the react-native dependency '#{package[:name]}'. No podspec file was found.",
[
"Check to see if there is an updated version that contains the necessary podspec file",
"Contact the library maintainers or send them a PR to add a podspec. The react-native-webview podspec is a good example of a package.json driven podspec. See https://github.com/react-native-community/react-native-webview/blob/master/react-native-webview.podspec",
"If necessary, you can disable autolinking for the dependency and link it manually. See https://github.com/react-native-community/cli/blob/main/docs/autolinking.md#how-can-i-disable-autolinking-for-unsupported-library"
])
next
end
spec = Pod::Specification.from_file(podspec_path)
# Don't try track packages that exclude our platforms
next unless AutolinkingUtils.is_platform_supported?(current_target_definition, spec)
# We want to do a look up inside the current CocoaPods target
# to see if it's already included, this:
# 1. Gives you the chance to define it beforehand
# 2. Ensures CocoaPods won't explode if it's included twice
#
this_target = current_target_definition
existing_deps = current_target_definition.dependencies
# Skip dependencies that the user already activated themselves.
next if existing_deps.find do |existing_dep|
existing_dep.name.split('/').first == spec.name
end
podspec_dir_path = Pathname.new(File.dirname(podspec_path))
relative_path = podspec_dir_path.relative_path_from ios_project_root
# Register the found React Native module into our collection of Pods.
pod spec.name, :path => relative_path.to_path, :configurations => configurations
if package[:script_phases] && !this_target.abstract?
# Can be either an object, or an array of objects
Array(package[:script_phases]).each do |phase|
# see https://www.rubydoc.info/gems/cocoapods-core/Pod/Podfile/DSL#script_phase-instance_method
# for the full object keys
Pod::UI.puts "Adding a custom script phase for Pod #{spec.name}: #{phase["name"] || 'No name specified.'}"
# Support passing in a path relative to the root of the package
if phase["path"]
phase["script"] = File.read(File.expand_path(phase["path"], package[:root]))
phase.delete("path")
end
# Support converting the execution position into a symbol
phase["execution_position"] = phase["execution_position"]&.to_sym
phase = Hash[phase.map { |k, v| [k.to_sym, v] }]
script_phase phase
end
end
found_pods.push spec
end
if found_pods.size > 0
pods = found_pods.map { |p| p.name }.sort.to_sentence
Pod::UI.puts "Auto-linking React Native #{"module".pluralize(found_pods.size)} for target `#{current_target_definition.name}`: #{pods}"
end
return {
:reactNativePath => config[:react_native_path]
}
end
$default_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"];
# Autolink your native modules
#
# Parameters:
# - config_command: the command to run to get the application's current config, e.g. ['npx', '@react-native-community/cli', 'config'],
# you can override this if you'd like to avoid the dependency. e.g. ['cat', 'your_config.json']
def use_native_modules!(config_command = $default_command)
return link_native_modules!(list_native_modules!(config_command))
end

View File

@@ -0,0 +1,25 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
class AutolinkingUtils
def self.nested_path_exists?(object, *path)
path.reduce(object) do |obj, method|
return false unless obj.respond_to?(method)
obj.public_send(method)
end
return true
end
def self.is_platform_supported?(current_target_definition, spec)
platform = current_target_definition.platform
if !platform
# Historically we've supported platforms that aren't specifically excluded.
return true
end
return spec.supported_on_platform?(platform.name)
end
end

48
node_modules/react-native/scripts/cocoapods/codegen.rb generated vendored Normal file
View File

@@ -0,0 +1,48 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require_relative './helpers.rb'
# keeping the run_codegen! method for testing purposes
def run_codegen!(
app_path,
config_file_dir,
new_arch_enabled: true,
disable_codegen: false,
react_native_path: "../node_modules/react-native",
fabric_enabled: false,
hermes_enabled: true,
codegen_output_dir: 'build/generated/ios',
config_key: 'codegenConfig',
package_json_file: '~/app/package.json',
folly_version: Helpers::Constants.folly_config()[:version],
codegen_utils: CodegenUtils.new()
)
if ENV["RCT_SKIP_CODEGEN"] == "1"
return
end
codegen_utils.use_react_native_codegen_discovery!(
disable_codegen,
app_path,
:react_native_path => react_native_path,
:fabric_enabled => fabric_enabled,
:hermes_enabled => hermes_enabled,
:config_file_dir => config_file_dir,
:codegen_output_dir => codegen_output_dir,
:config_key => config_key,
:folly_version => folly_version
)
end
def basePath(react_native_path, relative_installation_root)
expanded_path = File.expand_path(react_native_path)
if expanded_path == react_native_path
react_native_path
else
File.join(relative_installation_root.to_s, react_native_path)
end
end

View File

@@ -0,0 +1,13 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
class CodegenScriptPhaseExtractor
def initialize()
end
def extract_script_phase(options)
get_script_phases_with_codegen_discovery(options)
end
end

View File

@@ -0,0 +1,126 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require 'json'
require_relative './utils.rb'
require_relative './helpers.rb'
require_relative './codegen_script_phase_extractor.rb'
class CodegenUtils
def initialize()
end
@@REACT_CODEGEN_DISCOVERY_DONE = false
def self.set_react_codegen_discovery_done(value)
@@REACT_CODEGEN_DISCOVERY_DONE = value
end
def self.react_codegen_discovery_done
@@REACT_CODEGEN_DISCOVERY_DONE
end
def use_react_native_codegen_discovery!(
codegen_disabled,
app_path,
react_native_path: "../node_modules/react-native",
fabric_enabled: false,
hermes_enabled: true,
config_file_dir: '',
codegen_output_dir: 'build/generated/ios',
config_key: 'codegenConfig',
folly_version: Helpers::Constants.folly_config[:version],
codegen_utils: CodegenUtils.new(),
file_manager: File,
logger: CodegenUtils::UI
)
return if codegen_disabled
if CodegenUtils.react_codegen_discovery_done()
logger.puts("Skipping use_react_native_codegen_discovery.")
return
end
if !app_path
logger.warn("Error: app_path is required for use_react_native_codegen_discovery.")
logger.warn("If you are calling use_react_native_codegen_discovery! in your Podfile, please remove the call and pass `app_path` and/or `config_file_dir` to `use_react_native!`.")
abort
end
relative_installation_root = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd)
out = Pod::Executable.execute_command(
'node',
[
"#{relative_installation_root}/#{react_native_path}/scripts/generate-codegen-artifacts.js",
"-p", "#{app_path}",
"-o", Pod::Config.instance.installation_root,
"-t", "ios",
])
Pod::UI.puts out;
CodegenUtils.set_react_codegen_discovery_done(true)
end
@@CLEANUP_DONE = false
def self.set_cleanup_done(newValue)
@@CLEANUP_DONE = newValue
end
def self.cleanup_done
return @@CLEANUP_DONE
end
def self.clean_up_build_folder(rn_path, codegen_dir, dir_manager: Dir, file_manager: File)
if ENV["RCT_SKIP_CODEGEN"] == "1"
return
end
return if CodegenUtils.cleanup_done()
CodegenUtils.set_cleanup_done(true)
ios_folder = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd)
codegen_path = file_manager.join(ios_folder, codegen_dir)
return if !dir_manager.exist?(codegen_path)
FileUtils.rm_rf("#{codegen_path}")
base_provider_path = file_manager.join(rn_path, 'React', 'Fabric', 'RCTThirdPartyFabricComponentsProvider')
FileUtils.rm_rf("#{base_provider_path}.h")
FileUtils.rm_rf("#{base_provider_path}.mm")
CodegenUtils.assert_codegen_folder_is_empty(codegen_path, dir_manager: dir_manager)
end
# Need to split this function from the previous one to be able to test it properly.
def self.assert_codegen_folder_is_empty(codegen_path, dir_manager: Dir)
# double check that the files have actually been deleted.
# Emit an error message if not.
if dir_manager.exist?(codegen_path) && dir_manager.glob("#{codegen_path}/*").length() != 0
Pod::UI.warn "Unable to remove the content of #{codegen_path} folder. Please run rm -rf #{codegen_path} and try again."
abort
end
end
class UI
# ANSI escape codes for colors and formatting
CYAN = "\e[36m"
YELLOW = "\e[33m"
BOLD = "\e[1m"
RESET = "\e[0m"
class << self
def puts(text, info: false)
prefix = "#{CYAN}#{BOLD}[Codegen]#{RESET}"
message = info ? "#{YELLOW}#{text}#{RESET}" : text
Pod::UI.puts "#{prefix} #{message}"
end
def warn(text)
puts(text, info: true)
end
end
end
end

17
node_modules/react-native/scripts/cocoapods/fabric.rb generated vendored Normal file
View File

@@ -0,0 +1,17 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
# It sets up the Fabric dependencies.
#
# @parameter react_native_path: relative path to react-native
def setup_fabric!(react_native_path: "../node_modules/react-native")
pod 'React-Fabric', :path => "#{react_native_path}/ReactCommon"
pod 'React-FabricComponents', :path => "#{react_native_path}/ReactCommon"
pod 'React-graphics', :path => "#{react_native_path}/ReactCommon/react/renderer/graphics"
pod 'React-RCTFabric', :path => "#{react_native_path}/React", :modular_headers => true
pod 'React-ImageManager', :path => "#{react_native_path}/ReactCommon/react/renderer/imagemanager/platform/ios"
pod 'React-FabricImage', :path => "#{react_native_path}/ReactCommon"
end

151
node_modules/react-native/scripts/cocoapods/helpers.rb generated vendored Normal file
View File

@@ -0,0 +1,151 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
# Helper object to wrap the invocation of sysctl
# This makes it easier to mock the behaviour in tests
class SysctlChecker
def call_sysctl_arm64
return `/usr/sbin/sysctl -n hw.optional.arm64 2>&1`.to_i
end
end
# Helper class that is used to easily send commands to Xcodebuild
# And that can be subclassed for testing purposes.
class Xcodebuild
def self.version
`xcodebuild -version`
end
end
# Helper object to wrap system properties like RUBY_PLATFORM
# This makes it easier to mock the behaviour in tests
class Environment
def ruby_platform
return RUBY_PLATFORM
end
end
class Finder
def self.find_codegen_file(path)
js_files = '-name "Native*.js" -or -name "*NativeComponent.js"'
ts_files = '-name "Native*.ts" -or -name "*NativeComponent.ts"'
return `find #{path} -type f \\( #{js_files} -or #{ts_files} \\)`.split("\n").sort()
end
end
module Helpers
class Constants
@@boost_config = {
:git => "https://github.com/react-native-community/boost-for-react-native",
:compiler_flags => '-Wno-documentation'
}
@@socket_rocket_config = {
:version => '0.7.1'
}
@@folly_config = {
:version => '2024.11.18.00',
:git => 'https://github.com/facebook/folly.git',
:compiler_flags => '-DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_CFG_NO_COROUTINES=1 -DFOLLY_HAVE_CLOCK_GETTIME=1 -Wno-comma -Wno-shorten-64-to-32',
:config_file => [
"#pragma once",
"",
"#define FOLLY_MOBILE 1",
"#define FOLLY_USE_LIBCPP 1",
"#define FOLLY_HAVE_PTHREAD 1",
"#define FOLLY_CFG_NO_COROUTINES 1",
"#define FOLLY_HAVE_CLOCK_GETTIME 1",
"",
'#pragma clang diagnostic ignored "-Wcomma"',
],
:dep_name => 'RCT-Folly/Fabric'
}
@@fast_float_config = {
:git => "https://github.com/fastfloat/fast_float.git",
}
@@fmt_config = {
:git => "https://github.com/fmtlib/fmt.git",
}
@@glog_config = {
:git => "https://github.com/google/glog.git",
}
@@double_conversion_config = {
:git => "https://github.com/google/double-conversion.git",
}
def self.min_ios_version_supported
return '15.1'
end
def self.min_xcode_version_supported
return '16.1'
end
def self.folly_config
return @@folly_config
end
def self.set_folly_config(new_folly_config)
@@folly_config.update(new_folly_config)
end
def self.boost_config
return @@boost_config
end
def self.set_boost_config(new_boost_config)
@@boost_config.update(new_boost_config)
end
def self.socket_rocket_config
return @@socket_rocket_config
end
def self.set_socket_rocket_config(new_socket_rocket_config)
@@socket_rocket_config.update(new_socket_rocket_config)
end
def self.fast_float_config
return @@fast_float_config
end
def self.set_fast_float_config(new_fast_float_config)
@@fast_float_config.update(new_fast_float_config)
end
def self.fmt_config
return @@fmt_config
end
def self.set_fmt_config(new_fmt_config)
@@fmt_config.update(new_fmt_config)
end
def self.glog_config
return @@glog_config
end
def self.set_glog_config(new_glog_config)
@@glog_config.update(new_glog_config)
end
def self.double_conversion_config
return @@double_conversion_config
end
def self.set_double_conversion_config(new_double_conversion_config)
@@double_conversion_config.update(new_double_conversion_config)
end
def self.cxx_language_standard
return "c++20"
end
end
end

View File

@@ -0,0 +1,56 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require_relative './utils.rb'
# It sets up the Hermes.
#
# @parameter react_native_path: relative path to react-native
# @parameter fabric_enabled: whether Fabirc is enabled
def setup_hermes!(react_native_path: "../node_modules/react-native")
react_native_dir = Pod::Config.instance.installation_root.join(react_native_path)
# This `:tag => hermestag` below is only to tell CocoaPods to update hermes-engine when React Native version changes.
# We have custom logic to compute the source for hermes-engine. See sdks/hermes-engine/*
hermestag_file_name = ENV['RCT_HERMES_V1_ENABLED'] == "1" ? ".hermesv1version" : ".hermesversion"
hermestag_file = File.join(react_native_dir, "sdks", hermestag_file_name)
hermestag = File.exist?(hermestag_file) ? File.read(hermestag_file).strip : ''
pod 'hermes-engine', :podspec => "#{react_native_path}/sdks/hermes-engine/hermes-engine.podspec", :tag => hermestag
pod 'React-hermes', :path => "#{react_native_path}/ReactCommon/hermes"
end
def use_third_party_jsc
return ENV['USE_THIRD_PARTY_JSC'] == '1'
end
# use Hermes is the default. The only other option is the third-party JSC
# if the 3rd party JSC is not true, we always want to use Hermes.
def use_hermes
return !use_third_party_jsc()
end
def use_hermes_flags
return "-DUSE_HERMES=1"
end
def use_third_party_jsc_flags
return "-DUSE_THIRD_PARTY_JSC=1"
end
def js_engine_flags()
if use_hermes()
return use_hermes_flags()
else
return use_third_party_jsc_flags()
end
end
# Utility function to depend on JS engine based on the environment variable.
def depend_on_js_engine(s)
if use_hermes()
s.dependency 'hermes-engine'
elsif use_third_party_jsc()
s.dependency 'React-jsc'
end
end

View File

@@ -0,0 +1,51 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
# Monkeypatch of `Pod::Lockfile` to ensure automatic update of dependencies integrated with a local podspec when their version changed.
# This is necessary because local podspec dependencies must be otherwise manually updated.
module LocalPodspecPatch
# Returns local podspecs whose versions differ from the one in the `react-native` package.
def self.pods_to_update(react_native_path: "../node_modules/react-native", dir_manager: Dir, file_manager: File)
@@local_podspecs = dir_manager.glob("#{react_native_path}/third-party-podspecs/*").map { |file| file_manager.basename(file, ".podspec") }
@@local_podspecs = @@local_podspecs.select do |podspec_name|
# Read local podspec to determine the cached version
local_podspec_path = file_manager.join(
dir_manager.pwd, "Pods/Local Podspecs/#{podspec_name}.podspec.json"
)
# Local podspec cannot be outdated if it does not exist, yet
next unless file_manager.exist?(local_podspec_path)
local_podspec = file_manager.read(local_podspec_path)
local_podspec_json = JSON.parse(local_podspec)
local_version = local_podspec_json["version"]
# Read the version from a podspec from the `react-native` package
podspec_path = "#{react_native_path}/third-party-podspecs/#{podspec_name}.podspec"
current_podspec = Pod::Specification.from_file(podspec_path)
current_version = current_podspec.version.to_s
current_version != local_version
end
@@local_podspecs
end
# Patched `detect_changes_with_podfile` method
def detect_changes_with_podfile(podfile)
Pod::UI.puts "Invoke detect_changes_with_podfile patched method".red
changes = super(podfile)
return patch_detect_changes_with_podfile(changes)
end
def patch_detect_changes_with_podfile(changes)
@@local_podspecs.each do |local_podspec|
next unless changes[:unchanged].include?(local_podspec)
changes[:unchanged].delete(local_podspec)
changes[:changed] << local_podspec
end
changes
end
end

View File

@@ -0,0 +1,199 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require 'json'
require_relative "./utils.rb"
require_relative "./helpers.rb"
require_relative "./jsengine.rb"
class NewArchitectureHelper
@@NewArchWarningEmitted = false # Used not to spam warnings to the user.
def self.set_clang_cxx_language_standard_if_needed(installer)
cxxBuildsettingsName = "CLANG_CXX_LANGUAGE_STANDARD"
projects = installer.aggregate_targets
.map{ |t| t.user_project }
.uniq{ |p| p.path }
projects.each do |project|
Pod::UI.puts("Setting #{cxxBuildsettingsName} to #{ Helpers::Constants::cxx_language_standard } on #{ project.path }")
project.build_configurations.each do |config|
config.build_settings[cxxBuildsettingsName] = Helpers::Constants::cxx_language_standard
end
project.save()
end
installer.target_installation_results.pod_target_installation_results.each do |pod_name, target_installation_result|
target_installation_result.native_target.build_configurations.each do |config|
config.build_settings[cxxBuildsettingsName] = Helpers::Constants::cxx_language_standard
end
end
# Override targets that would set spec.xcconfig to define c++ version
installer.aggregate_targets.each do |aggregate_target|
aggregate_target.xcconfigs.each do |config_name, config_file|
config_file.attributes[cxxBuildsettingsName] = Helpers::Constants::cxx_language_standard
end
end
end
def self.computeFlags(is_new_arch_enabled)
new_arch_flag = is_new_arch_enabled ? "-DRCT_NEW_ARCH_ENABLED=1 " : ""
return " #{new_arch_flag}"
end
def self.modify_flags_for_new_architecture(installer, is_new_arch_enabled)
# Add flags to Target pods xcconfig
installer.aggregate_targets.each do |aggregate_target|
aggregate_target.xcconfigs.each do |config_name, config_file|
ReactNativePodsUtils.add_flag_to_map_with_inheritance(config_file.attributes, "OTHER_CPLUSPLUSFLAGS", self.computeFlags(is_new_arch_enabled))
xcconfig_path = aggregate_target.xcconfig_path(config_name)
config_file.save_as(xcconfig_path)
end
end
# Add flags to Target pods xcconfig
installer.target_installation_results.pod_target_installation_results.each do |pod_name, target_installation_result|
# The React-Core pod may have a suffix added by Cocoapods, so we test whether 'React-Core' is a substring, and do not require exact match
if pod_name.include? 'React-Core'
target_installation_result.native_target.build_configurations.each do |config|
ReactNativePodsUtils.add_flag_to_map_with_inheritance(config.build_settings, "OTHER_CPLUSPLUSFLAGS", self.computeFlags(is_new_arch_enabled))
end
end
end
end
def self.install_modules_dependencies(spec, new_arch_enabled, folly_version = Helpers::Constants.folly_config[:version])
# Pod::Specification does not have getters so, we have to read
# the existing values from a hash representation of the object.
hash = spec.to_hash
compiler_flags = hash["compiler_flags"] ? hash["compiler_flags"] : ""
current_config = hash["pod_target_xcconfig"] != nil ? hash["pod_target_xcconfig"] : {}
current_headers = current_config["HEADER_SEARCH_PATHS"] != nil ? current_config["HEADER_SEARCH_PATHS"] : ""
header_search_paths = ["\"$(PODS_ROOT)/Headers/Private/Yoga\""]
if ENV['USE_FRAMEWORKS']
ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-graphics", "React_graphics", ["react/renderer/graphics/platform/ios"])
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-Fabric", "React_Fabric", ["react/renderer/components/view/platform/cxx"]))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-FabricImage", "React_FabricImage", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "ReactCommon", "ReactCommon", ["react/nativemodule/core"]))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-runtimeexecutor", "React_runtimeexecutor", ["platform/ios"]))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-NativeModulesApple", "React_NativeModulesApple", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-RCTFabric", "RCTFabric", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-utils", "React_utils", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-featureflags", "React_featureflags", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-debug", "React_debug", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-ImageManager", "React_ImageManager", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-rendererdebug", "React_rendererdebug", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-renderercss", "React_renderercss", []))
.each { |search_path|
header_search_paths << "\"#{search_path}\""
}
end
header_search_paths_string = header_search_paths.join(" ")
spec.compiler_flags = compiler_flags.empty? ? self.computeFlags(new_arch_enabled).strip! : "#{compiler_flags} #{self.computeFlags(new_arch_enabled)}"
current_config["HEADER_SEARCH_PATHS"] = current_headers.empty? ?
header_search_paths_string :
"#{current_headers} #{header_search_paths_string}"
current_config["CLANG_CXX_LANGUAGE_STANDARD"] = Helpers::Constants::cxx_language_standard
spec.dependency "React-Core"
ReactNativePodsUtils.add_flag_to_map_with_inheritance(current_config, "OTHER_CPLUSPLUSFLAGS", self.computeFlags(new_arch_enabled))
ReactNativePodsUtils.add_flag_to_map_with_inheritance(current_config, "OTHER_SWIFT_FLAGS", new_arch_enabled ? " -DRCT_NEW_ARCH_ENABLED" : "")
spec.dependency "React-RCTFabric" # This is for Fabric Component
spec.dependency "ReactCodegen"
spec.dependency "RCTRequired"
spec.dependency "RCTTypeSafety"
spec.dependency "ReactCommon/turbomodule/bridging"
spec.dependency "ReactCommon/turbomodule/core"
spec.dependency "React-NativeModulesApple"
spec.dependency "Yoga"
spec.dependency "React-Fabric"
spec.dependency "React-graphics"
spec.dependency "React-utils"
spec.dependency "React-featureflags"
spec.dependency "React-debug"
spec.dependency "React-ImageManager"
spec.dependency "React-rendererdebug"
spec.dependency 'React-jsi'
spec.dependency 'React-renderercss'
depend_on_js_engine(spec)
add_rn_third_party_dependencies(spec)
add_rncore_dependency(spec)
spec.pod_target_xcconfig = current_config
end
def self.extract_react_native_version(react_native_path, file_manager: File, json_parser: JSON)
package_json_file = File.join(react_native_path, "package.json")
if !file_manager.exist?(package_json_file)
raise "Couldn't find the React Native package.json file at #{package_json_file}"
end
package = json_parser.parse(file_manager.read(package_json_file))
return package["version"]
end
# Deprecated method. This has been restored because some libraries (e.g. react-native-exit-app) still use it.
def self.folly_compiler_flags
folly_config = Helpers::Constants.folly_config
return folly_config[:compiler_flags]
end
def self.new_arch_enabled
return 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", "build/", "DerivedData/", ".xcframework", ".framework", "watchkitapp", "today-extention"]
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
begin
info_plist = Xcodeproj::Plist.read_from_path(infoPlistFile)
rescue StandardError => e
Pod::UI.warn("Failed to read Info.plist at #{infoPlistFile}: #{e.message}")
next
end
# 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

View File

@@ -0,0 +1,194 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
module PrivacyManifestUtils
def self.add_aggregated_privacy_manifest(installer)
user_project = get_user_project_from(installer)
targets = get_application_targets(user_project)
file_path = get_privacyinfo_file_path(user_project, targets)
privacy_info = read_privacyinfo_file(file_path) || {
"NSPrivacyCollectedDataTypes" => [],
"NSPrivacyTracking" => false
}
# Get all required reason APIs defined in current pods
required_reason_apis = get_used_required_reason_apis(installer)
# Add the Required Reason APIs from React Native core
get_core_accessed_apis.each do |accessed_api|
api_type = accessed_api["NSPrivacyAccessedAPIType"]
reasons = accessed_api["NSPrivacyAccessedAPITypeReasons"]
required_reason_apis[api_type] ||= []
required_reason_apis[api_type] += reasons
end
# Merge the Required Reason APIs from pods with the ones from the existing PrivacyInfo file
(privacy_info["NSPrivacyAccessedAPITypes"] || []).each do |accessed_api|
api_type = accessed_api["NSPrivacyAccessedAPIType"]
reasons = accessed_api["NSPrivacyAccessedAPITypeReasons"]
# Add reasons from existing PrivacyInfo file to the ones from pods
required_reason_apis[api_type] ||= []
required_reason_apis[api_type] += reasons
end
# Update the existing PrivacyInfo file with the new aggregated data
privacy_info["NSPrivacyAccessedAPITypes"] = required_reason_apis.map { |api_type, reasons|
{
"NSPrivacyAccessedAPIType" => api_type,
"NSPrivacyAccessedAPITypeReasons" => reasons.uniq
}
}
Xcodeproj::Plist.write_to_path(privacy_info, file_path)
targets.each do |target|
ensure_reference(file_path, user_project, target)
end
end
def self.get_application_targets(user_project)
return user_project.targets.filter { |t| t.respond_to?(:symbol_type) && t.symbol_type == :application }
end
def self.read_privacyinfo_file(file_path)
# Maybe add missing default NSPrivacyTracking, NSPrivacyTrackingDomains, NSPrivacyCollectedDataTypes, but this works without those keys
source_data = nil
# Try to read an existing PrivacyInfo.xcprivacy file
begin
source_data = Xcodeproj::Plist.read_from_path(file_path)
Pod::UI.puts "[Privacy Manifest Aggregation] Appending aggregated reasons to existing PrivacyInfo.xcprivacy file."
rescue => e
Pod::UI.puts "[Privacy Manifest Aggregation] No existing PrivacyInfo.xcprivacy file found, creating a new one."
end
return source_data
end
def self.ensure_reference(file_path, user_project, target)
privacy_info_filename = File.basename(file_path)
# Check if the file is already in the PBXBuildFile section
build_phase_reference_exists = target.resources_build_phase.files_references.any? { |file_ref| file_ref&.path&.end_with?(privacy_info_filename) }
unless build_phase_reference_exists
# Check if the file is already in the PBXFileReference section
existing_file_reference = user_project.files.find { |file| file.path&.end_with?(privacy_info_filename) }
if existing_file_reference
# If the file reference exists, add it to the build phase
target.resources_build_phase.add_file_reference(existing_file_reference, true)
else
# If the file reference doesn't exist, add it to the project and the build phase
# We try to find the main group, but if it doesn't exist, we default to adding the file to the project root - both work
file_root = user_project.root_object.main_group.children.find { |group|
group.class == Xcodeproj::Project::Object::PBXGroup && (group.name == target.name || group.path == target.name)
} || user_project
puts "file_root: #{file_root}"
file_ref = file_root.new_file(file_path)
target.resources_build_phase.add_file_reference(file_ref, true)
end
end
end
def self.get_privacyinfo_file_path(user_project, targets)
file_refs = targets.flat_map { |target| target.resources_build_phase.files_references }
existing_file = file_refs.find { |file_ref| file_ref&.path&.end_with?("PrivacyInfo.xcprivacy") }
if existing_file
return existing_file.real_path
end
# We try to find a file we know exists in the project to get the path to the main group directory
info_plist_path = user_project.files.find { |file_ref| file_ref.name == "Info.plist" }
if info_plist_path.nil?
# return path that is sibling to .xcodeproj
path = user_project.path
return File.join(File.dirname(path), "PrivacyInfo.xcprivacy")
end
return File.join(File.dirname(info_plist_path.real_path),"PrivacyInfo.xcprivacy")
end
def self.get_used_required_reason_apis(installer)
# A dictionary with keys of type string (NSPrivacyAccessedAPIType) and values of type string[] (NSPrivacyAccessedAPITypeReasons[])
used_apis = {}
Pod::UI.puts "[Privacy Manifest Aggregation] Reading .xcprivacy files to aggregate all used Required Reason APIs."
installer.pod_targets.each do |pod_target|
# puts pod_target
pod_target.file_accessors.each do |file_accessor|
file_accessor.resource_bundles.each do |bundle_name, bundle_files|
bundle_files.each do |file_path|
# This needs to be named like that due to apple requirements
if File.basename(file_path) == 'PrivacyInfo.xcprivacy'
content = Xcodeproj::Plist.read_from_path(file_path)
accessed_api_types = content["NSPrivacyAccessedAPITypes"]
accessed_api_types&.each do |accessed_api|
api_type = accessed_api["NSPrivacyAccessedAPIType"]
reasons = accessed_api["NSPrivacyAccessedAPITypeReasons"]
next unless api_type
used_apis[api_type] ||= []
used_apis[api_type] += reasons
end
end
end
end
end
end
return used_apis
end
def self.get_privacy_manifest_paths_from(user_project)
privacy_manifests = user_project
.files
.select { |p|
p&.path&.end_with?('PrivacyInfo.xcprivacy')
}
return privacy_manifests
end
def self.get_core_accessed_apis()
file_timestamp_accessed_api = {
"NSPrivacyAccessedAPIType" => "NSPrivacyAccessedAPICategoryFileTimestamp",
"NSPrivacyAccessedAPITypeReasons" => ["C617.1"],
}
user_defaults_accessed_api = {
"NSPrivacyAccessedAPIType" => "NSPrivacyAccessedAPICategoryUserDefaults",
"NSPrivacyAccessedAPITypeReasons" => ["CA92.1"],
}
boot_time_accessed_api = {
"NSPrivacyAccessedAPIType" => "NSPrivacyAccessedAPICategorySystemBootTime",
"NSPrivacyAccessedAPITypeReasons" => ["35F9.1"],
}
return [file_timestamp_accessed_api, user_defaults_accessed_api, boot_time_accessed_api]
end
def self.get_user_project_from(installer)
user_project = installer.aggregate_targets
.map{ |t| t.user_project }
.first
return user_project
end
def self.add_privacy_manifest_if_needed(installer)
user_project = get_user_project_from(installer)
privacy_manifest = self.get_privacy_manifest_paths_from(user_project).first
if privacy_manifest.nil?
privacy_manifest = {
"NSPrivacyCollectedDataTypes" => [],
"NSPrivacyTracking" => false,
"NSPrivacyAccessedAPITypes" => get_core_accessed_apis
}
path = File.join(user_project&.path.parent, "PrivacyInfo.xcprivacy")
Xcodeproj::Plist.write_to_path(privacy_manifest, path)
Pod::UI.puts "Your app does not have a privacy manifest! A template has been generated containing Required Reasons API usage in the core React Native library. Please add the PrivacyInfo.xcprivacy file to your project and complete data use, tracking and any additional required reasons your app is using according to Apple's guidance: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files. Then, you will need to manually add this file to your project in Xcode.".red
end
end
end

453
node_modules/react-native/scripts/cocoapods/rncore.rb generated vendored Normal file
View File

@@ -0,0 +1,453 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require 'json'
require 'net/http'
require 'rexml/document'
require_relative './utils.rb'
### Adds ReactNativeCore-prebuilt as a dependency to the given podspec if we're not
### building ReactNativeCore from source (then this function does nothing).
def add_rncore_dependency(s)
if !ReactNativeCoreUtils.build_rncore_from_source()
current_pod_target_xcconfig = s.to_hash["pod_target_xcconfig"] || {}
current_pod_target_xcconfig = current_pod_target_xcconfig.to_h unless current_pod_target_xcconfig.is_a?(Hash)
s.dependency "React-Core-prebuilt"
current_pod_target_xcconfig["HEADER_SEARCH_PATHS"] ||= [] << "$(PODS_ROOT)/React-Core-prebuilt/React.xcframework/Headers"
s.pod_target_xcconfig = current_pod_target_xcconfig
end
end
## - RCT_USE_PREBUILT_RNCORE: If set to 1, it will use the release tarball from Maven instead of building from source.
## - RCT_TESTONLY_RNCORE_TARBALL_PATH: **TEST ONLY** If set, it will use a local tarball of RNCore if it exists.
## - RCT_TESTONLY_RNCORE_VERSION: **TEST ONLY** If set, it will override the version of RNCore to be used.
## - RCT_SYMBOLICATE_PREBUILT_FRAMEWORKS: If set to 1, it will download the dSYMs for the prebuilt RNCore frameworks and install these in the framework folders
class ReactNativeCoreUtils
@@build_from_source = true
@@react_native_path = ""
@@react_native_version = ""
@@use_nightly = false
@@download_dsyms = false
## Sets up wether ReactNative Core should be built from source or not.
## If RCT_USE_PREBUILT_RNCORE is set to 1 and the artifacts exists on Maven, it will
## not build from source. Otherwise, it will build from source.
def self.setup_rncore(react_native_path, react_native_version)
# We don't want setup to be called multiple times, so we check if the variables are already set.
if @@react_native_version == ""
rncore_log("Setting up ReactNativeCore...")
@@react_native_path = react_native_path
@@react_native_version = ENV["RCT_TESTONLY_RNCORE_VERSION"] == nil ? react_native_version : ENV["RCT_TESTONLY_RNCORE_VERSION"]
@@download_dsyms = ENV["RCT_SYMBOLICATE_PREBUILT_FRAMEWORKS"] == "1"
if @@react_native_version.include? "nightly"
@@use_nightly = true
if ENV["RCT_TESTONLY_RNCORE_VERSION"] == "nightly"
@@react_native_version = ReactNativeDependenciesUtils.get_nightly_npm_version()
rncore_log("Using nightly version from npm: #{@@react_native_version}")
else
rncore_log("Using nightly build #{@@react_native_version}")
end
end
if ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"]
abort_if_use_local_rncore_with_no_file()
end
use_local_xcframework = ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"] && File.exist?(ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"])
artifacts_exists = ENV["RCT_USE_PREBUILT_RNCORE"] == "1" && (@@use_nightly ? nightly_artifact_exists(@@react_native_version) : release_artifact_exists(@@react_native_version))
@@build_from_source = !use_local_xcframework && !artifacts_exists
if @@build_from_source && ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"] && !use_local_xcframework
rncore_log("No local xcframework found, reverting to building from source.")
end
if @@build_from_source && ENV["RCT_USE_PREBUILT_RNCORE"] && !artifacts_exists
rncore_log("No prebuilt artifacts found, reverting to building from source.")
end
rncore_log("Building from source: #{@@build_from_source}")
end
end
def self.abort_if_use_local_rncore_with_no_file()
if !File.exist?(ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"])
abort("RCT_TESTONLY_RNCORE_TARBALL_PATH is set to #{ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"]} but the file does not exist!")
end
end
def self.build_rncore_from_source()
return @@build_from_source
end
def self.resolve_podspec_source()
if ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"]
abort_if_use_local_rncore_with_no_file()
rncore_log("Using local xcframework at #{ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"]}")
return {:http => "file://#{ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"]}" }
end
if ENV["RCT_USE_PREBUILT_RNCORE"] == "1"
if @@use_nightly
begin
return self.podspec_source_download_prebuilt_nightly_tarball()
rescue => e
rncore_log("Failed to download nightly tarball: #{e.message}", :error)
return
end
end
begin
return self.podspec_source_download_prebuild_stable_tarball()
rescue => e
rncore_log("Failed to download release tarball: #{e.message}", :error)
return
end
end
end
def self.podspec_source_download_prebuild_stable_tarball()
if @@react_native_path == ""
rncore_log("react_native_path is not set", :error)
return
end
if @@react_native_version == ""
rncore_log("react_native_version is not set", :error)
return
end
if @@build_from_source
return
end
destinationDebug = download_stable_rncore(@@react_native_path, @@react_native_version, :debug)
destinationRelease = download_stable_rncore(@@react_native_path, @@react_native_version, :release)
if @@download_dsyms
dSymsDebug = download_stable_rncore(@@react_native_path, @@react_native_version, :debug, true)
dSymsRelease = download_stable_rncore(@@react_native_path, @@react_native_version, :release, true)
rncore_log("Resolved stable dSYMs")
rncore_log(" #{Pathname.new(dSymsDebug).relative_path_from(Pathname.pwd).to_s}")
rncore_log(" #{Pathname.new(dSymsRelease).relative_path_from(Pathname.pwd).to_s}")
# Make sure that the dSYMs are processed
process_dsyms(destinationDebug, dSymsDebug)
process_dsyms(destinationRelease, dSymsRelease)
end
rncore_log("Resolved stable ReactNativeCore-prebuilt version:")
rncore_log(" #{Pathname.new(destinationDebug).relative_path_from(Pathname.pwd).to_s}")
rncore_log(" #{Pathname.new(destinationRelease).relative_path_from(Pathname.pwd).to_s}")
return {:http => URI::File.build(path: destinationDebug).to_s }
end
def self.podspec_source_download_prebuilt_nightly_tarball()
if @@react_native_path == ""
rncore_log("react_native_path is not set", :error)
return
end
if @@react_native_version == ""
rncore_log("react_native_version is not set", :error)
return
end
if @@build_from_source
return
end
destinationDebug = download_nightly_rncore(@@react_native_path, @@react_native_version, :debug)
destinationRelease = download_nightly_rncore(@@react_native_path, @@react_native_version, :release)
if @@download_dsyms
dSymsDebug = download_nightly_rncore(@@react_native_path, @@react_native_version, :debug, true)
dSymsRelease = download_nightly_rncore(@@react_native_path, @@react_native_version, :release, true)
rncore_log("Resolved nightly dSYMs")
rncore_log(" #{Pathname.new(dSymsDebug).relative_path_from(Pathname.pwd).to_s}")
rncore_log(" #{Pathname.new(dSymsRelease).relative_path_from(Pathname.pwd).to_s}")
# Make sure that the dSYMs are processed
process_dsyms(destinationDebug, dSymsDebug)
process_dsyms(destinationRelease, dSymsRelease)
end
rncore_log("Resolved nightly ReactNativeCore-prebuilt version:")
rncore_log(" #{Pathname.new(destinationDebug).relative_path_from(Pathname.pwd).to_s}")
rncore_log(" #{Pathname.new(destinationRelease).relative_path_from(Pathname.pwd).to_s}")
return {:http => URI::File.build(path: destinationDebug).to_s }
end
def self.process_dsyms(frameworkTarball, dSymsTarball)
if !@@download_dsyms
return
end
if @@react_native_path == ""
rncore_log("react_native_path is not set", :error)
return
end
if @@react_native_version == ""
rncore_log("react_native_version is not set", :error)
return
end
if @@build_from_source
return
end
# gunzip the dSymsTarball and the frameworkTarball into a temporary folder
# and then copy the dSYMs into the framework folder and then tar/gz the framework folder again
# into the same location as the original frameworkTarball
rncore_log("Adding symbols #{Pathname.new(dSymsTarball).relative_path_from(Pathname.pwd).to_s} to framework tarball #{Pathname.new(frameworkTarball).relative_path_from(Pathname.pwd).to_s}")
FileUtils.mkdir_p(File.dirname(frameworkTarball))
FileUtils.cp(frameworkTarball, "#{frameworkTarball}.orig")
rncore_log(" Backed up original tarballs")
begin
# Now let's gunzip the framework tarball into a .tar file
# Get filename and foldername from the tarball path
frameworkFolder = File.dirname(frameworkTarball)
frameworkFilename = File.basename(frameworkTarball, ".tar.gz")
frameworkTarPath = File.join(frameworkFolder, frameworkFilename + ".tar")
# Now gunzip the tarball into the frameworkFolder - this will remove the .gz file and leave us with a .tar file
rncore_log(" Unpacking framework tarball")
`gunzip "#{frameworkTarball}"`
# Now let's untar the dSyms tarball into a temporary folder / dSYMs subfolder
dsyms_tmp_dir = "#{artifacts_dir}/dSYMs"
rncore_log(" Unpacking dSYMs to temporary folder")
`mkdir -p "#{dsyms_tmp_dir}" && tar -xzf "#{dSymsTarball}" -C "#{dsyms_tmp_dir}"`
# Now we need to remap the symbol files to be relative to the framework folder
remap_sourcemaps_for_symbols(dsyms_tmp_dir)
# Add the dSYMs folder to the framework folder
rncore_log(" Adding dSYMs to framework tarball")
# Move symbol bundles into each of the slices in the xcframework
# Example:
# move dSYMs/ios-arm64/. into React.xcframework/ios-arm64/React.framework/dSYMs/.
Dir.glob(File.join(dsyms_tmp_dir, "*")).each do |dsym_path|
slice_name = File.basename(dsym_path)
slice_dsym_dest = File.join("React.xcframework", slice_name, "React.framework", "dSYMs")
rncore_log(" Adding dSYM slice #{slice_name} into tarball at #{slice_dsym_dest}")
`(cd "#{File.dirname(frameworkTarPath)}" && mkdir -p "#{slice_dsym_dest}" && cp -R "#{dsym_path}/." "#{slice_dsym_dest}" && tar -rf "#{frameworkTarPath}" "#{slice_dsym_dest}")`
end
# Now gzip the framework tarball again - remember to use the .tar file and not the .gz file
rncore_log(" Packing #{Pathname.new(frameworkTarPath).relative_path_from(Pathname.pwd).to_s}")
`gzip -1 "#{frameworkTarPath}"`
# Clean up the temporary folder
FileUtils.remove_entry(dsyms_tmp_dir)
rncore_log(" Processed dSYMs into framework tarball #{Pathname.new(frameworkTarball).relative_path_from(Pathname.pwd).to_s}")
# Remove backup of original tarballs
FileUtils.rm_f("#{frameworkTarball}.orig")
# Remove temp dSYMs folder and the temp Framework folder
FileUtils.rm_rf(dsyms_tmp_dir)
FileUtils.rm_rf(File.join(artifacts_dir, "React.xcframework"))
rescue => e
rncore_log("Failed to process dSYMs: #{e.message}", :error)
# Restore the original tarballs
FileUtils.mv("#{frameworkTarball}.orig", frameworkTarball) if File.exist?("#{frameworkTarball}.orig")
rncore_log("Restored original tarballs", :error)
abort "Couldn't process dSYMs: #{e.message}"
end
end
def self.remap_sourcemaps_for_symbols(symbolsPath)
rncore_log(" Remapping dSYMs to be relative to framework folder")
# Find all .dSYM bundles in the symbols path
dsym_bundles = []
Dir.glob(File.join(symbolsPath, "**", "*.dSYM")).each do |path|
if File.directory?(path)
# Check if it's a valid dSYM bundle with Info.plist
info_plist = File.join(path, 'Contents', 'Info.plist')
dsym_bundles << path if File.exist?(info_plist)
end
end
return if dsym_bundles.empty?
# Define source path mappings - from absolute build paths to relative framework paths
# Expand the path relative to the installation root (project root, parent of ios/)
react_native_absolute_path = File.expand_path(@@react_native_path, Pod::Config.instance.installation_root)
mappings = [
["/Users/runner/work/react-native/react-native/packages/react-native", react_native_absolute_path],
]
dsym_bundles.each do |dsym_path| begin
# Get UUIDs for this dSYM bundle
uuid_output = `dwarfdump --uuid "#{dsym_path}" 2>/dev/null`
uuids = uuid_output.scan(/UUID:\s+([0-9A-F-]{36})/i).flatten
next if uuids.empty?
# Create Resources directory if it doesn't exist
resources_dir = File.join(dsym_path, 'Contents', 'Resources')
FileUtils.mkdir_p(resources_dir)
# Generate plist content with path mappings
plist_content = generate_plist_content(mappings)
# Write plist for each UUID
uuids.each do |uuid|
plist_path = File.join(resources_dir, "#{uuid}.plist")
File.write(plist_path, plist_content)
end
rescue => e
rncore_log(" Failed to process dSYM #{dsym_path}: #{e.message}", :error)
end
end
rncore_log(" Completed dSYM remapping for #{dsym_bundles.length} bundles")
end
def self.generate_plist_content(mappings)
# Generate the source path remapping entries
remapping_entries = mappings.map do |from, to|
" <key>#{from}</key><string>#{to}</string>"
end.join("\n")
# Use the first mapping for legacy keys
first_from, first_to = mappings.first
return <<~PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>DBGVersion</key><string>3</string>
<key>DBGBuildSourcePath</key><string>#{first_from}</string>
<key>DBGSourcePath</key><string>#{first_to}</string>
<key>DBGSourcePathRemapping</key>
<dict>
#{remapping_entries}
</dict>
</dict>
</plist>
PLIST
end
def self.stable_tarball_url(version, build_type, dsyms = false)
## You can use the `ENTERPRISE_REPOSITORY` ariable to customise the base url from which artifacts will be downloaded.
## The mirror's structure must be the same of the Maven repo the react-native core team publishes on Maven Central.
maven_repo_url =
ENV['ENTERPRISE_REPOSITORY'] != nil && ENV['ENTERPRISE_REPOSITORY'] != "" ?
ENV['ENTERPRISE_REPOSITORY'] :
"https://repo1.maven.org/maven2"
group = "com/facebook/react"
# Sample url from Maven:
# https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.81.0/react-native-artifacts-0.81.0-reactnative-core-debug.tar.gz
return "#{maven_repo_url}/#{group}/react-native-artifacts/#{version}/react-native-artifacts-#{version}-reactnative-core-#{dsyms ? "dSYM-" : ""}#{build_type.to_s}.tar.gz"
end
def self.nightly_tarball_url(version, configuration, dsyms = false)
artefact_coordinate = "react-native-artifacts"
artefact_name = "reactnative-core-#{dsyms ? "dSYM-" : ""}#{configuration ? configuration : "debug"}.tar.gz"
xml_url = "https://central.sonatype.com/repository/maven-snapshots/com/facebook/react/#{artefact_coordinate}/#{version}-SNAPSHOT/maven-metadata.xml"
response = Net::HTTP.get_response(URI(xml_url))
if response.is_a?(Net::HTTPSuccess)
xml = REXML::Document.new(response.body)
timestamp = xml.elements['metadata/versioning/snapshot/timestamp'].text
build_number = xml.elements['metadata/versioning/snapshot/buildNumber'].text
full_version = "#{version}-#{timestamp}-#{build_number}"
final_url = "https://central.sonatype.com/repository/maven-snapshots/com/facebook/react/#{artefact_coordinate}/#{version}-SNAPSHOT/#{artefact_coordinate}-#{full_version}-#{artefact_name}"
return final_url
else
return ""
end
end
def self.download_stable_rncore(react_native_path, version, configuration, dsyms = false)
tarball_url = stable_tarball_url(version, configuration, dsyms)
download_rncore_tarball(react_native_path, tarball_url, version, configuration, dsyms)
end
def self.download_nightly_rncore(react_native_path, version, configuration, dsyms = false)
tarball_url = nightly_tarball_url(version, configuration, dsyms)
download_rncore_tarball(react_native_path, tarball_url, version, configuration, dsyms)
end
def self.download_rncore_tarball(react_native_path, tarball_url, version, configuration, dsyms = false)
destination_path = configuration == nil ?
"#{artifacts_dir()}/reactnative-core-#{version}#{dsyms ? "-dSYM" : ""}.tar.gz" :
"#{artifacts_dir()}/reactnative-core-#{version}#{dsyms ? "-dSYM" : ""}-#{configuration}.tar.gz"
unless File.exist?(destination_path)
# Download to a temporary file first so we don't cache incomplete downloads.
rncore_log("Downloading ReactNativeCore-prebuilt #{dsyms ? "dSYMs " : ""}#{configuration ? configuration.to_s : ""} tarball from #{tarball_url} to #{Pathname.new(destination_path).relative_path_from(Pathname.pwd).to_s}")
tmp_file = "#{artifacts_dir()}/reactnative-core.download"
`mkdir -p "#{artifacts_dir()}" && curl "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
else
rncore_log("Using downloaded ReactNativeCore-prebuilt #{dsyms ? "dSYMs " : ""}#{configuration ? configuration.to_s : ""} tarball at #{Pathname.new(destination_path).relative_path_from(Pathname.pwd).to_s}")
end
return destination_path
end
def self.release_artifact_exists(version)
return artifact_exists(stable_tarball_url(version, :debug))
end
def self.nightly_artifact_exists(version)
return artifact_exists(nightly_tarball_url(version, :debug).gsub("\\", ""))
end
def self.artifacts_dir()
return File.join(Pod::Config.instance.project_pods_root, "ReactNativeCore-artifacts")
end
# This function checks that ReactNativeCore artifact exists on the maven repo
def self.artifact_exists(tarball_url)
# -L is used to follow redirects, useful for the nightlies
# I also needed to wrap the url in quotes to avoid escaping & and ?.
return (`curl -o /dev/null --silent -Iw '%{http_code}' -L "#{tarball_url}"` == "200")
end
def self.rncore_log(message, level = :info)
if !Object.const_defined?("Pod::UI")
return
end
log_message = '[ReactNativeCore] '
case level
when :info
Pod::UI.puts log_message.green + message
when :error
Pod::UI.puts log_message.red + message
else
Pod::UI.puts log_message.yellow + message
end
end
def self.get_nightly_npm_version()
uri = URI('https://registry.npmjs.org/react-native/nightly')
response = Net::HTTP.get_response(uri)
unless response.is_a?(Net::HTTPSuccess)
raise "Couldn't get an answer from NPM: #{response.code} #{response.message}"
end
json = JSON.parse(response.body)
latest_nightly = json['version']
return latest_nightly
end
end

View File

@@ -0,0 +1,294 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require "json"
require 'net/http'
require 'rexml/document'
require_relative './utils.rb'
## There are two environment variables that is related to ReactNativeDependencies:
## - RCT_USE_RN_DEP: If set to 1, it will use the release tarball from Maven instead of building from source.
## - RCT_USE_LOCAL_RN_DEP: **TEST ONLY** If set, it will use a local tarball of ReactNativeDependencies if it exists.
## - RCT_DEPS_VERSION: **TEST ONLY** If set, it will override the version of ReactNativeDependencies to be used.
### Adds ReactNativeDependencies as a dependency to the given podspec if we're not
### building ReactNativeDependencies from source.
def add_rn_third_party_dependencies(s)
current_pod_target_xcconfig = s.to_hash["pod_target_xcconfig"] || {}
current_pod_target_xcconfig = current_pod_target_xcconfig.to_h unless current_pod_target_xcconfig.is_a?(Hash)
if ReactNativeDependenciesUtils.build_react_native_deps_from_source()
s.dependency "glog"
s.dependency "boost"
s.dependency "DoubleConversion"
s.dependency "fast_float"
s.dependency "fmt"
s.dependency "RCT-Folly"
s.dependency "SocketRocket"
if ENV["RCT_NEW_ARCH_ENABLED"]
s.dependency "RCT-Folly/Fabric"
end
header_search_paths = current_pod_target_xcconfig["HEADER_SEARCH_PATHS"] || []
if header_search_paths.is_a?(String)
header_search_paths = header_search_paths.split(" ")
end
header_search_paths << "$(PODS_ROOT)/glog"
header_search_paths << "$(PODS_ROOT)/boost"
header_search_paths << "$(PODS_ROOT)/DoubleConversion"
header_search_paths << "$(PODS_ROOT)/fast_float/include"
header_search_paths << "$(PODS_ROOT)/fmt/include"
header_search_paths << "$(PODS_ROOT)/SocketRocket"
header_search_paths << "$(PODS_ROOT)/RCT-Folly"
current_pod_target_xcconfig["HEADER_SEARCH_PATHS"] = header_search_paths
else
s.dependency "ReactNativeDependencies"
current_pod_target_xcconfig["HEADER_SEARCH_PATHS"] ||= [] << "$(PODS_ROOT)/ReactNativeDependencies"
end
s.pod_target_xcconfig = current_pod_target_xcconfig
end
class ReactNativeDependenciesUtils
@@build_from_source = true
@@react_native_path = ""
@@react_native_version = ""
@@use_nightly = false
def self.build_react_native_deps_from_source()
return @@build_from_source
end
def self.resolve_podspec_source()
if ENV["RCT_USE_LOCAL_RN_DEP"]
abort_if_use_local_rndeps_with_no_file()
rndeps_log("Using local xcframework at #{ENV["RCT_USE_LOCAL_RN_DEP"]}")
return {:http => "file://#{ENV["RCT_USE_LOCAL_RN_DEP"]}" }
end
if ENV["RCT_USE_RN_DEP"] && ENV["RCT_USE_RN_DEP"] == "1"
if @@use_nightly
begin
return self.podspec_source_download_prebuilt_nightly_tarball(@@react_native_version)
rescue => e
rndeps_log("Failed to download nightly tarball: #{e.message}", :error)
return
end
end
begin
return self.podspec_source_download_prebuild_release_tarball()
rescue => e
rndeps_log("Failed to download release tarball: #{e.message}", :error)
return
end
end
end
## Sets up wether react-native-dependencies should be built from source or not.
## If RCT_USE_RN_DEP is set to 1 and the artifacts exists on Maven, it will
## not build from source. Otherwise, it will build from source.
def self.setup_react_native_dependencies(react_native_path, react_native_version)
# We don't want setup to be called multiple times, so we check if the variables are already set.
if @@react_native_version == ""
rndeps_log("Setting up ReactNativeDependencies...")
@@react_native_path = react_native_path
@@react_native_version = ENV["RCT_DEPS_VERSION"] == nil ? react_native_version : ENV["RCT_DEPS_VERSION"]
if @@react_native_version.include? 'nightly'
@@use_nightly = true
if ENV["RCT_DEPS_VERSION"] == "nightly"
@@react_native_version = ReactNativeDependenciesUtils.get_nightly_npm_version()
rndeps_log("Using nightly version from npm: #{@@react_native_version}")
else
rndeps_log("Using nightly build #{@@react_native_version}")
end
end
if ENV["RCT_USE_LOCAL_RN_DEP"]
abort_if_use_local_rndeps_with_no_file()
end
artifacts_exists = ENV["RCT_USE_RN_DEP"] == "1" && (@@use_nightly ? nightly_artifact_exists(@@react_native_version) : release_artifact_exists(@@react_native_version))
use_local_xcframework = ENV["RCT_USE_LOCAL_RN_DEP"] && File.exist?(ENV["RCT_USE_LOCAL_RN_DEP"])
@@build_from_source = !use_local_xcframework && !artifacts_exists
if @@build_from_source && ENV["RCT_USE_LOCAL_RN_DEP"] && !use_local_xcframework
rndeps_log("No local xcframework found, reverting to building from source.")
end
if @@build_from_source && ENV["RCT_USE_PREBUILT_RNCORE"] && !artifacts_exists
rndeps_log("No prebuilt artifacts found, reverting to building from source.")
end
rndeps_log("Building from source: #{@@build_from_source}")
rndeps_log("Source: #{self.resolve_podspec_source()}")
end
end
def self.abort_if_use_local_rndeps_with_no_file()
if !File.exist?(ENV["RCT_USE_LOCAL_RN_DEP"])
abort("RCT_USE_LOCAL_RN_DEP is set to #{ENV["RCT_USE_LOCAL_RN_DEP"]} but the file does not exist!")
end
end
def self.podspec_source_download_prebuild_release_tarball()
# Warn if @@react_native_path is not set
if @@react_native_path == ""
rndeps_log("react_native_path is not set", :error)
return
end
# Warn if @@react_native_version is not set
if @@react_native_version == ""
rndeps_log("react_native_version is not set", :error)
return
end
if @@build_from_source
return
end
url = release_tarball_url(@@react_native_version, :debug)
rndeps_log("Using tarball from URL: #{url}")
destinationDebug = download_stable_rndeps(@@react_native_path, @@react_native_version, :debug)
download_stable_rndeps(@@react_native_path, @@react_native_version, :release)
return {:http => URI::File.build(path: destinationDebug).to_s }
end
def self.release_tarball_url(version, build_type)
## You can use the `ENTERPRISE_REPOSITORY` ariable to customise the base url from which artifacts will be downloaded.
## The mirror's structure must be the same of the Maven repo the react-native core team publishes on Maven Central.
maven_repo_url =
ENV['ENTERPRISE_REPOSITORY'] != nil && ENV['ENTERPRISE_REPOSITORY'] != "" ?
ENV['ENTERPRISE_REPOSITORY'] :
"https://repo1.maven.org/maven2"
group = "com/facebook/react"
# Sample url from Maven:
# https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.79.0-rc.0/react-native-artifacts-0.79.0-rc.0-reactnative-dependencies-debug.tar.gz
return "#{maven_repo_url}/#{group}/react-native-artifacts/#{version}/react-native-artifacts-#{version}-reactnative-dependencies-#{build_type.to_s}.tar.gz"
end
def self.nightly_tarball_url(version, build_type)
artifact_coordinate = "react-native-artifacts"
artifact_name = "reactnative-dependencies-#{build_type.to_s}.tar.gz"
xml_url = "https://central.sonatype.com/repository/maven-snapshots/com/facebook/react/#{artifact_coordinate}/#{version}-SNAPSHOT/maven-metadata.xml"
response = Net::HTTP.get_response(URI(xml_url))
if response.is_a?(Net::HTTPSuccess)
xml = REXML::Document.new(response.body)
timestamp = xml.elements['metadata/versioning/snapshot/timestamp'].text
build_number = xml.elements['metadata/versioning/snapshot/buildNumber'].text
full_version = "#{version}-#{timestamp}-#{build_number}"
final_url = "https://central.sonatype.com/repository/maven-snapshots/com/facebook/react/#{artifact_coordinate}/#{version}-SNAPSHOT/#{artifact_coordinate}-#{full_version}-#{artifact_name}"
return final_url
else
return ""
end
end
def self.download_nightly_rndeps(react_native_path, version, configuration)
tarball_url = nightly_tarball_url(version, configuration)
download_rndeps_tarball(react_native_path, tarball_url, version, configuration)
end
def self.download_stable_rndeps(react_native_path, version, configuration)
tarball_url = release_tarball_url(version, configuration)
download_rndeps_tarball(react_native_path, tarball_url, version, configuration)
end
def self.podspec_source_download_prebuilt_nightly_tarball(version)
# Warn if @@react_native_path is not set
if @@react_native_path == ""
rndeps_log("react_native_path is not set", :error)
return
end
# Warn if @@react_native_version is not set
if @@react_native_version == ""
rndeps_log("react_native_version is not set", :error)
return
end
if @@build_from_source
return
end
url = nightly_tarball_url(version, :debug)
rndeps_log("Using tarball from URL: #{url}")
destinationDebug = download_nightly_rndeps(@@react_native_path, @@react_native_version, :debug)
download_nightly_rndeps(@@react_native_path, @@react_native_version, :release)
return {:http => URI::File.build(path: destinationDebug).to_s }
return {:http => url}
end
def self.download_rndeps_tarball(react_native_path, tarball_url, version, configuration)
destination_path = configuration == nil ?
"#{artifacts_dir()}/reactnative-dependencies-#{version}.tar.gz" :
"#{artifacts_dir()}/reactnative-dependencies-#{version}-#{configuration}.tar.gz"
unless File.exist?(destination_path)
# Download to a temporary file first so we don't cache incomplete downloads.
tmp_file = "#{artifacts_dir()}/reactnative-dependencies.download"
`mkdir -p "#{artifacts_dir()}" && curl "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
end
return destination_path
end
def self.release_artifact_exists(version)
return artifact_exists(release_tarball_url(version, :debug))
end
def self.nightly_artifact_exists(version)
return artifact_exists(nightly_tarball_url(version, :debug).gsub("\\", ""))
end
def self.artifacts_dir()
return File.join(Pod::Config.instance.project_pods_root, "ReactNativeDependencies-artifacts")
end
# This function checks that ReactNativeDependencies artifact exists on the maven repo
def self.artifact_exists(tarball_url)
# -L is used to follow redirects, useful for the nightlies
# I also needed to wrap the url in quotes to avoid escaping & and ?.
return (`curl -o /dev/null --silent -Iw '%{http_code}' -L "#{tarball_url}"` == "200")
end
def self.rndeps_log(message, level = :info)
if !Object.const_defined?("Pod::UI")
return
end
case level
when :info
Pod::UI.puts '[ReactNativeDependencies] '.green + message
when :error
Pod::UI.puts '[ReactNativeDependencies] '.red + message
else
Pod::UI.puts '[ReactNativeDependencies] '.yellow + message
end
end
def self.get_nightly_npm_version()
uri = URI('https://registry.npmjs.org/react-native/nightly')
response = Net::HTTP.get_response(uri)
unless response.is_a?(Net::HTTPSuccess)
raise "Couldn't get an answer from NPM: #{response.code} #{response.message}"
end
json = JSON.parse(response.body)
latest_nightly = json['version']
return latest_nightly
end
end

18
node_modules/react-native/scripts/cocoapods/runtime.rb generated vendored Normal file
View File

@@ -0,0 +1,18 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
# Set up Bridgeless dependencies
#
# @parameter react_native_path: relative path to react-native
def setup_bridgeless!(react_native_path: "../node_modules/react-native", use_hermes: true)
pod "React-jsitracing", :path => "#{react_native_path}/ReactCommon/hermes/executor/"
pod "React-runtimescheduler", :path => "#{react_native_path}/ReactCommon/react/renderer/runtimescheduler"
pod 'React-RuntimeCore', :path => "#{react_native_path}/ReactCommon/react/runtime"
pod 'React-RuntimeApple', :path => "#{react_native_path}/ReactCommon/react/runtime/platform/ios"
if use_hermes
pod 'React-RuntimeHermes', :path => "#{react_native_path}/ReactCommon/react/runtime"
end
end

94
node_modules/react-native/scripts/cocoapods/spm.rb generated vendored Normal file
View File

@@ -0,0 +1,94 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
class SPMManager
def initialize()
@dependencies_by_pod = {}
end
def dependency(pod_spec, url:, requirement:, products:)
@dependencies_by_pod[pod_spec.name] ||= []
@dependencies_by_pod[pod_spec.name] << { url: url, requirement: requirement, products: products}
end
def apply_on_post_install(installer)
project = installer.pods_project
log 'Cleaning old SPM dependencies from Pods project'
clean_spm_dependencies_from_target(project, @dependencies_by_pod)
log 'Adding SPM dependencies to Pods project'
@dependencies_by_pod.each do |pod_name, dependencies|
dependencies.each do |spm_spec|
log "Adding SPM dependency on product #{spm_spec[:products]}"
add_spm_to_target(
project,
project.targets.find { |t| t.name == pod_name},
spm_spec[:url],
spm_spec[:requirement],
spm_spec[:products]
)
log " Adding workaround for Swift package not found issue"
target = project.targets.find { |t| t.name == pod_name}
target.build_configurations.each do |config|
target.build_settings(config.name)['SWIFT_INCLUDE_PATHS'] ||= ['$(inherited)']
search_path = '${SYMROOT}/${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}/'
unless target.build_settings(config.name)['SWIFT_INCLUDE_PATHS'].include?(search_path)
target.build_settings(config.name)['SWIFT_INCLUDE_PATHS'].push(search_path)
end
end
end
end
unless @dependencies_by_pod.empty?
log_warning "If you're using Xcode 15 or earlier you might need to close and reopen the Xcode workspace"
unless ENV["USE_FRAMEWORKS"] == "dynamic"
@dependencies_by_pod.each do |pod_name, dependencies|
log_warning "Pod #{pod_name} is using swift package(s) #{dependencies.map{|i| i[:products]}.flatten.uniq.join(", ")} with static linking, this might cause linker errors. Consider using USE_FRAMEWORKS=dynamic, see https://github.com/facebook/react-native/pull/44627#issuecomment-2123119711 for more information"
end
end
end
end
private
def log(msg)
::Pod::UI.puts "[SPM] #{msg}"
end
def log_warning(msg)
::Pod::UI.puts "\n\n[SPM] WARNING!!! #{msg}\n\n"
end
def clean_spm_dependencies_from_target(project, new_targets)
project.root_object.package_references.delete_if { |pkg| (pkg.class == Xcodeproj::Project::Object::XCRemoteSwiftPackageReference) }
end
def add_spm_to_target(project, target, url, requirement, products)
pkg_class = Xcodeproj::Project::Object::XCRemoteSwiftPackageReference
ref_class = Xcodeproj::Project::Object::XCSwiftPackageProductDependency
pkg = project.root_object.package_references.find { |p| p.class == pkg_class && p.repositoryURL == url }
if !pkg
pkg = project.new(pkg_class)
pkg.repositoryURL = url
pkg.requirement = requirement
log(" Adding package to workspace: #{pkg.inspect}")
project.root_object.package_references << pkg
end
products.each do |product_name|
ref = target.package_product_dependencies.find do |r|
r.class == ref_class && r.package == pkg && r.product_name == product_name
end
next if ref
log(" Adding product dependency #{product_name} to #{target.name}")
ref = project.new(ref_class)
ref.package = pkg
ref.product_name = product_name
target.package_product_dependencies << ref
end
end
end
SPM = SPMManager.new

727
node_modules/react-native/scripts/cocoapods/utils.rb generated vendored Normal file
View File

@@ -0,0 +1,727 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require 'shellwords'
require_relative "./helpers.rb"
require_relative "./jsengine.rb"
# Utilities class for React Native Cocoapods
class ReactNativePodsUtils
def self.warn_if_not_on_arm64
if SysctlChecker.new().call_sysctl_arm64() == 1 && !Environment.new().ruby_platform().include?('arm64')
Pod::UI.warn 'Do not use "pod install" from inside Rosetta2 (x86_64 emulation on arm64).'
Pod::UI.warn ' - Emulated x86_64 is slower than native arm64'
Pod::UI.warn ' - May result in mixed architectures in rubygems (eg: ffi_c.bundle files may be x86_64 with an arm64 interpreter)'
Pod::UI.warn 'Run "env /usr/bin/arch -arm64 /bin/bash --login" then try again.'
end
end
# deprecated. These checks are duplicated in the react_native_pods function
# and we don't really need them. Removing this function will make it easy to
# move forward.
def self.get_default_flags
flags = {
:fabric_enabled => false,
:hermes_enabled => true,
}
if ENV['RCT_NEW_ARCH_ENABLED'] == '1'
flags[:fabric_enabled] = true
flags[:hermes_enabled] = true
end
if !use_hermes()
flags[:hermes_enabled] = false
end
return flags
end
def self.has_pod(installer, name)
installer.pods_project.pod_group(name) != nil
end
def self.set_gcc_preprocessor_definition_for_React_hermes(installer)
if ENV['RCT_HERMES_V1_ENABLED'] == "1"
self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "HERMES_ENABLE_DEBUGGER=1 HERMES_V1_ENABLED=1", "React-hermes", :debug)
self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "HERMES_ENABLE_DEBUGGER=1 HERMES_V1_ENABLED=1", "React-RuntimeHermes", :debug)
else
self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "HERMES_ENABLE_DEBUGGER=1", "React-hermes", :debug)
self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "HERMES_ENABLE_DEBUGGER=1", "React-RuntimeHermes", :debug)
end
self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "HERMES_ENABLE_DEBUGGER=1", "hermes-engine", :debug)
end
def self.set_gcc_preprocessor_definition_for_debugger(installer)
self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "REACT_NATIVE_DEBUGGER_ENABLED=1", "React-jsinspector", :debug)
self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "REACT_NATIVE_DEBUGGER_ENABLED=1", "React-jsinspectornetwork", :debug)
self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "REACT_NATIVE_DEBUGGER_ENABLED=1", "React-RCTNetwork", :debug)
self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "REACT_NATIVE_DEBUGGER_ENABLED=1", "React-networking", :debug)
self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "REACT_NATIVE_DEBUGGER_ENABLED_DEVONLY=1", "React-jsinspector", :debug)
self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "REACT_NATIVE_DEBUGGER_ENABLED_DEVONLY=1", "React-jsinspectornetwork", :debug)
self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "REACT_NATIVE_DEBUGGER_ENABLED_DEVONLY=1", "React-RCTNetwork", :debug)
self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "REACT_NATIVE_DEBUGGER_ENABLED_DEVONLY=1", "React-networking", :debug)
end
def self.turn_off_resource_bundle_react_core(installer)
# this is needed for Xcode 14, see more details here https://github.com/facebook/react-native/issues/34673
# we should be able to remove this once CocoaPods catches up to it, see more details here https://github.com/CocoaPods/CocoaPods/issues/11402
installer.target_installation_results.pod_target_installation_results.each do |pod_name, target_installation_result|
if pod_name.to_s == 'React-Core'
target_installation_result.resource_bundle_targets.each do |resource_bundle_target|
resource_bundle_target.build_configurations.each do |config|
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
end
end
end
end
end
def self.set_build_setting(installer, build_setting:, value:, config_name: nil)
Pod::UI.puts("Setting #{build_setting} build settings")
projects = self.extract_projects(installer)
projects.each do |project|
project.build_configurations.each do |config|
if config_name == nil || config.name == config_name
config.build_settings[build_setting] = value
end
end
project.save()
end
end
def self.set_ccache_compiler_and_linker_build_settings(installer, react_native_path, ccache_enabled)
projects = self.extract_projects(installer)
ccache_path = `command -v ccache`.strip
ccache_available = !ccache_path.empty?
message_prefix = "[Ccache]"
if ccache_available
Pod::UI.puts("#{message_prefix}: Ccache found at #{ccache_path}")
end
# Using scripts wrapping the ccache executable, to allow injection of configurations
ccache_clang_sh = File.join("$(REACT_NATIVE_PATH)", 'scripts', 'xcode', 'ccache-clang.sh')
ccache_clangpp_sh = File.join("$(REACT_NATIVE_PATH)", 'scripts', 'xcode', 'ccache-clang++.sh')
if ccache_available and ccache_enabled
Pod::UI.puts("#{message_prefix}: Setting CC, LD, CXX & LDPLUSPLUS build settings")
projects.each do |project|
project.build_configurations.each do |config|
# Using the un-qualified names means you can swap in different implementations, for example ccache
config.build_settings["CC"] = ccache_clang_sh
config.build_settings["LD"] = ccache_clang_sh
config.build_settings["CXX"] = ccache_clangpp_sh
config.build_settings["LDPLUSPLUS"] = ccache_clangpp_sh
config.build_settings["CCACHE_BINARY"] = ccache_path
end
project.save()
end
elsif ccache_available and !ccache_enabled
Pod::UI.puts("#{message_prefix}: Pass ':ccache_enabled => true' to 'react_native_post_install' in your Podfile or set environment variable 'USE_CCACHE=1' to increase the speed of subsequent builds")
elsif !ccache_available and ccache_enabled
Pod::UI.warn("#{message_prefix}: Install ccache or ensure your neither passing ':ccache_enabled => true' nor setting environment variable 'USE_CCACHE=1'")
else
Pod::UI.puts("#{message_prefix}: Removing Ccache from CC, LD, CXX & LDPLUSPLUS build settings")
projects.each do |project|
project.build_configurations.each do |config|
# Using the un-qualified names means you can swap in different implementations, for example ccache
config.build_settings["CC"] = config.build_settings["CC"].gsub(/#{Regexp.escape(ccache_clang_sh)}/, '') if config.build_settings["CC"]
config.build_settings["LD"] = config.build_settings["LD"].gsub(/#{Regexp.escape(ccache_clang_sh)}/, "") if config.build_settings["LD"]
config.build_settings["CXX"] = config.build_settings["CXX"].gsub(/#{Regexp.escape(ccache_clangpp_sh)}/, "") if config.build_settings["CXX"]
config.build_settings["LDPLUSPLUS"] = config.build_settings["LDPLUSPLUS"].gsub(/#{Regexp.escape(ccache_clangpp_sh)}/, "") if config.build_settings["LDPLUSPLUS"]
end
project.save()
end
end
end
def self.fix_library_search_paths(installer)
projects = self.extract_projects(installer)
projects.each do |project|
project.build_configurations.each do |config|
self.fix_library_search_path(config)
end
project.native_targets.each do |target|
target.build_configurations.each do |config|
self.fix_library_search_path(config)
end
end
project.save()
end
end
def self.apply_mac_catalyst_patches(installer)
# Fix bundle signing issues
installer.pods_project.targets.each do |target|
if target.respond_to?(:product_type) and target.product_type == "com.apple.product-type.bundle"
target.build_configurations.each do |config|
config.build_settings['CODE_SIGN_IDENTITY[sdk=macosx*]'] = '-'
end
end
end
installer.aggregate_targets.each do |aggregate_target|
aggregate_target.user_project.native_targets.each do |target|
target.build_configurations.each do |config|
# Explicitly set dead code stripping flags
config.build_settings['DEAD_CODE_STRIPPING'] = 'YES'
config.build_settings['PRESERVE_DEAD_CODE_INITS_AND_TERMS'] = 'YES'
# Modify library search paths
config.build_settings['LIBRARY_SEARCH_PATHS'] = ['$(SDKROOT)/usr/lib/swift', '$(SDKROOT)/System/iOSSupport/usr/lib/swift', '$(inherited)']
end
end
aggregate_target.user_project.save()
end
end
private
def self.add_build_settings_to_pod(installer, settings_name, settings_value, target_pod_name, configuration_type)
installer.target_installation_results.pod_target_installation_results.each do |pod_name, target_installation_result|
if pod_name.to_s == target_pod_name
target_installation_result.native_target.build_configurations.each do |config|
if configuration_type == nil || (configuration_type != nil && config.type == configuration_type)
config.build_settings[settings_name] ||= '$(inherited) '
config.build_settings[settings_name] << settings_value
end
end
end
end
end
def self.fix_library_search_path(config)
lib_search_paths = config.build_settings["LIBRARY_SEARCH_PATHS"]
if lib_search_paths == nil
# No search paths defined, return immediately
return
end
if lib_search_paths.include?("$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)") || lib_search_paths.include?("\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"")
# $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) causes problem with Xcode 12.5 + arm64 (Apple Silicon)
# since the libraries there are only built for x86_64 and i386.
lib_search_paths.delete("$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)")
lib_search_paths.delete("\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"")
end
if !(lib_search_paths.include?("$(SDKROOT)/usr/lib/swift") || lib_search_paths.include?("\"$(SDKROOT)/usr/lib/swift\""))
# however, $(SDKROOT)/usr/lib/swift is required, at least if user is not running CocoaPods 1.11
lib_search_paths.insert(0, "$(SDKROOT)/usr/lib/swift")
end
end
def self.create_xcode_env_if_missing(file_manager: File)
relative_path = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd)
file_path = file_manager.join(relative_path, '.xcode.env')
if !file_manager.exist?(file_path)
system("echo 'export NODE_BINARY=$(command -v node)' > #{file_path}")
end
if !file_manager.exist?("#{file_path}.local")
# When installing pods with a yarn alias, yarn creates a fake yarn and node executables
# in a temporary folder.
# Using `node --print "process.argv[0]";` we are able to retrieve the actual path from which node is running.
# see https://github.com/facebook/react-native/issues/43285 for more info. We've tweaked this slightly.
node_binary = Shellwords.escape(`node --print "process.argv[0]"`.strip)
system("echo 'export NODE_BINARY=#{node_binary}' > #{file_path}.local")
end
end
# It examines the target_definition property and sets the appropriate value for
# ENV['USE_FRAMEWORKS'] variable.
#
# - parameter target_definition: The current target definition
def self.detect_use_frameworks(target_definition)
if ENV['USE_FRAMEWORKS'] != nil
return
end
framework_build_type = target_definition.build_type.to_s
Pod::UI.puts("Framework build type is #{framework_build_type}")
if framework_build_type === "static framework"
ENV['USE_FRAMEWORKS'] = 'static'
elsif framework_build_type === "dynamic framework"
ENV['USE_FRAMEWORKS'] = 'dynamic'
else
ENV['USE_FRAMEWORKS'] = nil
end
end
def self.create_header_search_path_for_frameworks(base_folder, pod_name, framework_name, additional_paths, include_base_path = true)
search_paths = []
# When building using the prebuilt rncore we can't use framework folders as search paths since these aren't created
# Except for when adding search path for ReactCodegen since it contains source code.
if ReactNativeCoreUtils.build_rncore_from_source() || pod_name === "ReactCodegen"
platforms = $RN_PLATFORMS != nil ? $RN_PLATFORMS : []
if platforms.empty?() || platforms.length() == 1
base_path = File.join("${#{base_folder}}", pod_name, "#{framework_name}.framework", "Headers")
self.add_search_path_to_result(search_paths, base_path, additional_paths, include_base_path)
else
platforms.each { |platform|
base_path = File.join("${#{base_folder}}", "#{pod_name}-#{platform}", "#{framework_name}.framework", "Headers")
self.add_search_path_to_result(search_paths, base_path, additional_paths, include_base_path)
}
end
else
base_path = File.join("${PODS_ROOT}", "#{pod_name}")
self.add_search_path_to_result(search_paths, base_path, additional_paths, include_base_path)
end
return search_paths
end
# Add a new dependency to an existing spec, configuring also the headers search paths
def self.add_dependency(spec, dependency_name, base_folder_for_frameworks, framework_name, additional_paths: [], version: nil, subspec_dependency: nil)
# Update Search Path
current_pod_target_xcconfig = spec.to_hash["pod_target_xcconfig"] ? spec.to_hash["pod_target_xcconfig"] : {}
optional_current_search_path = current_pod_target_xcconfig["HEADER_SEARCH_PATHS"]
current_search_paths = (optional_current_search_path != nil ? optional_current_search_path : "")
.split(" ")
create_header_search_path_for_frameworks(base_folder_for_frameworks, dependency_name, framework_name, additional_paths)
.each { |path|
wrapped_path = "\"#{path}\""
current_search_paths << wrapped_path
}
current_pod_target_xcconfig["HEADER_SEARCH_PATHS"] = current_search_paths.join(" ")
spec.pod_target_xcconfig = current_pod_target_xcconfig
actual_dependency = subspec_dependency != nil ? "#{dependency_name}/#{subspec_dependency}" : dependency_name
# Set Dependency
if !version
spec.dependency actual_dependency
else
spec.dependency actual_dependency, version
end
end
def self.update_search_paths(installer)
return if ENV['USE_FRAMEWORKS'] == nil
projects = self.extract_projects(installer)
projects.each do |project|
project.build_configurations.each do |config|
header_search_paths = config.build_settings["HEADER_SEARCH_PATHS"] ||= "$(inherited)"
ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "ReactCommon", "ReactCommon", ["react/nativemodule/core"])
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-runtimeexecutor", "React_runtimeexecutor", ["platform/ios"]))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "ReactCommon-Samples", "ReactCommon_Samples", ["platform/ios"]))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-Fabric", "React_Fabric", ["react/renderer/components/view/platform/cxx"], false))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-NativeModulesApple", "React_NativeModulesApple", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-graphics", "React_graphics", ["react/renderer/graphics/platform/ios"]))
.each{ |search_path|
header_search_paths = self.add_search_path_if_not_included(header_search_paths, search_path)
}
config.build_settings["HEADER_SEARCH_PATHS"] = header_search_paths
end
project.save()
end
installer.target_installation_results.pod_target_installation_results.each do |pod_name, target_installation_result|
if self.react_native_pods.include?(pod_name) || pod_name.include?("Pod") || pod_name.include?("Tests")
next
end
self.set_rctfolly_search_paths(target_installation_result)
self.set_codegen_search_paths(target_installation_result)
self.set_reactcommon_searchpaths(target_installation_result)
self.set_rctfabric_search_paths(target_installation_result)
self.set_imagemanager_search_path(target_installation_result)
end
end
def self.updateOSDeploymentTarget(installer)
installer.target_installation_results.pod_target_installation_results
.each do |pod_name, target_installation_result|
target_installation_result.native_target.build_configurations.each do |config|
old_iphone_deploy_target = config.build_settings["IPHONEOS_DEPLOYMENT_TARGET"] ?
config.build_settings["IPHONEOS_DEPLOYMENT_TARGET"] :
Helpers::Constants.min_ios_version_supported
config.build_settings["IPHONEOS_DEPLOYMENT_TARGET"] = [Helpers::Constants.min_ios_version_supported.to_f, old_iphone_deploy_target.to_f].max.to_s
end
end
end
def self.set_dynamic_frameworks_flags(installer)
installer.target_installation_results.pod_target_installation_results.each do |pod_name, target_installation_result|
# Set "RCT_DYNAMIC_FRAMEWORKS=1" if pod are installed with USE_FRAMEWORKS=dynamic
# This helps with backward compatibility.
if pod_name == 'React-RCTFabric' && ENV['USE_FRAMEWORKS'] == 'dynamic'
Pod::UI.puts "Setting -DRCT_DYNAMIC_FRAMEWORKS=1 to React-RCTFabric".green
rct_dynamic_framework_flag = " -DRCT_DYNAMIC_FRAMEWORKS=1"
target_installation_result.native_target.build_configurations.each do |config|
prev_build_settings = config.build_settings['OTHER_CPLUSPLUSFLAGS'] != nil ? config.build_settings['OTHER_CPLUSPLUSFLAGS'] : "$(inherited)"
config.build_settings['OTHER_CPLUSPLUSFLAGS'] = prev_build_settings + rct_dynamic_framework_flag
end
end
end
end
# ========= #
# Utilities #
# ========= #
def self.extract_projects(installer)
return installer.aggregate_targets
.map{ |t| t.user_project }
.uniq{ |p| p.path }
.push(installer.pods_project)
end
def self.safe_init(config, setting_name)
old_config = config.build_settings[setting_name]
if old_config == nil
config.build_settings[setting_name] ||= '$(inherited) '
end
end
def self.add_value_to_setting_if_missing(config, setting_name, value)
old_config = config.build_settings[setting_name]
if old_config.is_a?(Array)
old_config = old_config.join(" ")
end
trimmed_value = value.strip()
if !old_config.include?(trimmed_value)
config.build_settings[setting_name] = "#{old_config.strip()} #{trimmed_value}".strip()
end
end
def self.remove_value_from_setting_if_present(config, setting_name, value)
old_config = config.build_settings[setting_name]
if old_config.is_a?(Array)
old_config = old_config.join(" ")
end
trimmed_value = value.strip()
if old_config.include?(trimmed_value)
new_config = old_config.gsub(trimmed_value, "")
config.build_settings[setting_name] = new_config.strip()
end
end
def self.parse_xcode_version(version_string)
# The output of xcodebuild -version is something like
# Xcode 15.0
# or
# Xcode 14.3.1
# We want to capture the version digits
match = version_string.match(/(\d+)\.(\d+)(?:\.(\d+))?/)
return nil if match.nil?
return {"str" => match[0], "major" => match[1].to_i, "minor" => match[2].to_i};
end
def self.check_minimum_required_xcode(xcodebuild_manager: Xcodebuild)
version = self.parse_xcode_version(xcodebuild_manager.version)
if (version.nil? || !Gem::Version::correct?(version["str"]))
Pod::UI.warn "Unexpected XCode version string '#{xcodebuild_manager.version}'"
return
end
current = version["str"]
min_required = Helpers::Constants.min_xcode_version_supported
if Gem::Version::new(current) < Gem::Version::new(min_required)
Pod::UI.puts "React Native requires XCode >= #{min_required}. Found #{current}.".red
raise "Please upgrade XCode"
end
end
def self.add_compiler_flag_to_project(installer, flag, configuration: nil)
projects = self.extract_projects(installer)
projects.each do |project|
project.build_configurations.each do |config|
self.set_flag_in_config(config, flag, configuration: configuration)
end
project.save()
end
end
def self.remove_compiler_flag_from_project(installer, flag, configuration: nil)
projects = self.extract_projects(installer)
projects.each do |project|
project.build_configurations.each do |config|
self.remove_flag_in_config(config, flag, configuration: configuration)
end
project.save()
end
end
def self.add_compiler_flag_to_pods(installer, flag, configuration: nil)
installer.target_installation_results.pod_target_installation_results.each do |pod_name, target_installation_result|
target_installation_result.native_target.build_configurations.each do |config|
self.set_flag_in_config(config, flag, configuration: configuration)
end
end
end
def self.set_flag_in_config(config, flag, configuration: nil)
if configuration == nil || config.name == configuration
self.add_flag_for_key(config, flag, "OTHER_CFLAGS")
self.add_flag_for_key(config, flag, "OTHER_CPLUSPLUSFLAGS")
end
end
def self.remove_flag_in_config(config, flag, configuration: nil)
if configuration == nil || config.name == configuration
self.remove_flag_for_key(config, flag, "OTHER_CFLAGS")
self.remove_flag_for_key(config, flag, "OTHER_CPLUSPLUSFLAGS")
end
end
def self.add_flag_for_key(config, flag, key)
current_setting = config.build_settings[key] ? config.build_settings[key] : "$(inherited)"
if current_setting.kind_of?(Array)
current_setting = current_setting
.map { |s| s.gsub('"', '') }
.map { |s| s.gsub('\"', '') }
.join(" ")
end
if !current_setting.include?(flag)
current_setting = "#{current_setting} #{flag}"
end
config.build_settings[key] = current_setting
end
def self.remove_flag_for_key(config, flag, key)
current_setting = config.build_settings[key] ? config.build_settings[key] : "$(inherited)"
if current_setting.kind_of?(Array)
current_setting = current_setting
.map { |s| s.gsub('"', '') }
.map { |s| s.gsub('\"', '') }
.join(" ")
end
if current_setting.include?(flag)
current_setting.slice! flag
current_setting.strip!
end
config.build_settings[key] = current_setting
end
def self.add_search_path_if_not_included(current_search_paths, new_search_path)
new_search_path = new_search_path.strip
if current_search_paths.is_a?(String)
current_search_paths = current_search_paths.strip
return "#{current_search_paths} #{new_search_path}" unless current_search_paths.include?(new_search_path)
end
if current_search_paths.is_a?(Array)
current_search_paths = current_search_paths.map(&:strip)
return current_search_paths << new_search_path unless current_search_paths.include?(new_search_path)
end
current_search_paths
end
def self.update_header_paths_if_depends_on(target_installation_result, dependency_name, header_paths)
depends_on_framework = target_installation_result.native_target.dependencies.any? { |d| d.name == dependency_name }
if depends_on_framework
target_installation_result.native_target.build_configurations.each do |config|
header_search_path = config.build_settings["HEADER_SEARCH_PATHS"] != nil ? config.build_settings["HEADER_SEARCH_PATHS"] : "$(inherited)"
header_paths.each { |header| header_search_path = ReactNativePodsUtils.add_search_path_if_not_included(header_search_path, header) }
config.build_settings["HEADER_SEARCH_PATHS"] = header_search_path
end
end
end
def self.set_rctfolly_search_paths(target_installation_result)
ReactNativePodsUtils.update_header_paths_if_depends_on(target_installation_result, "RCT-Folly", [
"\"$(PODS_ROOT)/RCT-Folly\"",
"\"$(PODS_ROOT)/DoubleConversion\"",
"\"$(PODS_ROOT)/fast_float/include\"",
"\"$(PODS_ROOT)/fmt/include\"",
"\"$(PODS_ROOT)/boost\""
])
end
def self.set_codegen_search_paths(target_installation_result)
header_search_paths = ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "ReactCodegen", "ReactCodegen", [])
.map { |search_path| "\"#{search_path}\"" }
ReactNativePodsUtils.update_header_paths_if_depends_on(target_installation_result, "ReactCodegen", header_search_paths)
end
def self.set_reactcommon_searchpaths(target_installation_result)
header_search_paths = ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "ReactCommon", "ReactCommon", ["react/nativemodule/core"])
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-runtimeexecutor", "React_runtimeexecutor", ["platform/ios"]))
.map { |search_path| "\"#{search_path}\"" }
ReactNativePodsUtils.update_header_paths_if_depends_on(target_installation_result, "ReactCommon", header_search_paths)
end
def self.set_rctfabric_search_paths(target_installation_result)
header_search_paths = ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-RCTFabric", "RCTFabric", [])
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-Fabric", "React_Fabric", ["react/renderer/components/view/platform/cxx"]))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-FabricImage", "React_FabricImage", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-Graphics", "React_graphics", ["react/renderer/graphics/platform/ios"]))
.map { |search_path| "\"#{search_path}\"" }
ReactNativePodsUtils.update_header_paths_if_depends_on(target_installation_result, "React-RCTFabric", header_search_paths)
end
def self.set_imagemanager_search_path(target_installation_result)
header_search_paths = ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-Fabric", "React_Fabric", ["react/renderer/imagemanager/platform/ios"])
.map { |search_path| "\"#{search_path}\"" }
ReactNativePodsUtils.update_header_paths_if_depends_on(target_installation_result, "React-ImageManager", header_search_paths)
end
def self.react_native_pods
pods = [
"DoubleConversion",
"FBLazyVector",
"RCT-Folly",
"RCTRequired",
"RCTTypeSafety",
"React",
"ReactCodegen",
"React-Core",
"React-CoreModules",
"React-Fabric",
"React-FabricImage",
"React-ImageManager",
"React-RCTActionSheet",
"React-RCTAnimation",
"React-RCTAppDelegate",
"React-RCTBlob",
"React-RCTFabric",
"React-RCTRuntime",
"React-RCTImage",
"React-RCTLinking",
"React-RCTNetwork",
"React-RCTPushNotification",
"React-RCTSettings",
"React-RCTText",
"React-RCTTest",
"React-RCTVibration",
"React-callinvoker",
"React-cxxreact",
"React-graphics",
"React-jsi",
"React-jsiexecutor",
"React-jsinspector",
"React-jsitooling",
"React-logger",
"React-oscompat",
"React-perflogger",
"React-runtimeexecutor",
"React-timing",
"ReactCommon",
"Yoga",
"boost",
"fast_float",
"fmt",
"glog",
"hermes-engine",
"React-hermes",
]
if ENV['USE_THIRD_PARTY_JSC'] != '1'
pods << "React-jsc"
end
return pods
end
def self.add_search_path_to_result(result, base_path, additional_paths, include_base_path)
if (include_base_path)
result << base_path
end
additional_paths.each { |extra_path|
result << File.join(base_path, extra_path)
}
return result
end
def self.add_ndebug_flag_to_pods_in_release(installer)
ndebug_flag = " -DNDEBUG"
installer.aggregate_targets.each do |aggregate_target|
aggregate_target.xcconfigs.each do |config_name, config_file|
is_release = aggregate_target.user_build_configurations[config_name] == :release
unless is_release
next
end
self.add_flag_to_map_with_inheritance(config_file.attributes, 'OTHER_CPLUSPLUSFLAGS', ndebug_flag);
self.add_flag_to_map_with_inheritance(config_file.attributes, 'OTHER_CFLAGS', ndebug_flag);
xcconfig_path = aggregate_target.xcconfig_path(config_name)
config_file.save_as(xcconfig_path)
end
end
installer.target_installation_results.pod_target_installation_results.each do |pod_name, target_installation_result|
target_installation_result.native_target.build_configurations.each do |config|
is_release = config.type == :release
unless is_release
next
end
self.add_flag_to_map_with_inheritance(config.build_settings, 'OTHER_CPLUSPLUSFLAGS', ndebug_flag);
self.add_flag_to_map_with_inheritance(config.build_settings, 'OTHER_CFLAGS', ndebug_flag);
end
end
end
def self.add_flag_to_map_with_inheritance(map, field, flag)
if map[field] == nil
map[field] = "$(inherited)" + flag
else
unless map[field].include?(flag)
if map[field].instance_of? String
map[field] = map[field] + flag
elsif map[field].instance_of? Array
map[field].push(flag)
end
end
unless map[field].include?("$(inherited)")
if map[field].instance_of? String
map[field] = "$(inherited) " + map[field]
elsif map[field].instance_of? Array
map[field].unshift("$(inherited)")
end
end
end
end
def self.resolve_use_frameworks(spec, header_mappings_dir: nil, module_name: nil)
return unless ENV['USE_FRAMEWORKS']
if module_name
spec.module_name = module_name
end
if header_mappings_dir != nil && ReactNativeCoreUtils.build_rncore_from_source()
spec.header_mappings_dir = header_mappings_dir
end
end
end