mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
d669ff7df8
* add privacy manifest to pod install Summary: Changelog: [iOS][Added] this creates the RN privacy manifest in the ios build step if user has not created one yet. the reasons have been added for the following APIs: NSPrivacyAccessedAPICategoryFileTimestamp - C617.1: We use fstat and stat in a few places in the C++ layer. We use these to read information about the JavaScript files in RN. NSPrivacyAccessedAPICategoryUserDefaults - CA92.1: We access NSUserDefaults in a few places. 1) To store RTL preferences 2) As part of caching server URLs for developer mode 3) A generic native module that wraps NSUserDefaults NSPrivacyAccessedAPICategorySystemBootTime - 35F9.1: Best guess reason from RR API pulled in by boost Reviewed By: cipolleschi Differential Revision: D53687232 fbshipit-source-id: 6dffb1a6013f8f29438a49752e47ed75c13f4a5c * add privacy manifest to hello world template Summary: Changelog: [iOS][Added] this change will be included in the RN CLI. so all new apps running the RN CLI to get created will get this manifest. the reasons have been added for the following APIs: NSPrivacyAccessedAPICategoryFileTimestamp - C617.1: We use fstat and stat in a few places in the C++ layer. We use these to read information about the JavaScript files in RN. NSPrivacyAccessedAPICategoryUserDefaults - CA92.1: We access NSUserDefaults in a few places. 1) To store RTL preferences 2) As part of caching server URLs for developer mode 3) A generic native module that wraps NSUserDefaults NSPrivacyAccessedAPICategorySystemBootTime - 35F9.1: Best guess reason from RR API pulled in by boost Reviewed By: cipolleschi Differential Revision: D53682756 fbshipit-source-id: 0426fe0002a3bc8b45ef24053ac4228c9f61eb85 --------- Co-authored-by: Phillip Pan <phillippan@meta.com>
379 lines
15 KiB
Ruby
379 lines
15 KiB
Ruby
# 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"
|
|
|
|
# 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
|
|
|
|
def self.get_default_flags
|
|
flags = {
|
|
:fabric_enabled => false,
|
|
:hermes_enabled => true,
|
|
:flipper_configuration => FlipperConfiguration.disabled
|
|
}
|
|
|
|
if ENV['RCT_NEW_ARCH_ENABLED'] == '1'
|
|
flags[:fabric_enabled] = true
|
|
flags[:hermes_enabled] = true
|
|
end
|
|
|
|
if ENV['USE_HERMES'] == '0'
|
|
flags[:hermes_enabled] = false
|
|
end
|
|
|
|
return flags
|
|
end
|
|
|
|
def self.has_pod(installer, name)
|
|
installer.pods_project.pod_group(name) != nil
|
|
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.extract_projects(installer)
|
|
return installer.aggregate_targets
|
|
.map{ |t| t.user_project }
|
|
.uniq{ |p| p.path }
|
|
.push(installer.pods_project)
|
|
end
|
|
|
|
def self.exclude_i386_architecture_while_using_hermes(installer)
|
|
is_using_hermes = self.has_pod(installer, 'hermes-engine')
|
|
|
|
if is_using_hermes
|
|
key = "EXCLUDED_ARCHS[sdk=iphonesimulator*]"
|
|
|
|
projects = self.extract_projects(installer)
|
|
|
|
projects.each do |project|
|
|
project.build_configurations.each do |config|
|
|
current_setting = config.build_settings[key] || ""
|
|
|
|
excluded_archs_includes_I386 = current_setting.include?("i386")
|
|
|
|
if !excluded_archs_includes_I386
|
|
# Hermes does not support `i386` architecture
|
|
config.build_settings[key] = "#{current_setting} i386".strip
|
|
end
|
|
end
|
|
|
|
project.save()
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.set_node_modules_user_settings(installer, react_native_path)
|
|
Pod::UI.puts("Setting REACT_NATIVE build settings")
|
|
projects = installer.aggregate_targets
|
|
.map{ |t| t.user_project }
|
|
.uniq{ |p| p.path }
|
|
.push(installer.pods_project)
|
|
|
|
projects.each do |project|
|
|
project.build_configurations.each do |config|
|
|
config.build_settings["REACT_NATIVE_PATH"] = File.join("${PODS_ROOT}", "..", react_native_path)
|
|
end
|
|
|
|
project.save()
|
|
end
|
|
end
|
|
|
|
def self.fix_library_search_paths(installer)
|
|
projects = installer.aggregate_targets
|
|
.map{ |t| t.user_project }
|
|
.uniq{ |p| p.path }
|
|
.push(installer.pods_project)
|
|
|
|
projects.each do |project|
|
|
project.build_configurations.each do |config|
|
|
ReactNativePodsUtils.fix_library_search_path(config)
|
|
end
|
|
project.native_targets.each do |target|
|
|
target.build_configurations.each do |config|
|
|
ReactNativePodsUtils.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
|
|
|
|
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.add_privacy_manifest_if_needed(installer)
|
|
user_project = installer.aggregate_targets
|
|
.map{ |t| t.user_project }
|
|
.first
|
|
privacy_manifest = self.get_privacy_manifest_paths_from(user_project).first
|
|
if privacy_manifest.nil?
|
|
file_timestamp_reason = {
|
|
"NSPrivacyAccessedAPIType" => "NSPrivacyAccessedAPICategoryFileTimestamp",
|
|
"NSPrivacyAccessedAPITypeReasons" => ["C617.1"],
|
|
}
|
|
user_defaults_reason = {
|
|
"NSPrivacyAccessedAPIType" => "NSPrivacyAccessedAPICategoryUserDefaults",
|
|
"NSPrivacyAccessedAPITypeReasons" => ["CA92.1"],
|
|
}
|
|
boot_time_reason = {
|
|
"NSPrivacyAccessedAPIType" => "NSPrivacyAccessedAPICategorySystemBootTime",
|
|
"NSPrivacyAccessedAPITypeReasons" => ["35F9.1"],
|
|
}
|
|
privacy_manifest = {
|
|
"NSPrivacyCollectedDataTypes" => [],
|
|
"NSPrivacyTracking" => false,
|
|
"NSPrivacyAccessedAPITypes" => [file_timestamp_reason, user_defaults_reason, boot_time_reason]
|
|
}
|
|
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
|
|
|
|
def self.fix_flipper_for_xcode_15_3(installer)
|
|
installer.pods_project.targets.each do |target|
|
|
if target.name == 'Flipper'
|
|
file_path = 'Pods/Flipper/xplat/Flipper/FlipperTransportTypes.h'
|
|
if !File.exist?(file_path)
|
|
return
|
|
end
|
|
|
|
contents = File.read(file_path)
|
|
if contents.include?('#include <functional>')
|
|
return
|
|
end
|
|
mod_content = contents.gsub("#pragma once", "#pragma once\n#include <functional>")
|
|
File.chmod(0755, file_path)
|
|
File.open(file_path, 'w') do |file|
|
|
file.puts(mod_content)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.apply_xcode_15_patch(installer, xcodebuild_manager: Xcodebuild)
|
|
projects = self.extract_projects(installer)
|
|
|
|
gcc_preprocessor_definition_key = 'GCC_PREPROCESSOR_DEFINITIONS'
|
|
other_ld_flags_key = 'OTHER_LDFLAGS'
|
|
libcpp_cxx17_fix = '_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION'
|
|
xcode15_compatibility_flags = '-Wl -ld_classic '
|
|
|
|
projects.each do |project|
|
|
project.build_configurations.each do |config|
|
|
# fix for unary_function and binary_function
|
|
self.safe_init(config, gcc_preprocessor_definition_key)
|
|
self.add_value_to_setting_if_missing(config, gcc_preprocessor_definition_key, libcpp_cxx17_fix)
|
|
|
|
# fix for weak linking
|
|
self.safe_init(config, other_ld_flags_key)
|
|
if self.is_using_xcode15_0(:xcodebuild_manager => xcodebuild_manager)
|
|
self.add_value_to_setting_if_missing(config, other_ld_flags_key, xcode15_compatibility_flags)
|
|
else
|
|
self.remove_value_from_setting_if_present(config, other_ld_flags_key, xcode15_compatibility_flags)
|
|
end
|
|
end
|
|
project.save()
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
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 M1)
|
|
# 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
|
|
relative_path = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd)
|
|
file_path = File.join(relative_path, '.xcode.env')
|
|
if File.exist?(file_path)
|
|
return
|
|
end
|
|
|
|
system("echo 'export NODE_BINARY=$(command -v node)' > #{file_path}")
|
|
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.updateIphoneOSDeploymentTarget(installer)
|
|
pod_to_update = Set.new([
|
|
"boost",
|
|
"CocoaAsyncSocket",
|
|
"Flipper",
|
|
"Flipper-DoubleConversion",
|
|
"Flipper-Fmt",
|
|
"Flipper-Boost-iOSX",
|
|
"Flipper-Folly",
|
|
"Flipper-Glog",
|
|
"Flipper-PeerTalk",
|
|
"FlipperKit",
|
|
"fmt",
|
|
"libevent",
|
|
"OpenSSL-Universal",
|
|
"RCT-Folly",
|
|
"SocketRocket",
|
|
"YogaKit"
|
|
])
|
|
|
|
installer.target_installation_results.pod_target_installation_results
|
|
.each do |pod_name, target_installation_result|
|
|
unless pod_to_update.include?(pod_name)
|
|
next
|
|
end
|
|
target_installation_result.native_target.build_configurations.each do |config|
|
|
config.build_settings["IPHONEOS_DEPLOYMENT_TARGET"] = Helpers::Constants.min_ios_version_supported
|
|
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.is_using_xcode15_0(xcodebuild_manager: Xcodebuild)
|
|
xcodebuild_version = xcodebuild_manager.version
|
|
|
|
# The output of xcodebuild -version is something like
|
|
# Xcode 15.0
|
|
# or
|
|
# Xcode 14.3.1
|
|
# We want to capture the version digits
|
|
regex = /(\d+)\.(\d+)(?:\.(\d+))?/
|
|
if match_data = xcodebuild_version.match(regex)
|
|
major = match_data[1].to_i
|
|
minor = match_data[2].to_i
|
|
return major == 15 && minor == 0
|
|
end
|
|
|
|
return false
|
|
end
|
|
end
|