Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions packages/react-native/scripts/cocoapods/spm.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
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_FRAMEOWRKS=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
14 changes: 14 additions & 0 deletions packages/react-native/scripts/react_native_pods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
require_relative './cocoapods/runtime.rb'
require_relative './cocoapods/helpers.rb'
require_relative './cocoapods/privacy_manifest_utils.rb'
require_relative './cocoapods/spm.rb'
# Importing to expose use_native_modules!
require_relative './cocoapods/autolinking.rb'

Expand Down Expand Up @@ -241,6 +242,18 @@ def install_modules_dependencies(spec, new_arch_enabled: NewArchitectureHelper.n
NewArchitectureHelper.install_modules_dependencies(spec, new_arch_enabled, folly_config[:version])
end


# This function can be used by library developer to declare an SwiftPackageManager dependency.
#
# Parameters:
# - spec: The spec the Swift Package Manager dependency has to be added to
# - url: The URL of the Swift Package Manager dependency
# - requirement: The version requirement of the Swift Package Manager dependency (eg. ` {kind: 'upToNextMajorVersion', minimumVersion: '5.9.1'},`)
# - products: The product/target of the Swift Package Manager dependency (eg. AlamofireDynamic)
def spm_dependency(spec, url:, requirement:, products:)
SPM.dependency(spec, url: url, requirement: requirement, products: products)
end

# It returns the default flags.
# deprecated.
def get_default_flags()
Expand Down Expand Up @@ -294,6 +307,7 @@ def react_native_post_install(
ReactNativePodsUtils.updateOSDeploymentTarget(installer)
ReactNativePodsUtils.set_dynamic_frameworks_flags(installer)
ReactNativePodsUtils.add_ndebug_flag_to_pods_in_release(installer)
SPM.apply_on_post_install(installer)

if privacy_file_aggregation_enabled
PrivacyManifestUtils.add_aggregated_privacy_manifest(installer)
Expand Down