react-native 0.87.0-rc.1 → 0.87.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Libraries/Core/InitializeCore.js +8 -1
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/ReactNative/AppRegistry.flow.js +1 -0
- package/Libraries/ReactNative/AppRegistryImpl.js +2 -3
- package/React/Base/RCTVersion.m +1 -1
- package/React/I18n/RCTLocalizedString.mm +38 -2
- package/React-Core-prebuilt.podspec +45 -17
- package/React-Core.podspec +9 -2
- package/ReactAndroid/external-artifacts/build.gradle.kts +49 -0
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/SynchronousMountItem.kt +8 -2
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
- package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
- package/package.json +10 -8
- package/react-native.config.js +81 -0
- package/scripts/cocoapods/fabric.rb +1 -1
- package/scripts/cocoapods/rncore.rb +35 -78
- package/scripts/cocoapods/rncore_facades.rb +232 -0
- package/scripts/cocoapods/rndependencies.rb +64 -3
- package/scripts/cocoapods/rndeps_facades.rb +193 -0
- package/scripts/cocoapods/spm.rb +78 -11
- package/scripts/codegen/templates/Package.swift.spm-template +97 -0
- package/scripts/react-native-xcode.sh +20 -0
- package/scripts/react_native_pods.rb +65 -16
- package/scripts/replace-rncore-version.js +53 -6
- package/scripts/setup-apple-spm.js +1165 -0
- package/scripts/spm/__doc__/rfc-spm-xcframework.md +707 -0
- package/scripts/spm/__doc__/spm-autolinking-plugins.md +244 -0
- package/scripts/spm/__doc__/spm-header-paths-contract.md +97 -0
- package/scripts/spm/__doc__/spm-plugins-assessment.md +128 -0
- package/scripts/spm/__doc__/spm-scripts.md +451 -0
- package/scripts/spm/autolinking-plugins.js +331 -0
- package/scripts/spm/download-spm-artifacts.js +1409 -0
- package/scripts/spm/expand-spm-dependencies.js +216 -0
- package/scripts/spm/flavored-frameworks.js +1008 -0
- package/scripts/spm/generate-spm-autolinking-config.js +161 -0
- package/scripts/spm/generate-spm-autolinking.js +1888 -0
- package/scripts/spm/generate-spm-package.js +302 -0
- package/scripts/spm/generate-spm-xcodeproj.js +2224 -0
- package/scripts/spm/read-podspec.js +695 -0
- package/scripts/spm/scaffold-package-swift.js +1206 -0
- package/scripts/spm/spm-pbxproj.js +654 -0
- package/scripts/spm/spm-types.js +517 -0
- package/scripts/spm/spm-utils.js +645 -0
- package/scripts/spm/sync-spm-autolinking.js +160 -0
- package/sdks/.hermesv1version +1 -0
- package/sdks/hermes-engine/utils/replace_hermes_version.js +18 -4
- package/sdks/hermes-engine/version.properties +1 -1
- package/third-party-podspecs/ReactNativeDependencies.podspec +2 -2
- package/types_generated/Libraries/ReactNative/AppRegistry.flow.d.ts +2 -2
- package/Libraries/Utilities/SceneTracker.js +0 -42
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
#
|
|
3
|
+
# This source code is licensed under the MIT license found in the
|
|
4
|
+
# LICENSE file in the root directory of this source tree.
|
|
5
|
+
|
|
6
|
+
require 'json'
|
|
7
|
+
require 'fileutils'
|
|
8
|
+
# Self-contained against require ordering: this module reads
|
|
9
|
+
# Helpers::Constants.socket_rocket_config. react_native_pods.rb normally loads
|
|
10
|
+
# helpers.rb first, but requiring it here (idempotent) removes that implicit
|
|
11
|
+
# dependency. The defined? guard at the use site stays as a backstop.
|
|
12
|
+
require_relative './helpers'
|
|
13
|
+
|
|
14
|
+
# Dependency-only facade podspecs for the third-party deps in prebuilt-deps
|
|
15
|
+
# mode (deps-side analogue of RNCoreFacades). Design + rationale:
|
|
16
|
+
# scripts/cocoapods/__docs__/prebuilt-deps.md
|
|
17
|
+
module RNDepsFacades
|
|
18
|
+
# The name of the umbrella prebuilt-deps pod every facade depends on. Its pod
|
|
19
|
+
# self-serves the third-party headers + carries the binary (see
|
|
20
|
+
# rndependencies.rb, ReactNativeDependencies.podspec).
|
|
21
|
+
DEPS_POD = "ReactNativeDependencies"
|
|
22
|
+
|
|
23
|
+
# pod name => podspec path (relative to the react-native package root), or
|
|
24
|
+
# :synthesized for a pod with no local podspec (SocketRocket). Version +
|
|
25
|
+
# subspecs + default_subspecs are DERIVED from the real podspec where one
|
|
26
|
+
# exists; synthesized entries derive their version from a constant.
|
|
27
|
+
FACADE_PODS = {
|
|
28
|
+
"RCT-Folly" => "third-party-podspecs/RCT-Folly.podspec",
|
|
29
|
+
"glog" => "third-party-podspecs/glog.podspec",
|
|
30
|
+
"boost" => "third-party-podspecs/boost.podspec",
|
|
31
|
+
"DoubleConversion" => "third-party-podspecs/DoubleConversion.podspec",
|
|
32
|
+
"fmt" => "third-party-podspecs/fmt.podspec",
|
|
33
|
+
"fast_float" => "third-party-podspecs/fast_float.podspec",
|
|
34
|
+
"SocketRocket" => :synthesized,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Sub-directory (relative to the install root) that holds the generated
|
|
38
|
+
# deps facades. Kept separate from RNCoreFacades' `build/rncore-facades` so
|
|
39
|
+
# the two families never collide.
|
|
40
|
+
FACADE_RELDIR = File.join("build", "rndeps-facades")
|
|
41
|
+
|
|
42
|
+
# Generates the facade podspecs and returns the base directory holding them.
|
|
43
|
+
# Each facade gets its OWN sub-directory containing a single
|
|
44
|
+
# `<Name>.podspec.json`, so it can be installed as a LOCAL pod via
|
|
45
|
+
# `:path => <dir>` (PathSource uses the spec in place and never downloads
|
|
46
|
+
# `spec.source`). Idempotent; safe to call once per `pod install`.
|
|
47
|
+
#
|
|
48
|
+
# `react_native_path` locates the real third-party podspecs we mirror.
|
|
49
|
+
# version + subspecs + default_subspecs are DERIVED from the real spec (or,
|
|
50
|
+
# for SocketRocket, synthesized from the socket_rocket_config version) so the
|
|
51
|
+
# facade matches the source pod's spec/subspec SHAPE. It is not fully
|
|
52
|
+
# graph-equivalent: every derived subspec depends only on
|
|
53
|
+
# ReactNativeDependencies, so intra-pod subspec deps (e.g. RCT-Folly/Fabric
|
|
54
|
+
# -> RCT-Folly/Default) are not reproduced — harmless here because the deps
|
|
55
|
+
# are all declared explicitly in react_native_pods.rb. NO source_files and
|
|
56
|
+
# NO headers are emitted — the ReactNativeDependencies pod supplies both. A
|
|
57
|
+
# facaded pod whose real podspec can't be read is a hard error (see
|
|
58
|
+
# load_real_spec) — silently shipping an empty facade would hide drift.
|
|
59
|
+
def self.generate(react_native_path, install_root, ios_version)
|
|
60
|
+
abs_base = File.join(install_root.to_s, FACADE_RELDIR)
|
|
61
|
+
FileUtils.mkdir_p(abs_base)
|
|
62
|
+
FACADE_PODS.each do |name, podspec_rel_path|
|
|
63
|
+
dir = File.join(abs_base, name)
|
|
64
|
+
FileUtils.mkdir_p(dir)
|
|
65
|
+
|
|
66
|
+
if podspec_rel_path == :synthesized
|
|
67
|
+
spec = synthesized_spec(name, ios_version)
|
|
68
|
+
else
|
|
69
|
+
podspec_path = File.join(react_native_path.to_s, podspec_rel_path)
|
|
70
|
+
real = load_real_spec(podspec_path, name)
|
|
71
|
+
spec = derived_spec(name, real, ios_version)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
File.write(File.join(dir, "#{name}.podspec.json"), JSON.pretty_generate(spec))
|
|
75
|
+
end
|
|
76
|
+
abs_base
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Facade dir for `<name>`, RELATIVE to the install root — pass to `pod :path =>`.
|
|
80
|
+
# Relative (not absolute) so the path CocoaPods records in Podfile.lock is
|
|
81
|
+
# portable rather than machine-specific.
|
|
82
|
+
def self.facade_path(name)
|
|
83
|
+
File.join(FACADE_RELDIR, name)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Base spec skeleton shared by derived + synthesized facades: dependency-only,
|
|
87
|
+
# no source_files, no headers. Depends solely on ReactNativeDependencies.
|
|
88
|
+
def self.base_spec(name, version, ios_version)
|
|
89
|
+
{
|
|
90
|
+
"name" => name,
|
|
91
|
+
"version" => version,
|
|
92
|
+
"summary" => "Prebuilt facade for #{name} (code + headers live in #{DEPS_POD}).",
|
|
93
|
+
"homepage" => "https://reactnative.dev/",
|
|
94
|
+
"license" => "MIT",
|
|
95
|
+
"authors" => "Meta Platforms, Inc. and its affiliates",
|
|
96
|
+
"platforms" => { "ios" => ios_version },
|
|
97
|
+
# Required podspec attribute, but never fetched: installed as a LOCAL
|
|
98
|
+
# pod (`:path => <dir>`), which uses this spec in place and ships no
|
|
99
|
+
# source_files. Placeholder only.
|
|
100
|
+
"source" => { "git" => "https://github.com/facebook/react-native.git" },
|
|
101
|
+
"dependencies" => { DEPS_POD => [] },
|
|
102
|
+
}
|
|
103
|
+
end
|
|
104
|
+
private_class_method :base_spec
|
|
105
|
+
|
|
106
|
+
# Facade derived from a real third-party podspec: version + subspecs +
|
|
107
|
+
# default_subspecs mirror the real spec so a bare `pod '<Name>'` and any
|
|
108
|
+
# `pod '<Name>/<Subspec>'` resolve to the SAME graph (e.g. RCT-Folly's
|
|
109
|
+
# bare + /Default + /Fabric). Each subspec is also dependency-only and
|
|
110
|
+
# depends on ReactNativeDependencies.
|
|
111
|
+
#
|
|
112
|
+
# NOTE: resources (e.g. RCT-Folly's PrivacyInfo.xcprivacy) are intentionally
|
|
113
|
+
# NOT carried. In prebuilt-deps mode the third-party code — and its privacy
|
|
114
|
+
# manifest — is embedded in the ReactNativeDependencies artifact; the facade
|
|
115
|
+
# only needs to declare the dependency (see the design note in the PR).
|
|
116
|
+
def self.derived_spec(name, real, ios_version)
|
|
117
|
+
spec = base_spec(name, real.version.to_s, ios_version)
|
|
118
|
+
|
|
119
|
+
defaults = Array(real.default_subspecs)
|
|
120
|
+
spec["default_subspecs"] = defaults unless defaults.empty?
|
|
121
|
+
|
|
122
|
+
subspecs = derive_subspecs(real)
|
|
123
|
+
unless subspecs.empty?
|
|
124
|
+
spec["subspecs"] = subspecs.map do |ss|
|
|
125
|
+
{ "name" => ss, "dependencies" => { DEPS_POD => [] } }
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
spec
|
|
130
|
+
end
|
|
131
|
+
private_class_method :derived_spec
|
|
132
|
+
|
|
133
|
+
# Facade synthesized for a pod with NO local podspec (SocketRocket, a trunk
|
|
134
|
+
# pod). Version comes from Helpers::Constants::socket_rocket_config; no
|
|
135
|
+
# subspecs. A missing/blank constant is a hard error rather than a silent
|
|
136
|
+
# versionless facade — a bare `pod 'SocketRocket'` in the source path is
|
|
137
|
+
# `"~> #{socket_rocket_config[:version]}"`, so the facade MUST carry a version
|
|
138
|
+
# that satisfies that constraint.
|
|
139
|
+
def self.synthesized_spec(name, ios_version)
|
|
140
|
+
version = synthesized_version(name)
|
|
141
|
+
base_spec(name, version, ios_version)
|
|
142
|
+
end
|
|
143
|
+
private_class_method :synthesized_spec
|
|
144
|
+
|
|
145
|
+
# Resolves the synthesized version for a no-podspec facade. Fail-closed on a
|
|
146
|
+
# missing constant/version. Only SocketRocket is synthesized today.
|
|
147
|
+
def self.synthesized_version(name)
|
|
148
|
+
case name
|
|
149
|
+
when "SocketRocket"
|
|
150
|
+
unless defined?(Helpers::Constants) && Helpers::Constants.respond_to?(:socket_rocket_config)
|
|
151
|
+
raise "[RNDepsFacades] Cannot synthesize facade for '#{name}': " \
|
|
152
|
+
"Helpers::Constants.socket_rocket_config is unavailable."
|
|
153
|
+
end
|
|
154
|
+
version = Helpers::Constants.socket_rocket_config[:version]
|
|
155
|
+
if version.nil? || version.to_s.strip.empty?
|
|
156
|
+
raise "[RNDepsFacades] Cannot synthesize facade for '#{name}': " \
|
|
157
|
+
"socket_rocket_config[:version] is missing or empty."
|
|
158
|
+
end
|
|
159
|
+
version.to_s
|
|
160
|
+
else
|
|
161
|
+
raise "[RNDepsFacades] No synthesized version rule for facaded pod '#{name}'. " \
|
|
162
|
+
"Add one to synthesized_version or give it a real podspec in FACADE_PODS."
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
private_class_method :synthesized_version
|
|
166
|
+
|
|
167
|
+
# Loads the real podspec so we can mirror its structure. A facaded pod with a
|
|
168
|
+
# declared podspec path MUST have a readable real podspec — if it's missing or
|
|
169
|
+
# unparseable we raise rather than ship an empty facade (which would silently
|
|
170
|
+
# drop subspecs / the version, the very drift this mechanism prevents).
|
|
171
|
+
def self.load_real_spec(path, name)
|
|
172
|
+
unless File.exist?(path)
|
|
173
|
+
raise "[RNDepsFacades] Real podspec for facaded pod '#{name}' not found at #{path}. " \
|
|
174
|
+
"Update FACADE_PODS in rndeps_facades.rb if the podspec moved."
|
|
175
|
+
end
|
|
176
|
+
begin
|
|
177
|
+
Pod::Specification.from_file(path)
|
|
178
|
+
rescue => e
|
|
179
|
+
raise "[RNDepsFacades] Failed to read real podspec for facaded pod '#{name}' at #{path}: #{e.message}"
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
private_class_method :load_real_spec
|
|
183
|
+
|
|
184
|
+
# Library (non-test, non-app) subspec names of the real spec, so third-party
|
|
185
|
+
# libs depending on `<pod>/<subspec>` (e.g. `RCT-Folly/Fabric`) keep
|
|
186
|
+
# resolving. Derived, never hand-listed.
|
|
187
|
+
def self.derive_subspecs(real)
|
|
188
|
+
real.subspecs
|
|
189
|
+
.reject { |ss| ss.test_specification? || (ss.respond_to?(:app_specification?) && ss.app_specification?) }
|
|
190
|
+
.map(&:base_name)
|
|
191
|
+
end
|
|
192
|
+
private_class_method :derive_subspecs
|
|
193
|
+
end
|
package/scripts/cocoapods/spm.rb
CHANGED
|
@@ -19,28 +19,46 @@ class SPMManager
|
|
|
19
19
|
log 'Cleaning old SPM dependencies from Pods project'
|
|
20
20
|
clean_spm_dependencies_from_target(project, @dependencies_by_pod)
|
|
21
21
|
log 'Adding SPM dependencies to Pods project'
|
|
22
|
+
flattened_pod_names = []
|
|
22
23
|
@dependencies_by_pod.each do |pod_name, dependencies|
|
|
24
|
+
target = project.targets.find { |t| t.name == pod_name}
|
|
23
25
|
dependencies.each do |spm_spec|
|
|
24
26
|
log "Adding SPM dependency on product #{spm_spec[:products]}"
|
|
25
27
|
add_spm_to_target(
|
|
26
28
|
project,
|
|
27
|
-
|
|
29
|
+
target,
|
|
28
30
|
spm_spec[:url],
|
|
29
31
|
spm_spec[:requirement],
|
|
30
32
|
spm_spec[:products]
|
|
31
33
|
)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
if target.product_type == 'com.apple.product-type.library.static'
|
|
35
|
+
# Xcode emits a package C-target's module map both into the shared
|
|
36
|
+
# products dir and into this pod's CONFIGURATION_BUILD_DIR, and both
|
|
37
|
+
# copies are unavoidably visible (the package swiftmodule serializes
|
|
38
|
+
# the products-root path) — clang hard-errors with "redefinition of
|
|
39
|
+
# module" on Xcode 26.3. Building the pod straight into the products
|
|
40
|
+
# root makes both paths the same file, and puts the package
|
|
41
|
+
# swiftmodule on the pod's default search path.
|
|
42
|
+
log " Building #{pod_name} into the shared products dir to avoid duplicate module maps"
|
|
43
|
+
target.build_configurations.each do |config|
|
|
44
|
+
target.build_settings(config.name)['CONFIGURATION_BUILD_DIR'] = '${PODS_CONFIGURATION_BUILD_DIR}'
|
|
45
|
+
end
|
|
46
|
+
flattened_pod_names << pod_name unless flattened_pod_names.include?(pod_name)
|
|
47
|
+
else
|
|
48
|
+
log " Adding workaround for Swift package not found issue"
|
|
49
|
+
target.build_configurations.each do |config|
|
|
50
|
+
target.build_settings(config.name)['SWIFT_INCLUDE_PATHS'] ||= ['$(inherited)']
|
|
51
|
+
search_path = '${SYMROOT}/${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}/'
|
|
52
|
+
unless target.build_settings(config.name)['SWIFT_INCLUDE_PATHS'].include?(search_path)
|
|
53
|
+
target.build_settings(config.name)['SWIFT_INCLUDE_PATHS'].push(search_path)
|
|
54
|
+
end
|
|
39
55
|
end
|
|
40
56
|
end
|
|
41
57
|
end
|
|
42
58
|
end
|
|
43
59
|
|
|
60
|
+
rewrite_aggregate_modulemap_references(installer, flattened_pod_names) unless flattened_pod_names.empty?
|
|
61
|
+
|
|
44
62
|
unless @dependencies_by_pod.empty?
|
|
45
63
|
log_warning "If you're using Xcode 15 or earlier you might need to close and reopen the Xcode workspace"
|
|
46
64
|
unless ENV["USE_FRAMEWORKS"] == "dynamic"
|
|
@@ -53,6 +71,55 @@ class SPMManager
|
|
|
53
71
|
|
|
54
72
|
private
|
|
55
73
|
|
|
74
|
+
# Flattening a pod's build dir moves its generated modulemap from
|
|
75
|
+
# "<Pod>/<Pod>.modulemap" to "<Pod>.modulemap"; the aggregate xcconfigs
|
|
76
|
+
# reference the old path via -fmodule-map-file. Must mutate the in-memory
|
|
77
|
+
# Config attributes — later post_install steps (NewArchitectureHelper) re-save
|
|
78
|
+
# the same Config objects and would clobber a plain file edit.
|
|
79
|
+
def rewrite_aggregate_modulemap_references(installer, pod_names)
|
|
80
|
+
installer.aggregate_targets.each do |aggregate_target|
|
|
81
|
+
aggregate_target.xcconfigs.each do |config_name, config_file|
|
|
82
|
+
%w[OTHER_CFLAGS OTHER_SWIFT_FLAGS].each do |key|
|
|
83
|
+
value = config_file.attributes[key]
|
|
84
|
+
next unless value
|
|
85
|
+
|
|
86
|
+
updated_value = pod_names.reduce(value) do |acc, pod_name|
|
|
87
|
+
acc.gsub(
|
|
88
|
+
"${PODS_CONFIGURATION_BUILD_DIR}/#{pod_name}/#{pod_name}.modulemap",
|
|
89
|
+
"${PODS_CONFIGURATION_BUILD_DIR}/#{pod_name}.modulemap"
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
config_file.attributes[key] = updated_value if updated_value != value
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
config_file.save_as(aggregate_target.xcconfig_path(config_name))
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Creates a new object in the project with a UUID guaranteed not to collide
|
|
101
|
+
# with any UUID already present in the project.
|
|
102
|
+
#
|
|
103
|
+
# `Pod::Project` overrides `generate_available_uuid_list` with a fast,
|
|
104
|
+
# counter-based scheme (`<sha prefix><counter>0`) that deliberately skips
|
|
105
|
+
# collision checks, on the assumption that the whole Pods project is generated
|
|
106
|
+
# in a single pass. That assumption does not hold here: we run in a
|
|
107
|
+
# `post_install` hook, and the generator's counter can be out of sync with the
|
|
108
|
+
# UUIDs already assigned to existing objects (e.g. when the project has been
|
|
109
|
+
# reloaded from disk during an incremental install, the counter restarts at 0
|
|
110
|
+
# while the root object still occupies `<prefix>00000000`). Using `project.new`
|
|
111
|
+
# directly can therefore hand back a UUID that is already in use and overwrite
|
|
112
|
+
# an existing object (notably the root `PBXProject`), producing a Pods project
|
|
113
|
+
# Xcode refuses to load. We keep the deterministic scheme but probe forward
|
|
114
|
+
# until we find a UUID that is actually free.
|
|
115
|
+
def new_object(project, klass)
|
|
116
|
+
uuid = project.generate_uuid
|
|
117
|
+
uuid = project.generate_uuid while project.objects_by_uuid.key?(uuid)
|
|
118
|
+
object = klass.new(project, uuid)
|
|
119
|
+
object.initialize_defaults
|
|
120
|
+
object
|
|
121
|
+
end
|
|
122
|
+
|
|
56
123
|
def log(msg)
|
|
57
124
|
::Pod::UI.puts "[SPM] #{msg}"
|
|
58
125
|
end
|
|
@@ -76,7 +143,7 @@ class SPMManager
|
|
|
76
143
|
pkg_class = Xcodeproj::Project::Object::XCLocalSwiftPackageReference
|
|
77
144
|
pkg = project.root_object.package_references.find { |p| p.class == pkg_class && p.relative_path == url }
|
|
78
145
|
if !pkg
|
|
79
|
-
pkg = project
|
|
146
|
+
pkg = new_object(project, pkg_class)
|
|
80
147
|
pkg.relative_path = url
|
|
81
148
|
log(" Adding local package to workspace: #{pkg.inspect}")
|
|
82
149
|
project.root_object.package_references << pkg
|
|
@@ -85,7 +152,7 @@ class SPMManager
|
|
|
85
152
|
pkg_class = Xcodeproj::Project::Object::XCRemoteSwiftPackageReference
|
|
86
153
|
pkg = project.root_object.package_references.find { |p| p.class == pkg_class && p.repositoryURL == url }
|
|
87
154
|
if !pkg
|
|
88
|
-
pkg = project
|
|
155
|
+
pkg = new_object(project, pkg_class)
|
|
89
156
|
pkg.repositoryURL = url
|
|
90
157
|
pkg.requirement = requirement
|
|
91
158
|
log(" Adding remote package to workspace: #{pkg.inspect}")
|
|
@@ -101,7 +168,7 @@ class SPMManager
|
|
|
101
168
|
next if ref
|
|
102
169
|
|
|
103
170
|
log(" Adding product dependency #{product_name} to #{target.name}")
|
|
104
|
-
ref = project
|
|
171
|
+
ref = new_object(project, ref_class)
|
|
105
172
|
ref.package = pkg
|
|
106
173
|
ref.product_name = product_name
|
|
107
174
|
target.package_product_dependencies << ref
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// swift-tools-version: 6.0
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// AUTO-GENERATED by scripts/setup-apple-spm.js – do not edit manually.
|
|
10
|
+
// This SPM-specific template replaces the CocoaPods codegen template
|
|
11
|
+
// with xcframework configuration built in.
|
|
12
|
+
|
|
13
|
+
import PackageDescription
|
|
14
|
+
|
|
15
|
+
// React headers need NO search paths: the React module comes from the
|
|
16
|
+
// invariant ReactHeaders Clang target,
|
|
17
|
+
// every other RN namespace from the ReactNativeHeaders binaryTarget
|
|
18
|
+
// (pure-RN), the third-party deps namespaces (folly/glog/boost/...) from the
|
|
19
|
+
// ReactNativeDependenciesHeaders sidecar, and the per-app generated headers
|
|
20
|
+
// from the ReactAppHeaders target below — all auto-served by SPM through
|
|
21
|
+
// product/target dependencies.
|
|
22
|
+
let headersDep: [Target.Dependency] = [
|
|
23
|
+
.product(name: "ReactHeaders", package: "ReactNative"),
|
|
24
|
+
.product(name: "ReactNativeHeaders", package: "ReactNative"),
|
|
25
|
+
.product(name: "ReactNativeDependenciesHeaders", package: "ReactNative"),
|
|
26
|
+
"ReactAppHeaders",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
let package = Package(
|
|
30
|
+
name: "React-GeneratedCode",
|
|
31
|
+
platforms: [.iOS(.v15), .macCatalyst(SupportedPlatform.MacCatalystVersion.v13)],
|
|
32
|
+
products: [
|
|
33
|
+
.library(
|
|
34
|
+
name: "ReactCodegen",
|
|
35
|
+
targets: ["ReactCodegen"]),
|
|
36
|
+
.library(
|
|
37
|
+
name: "ReactAppDependencyProvider",
|
|
38
|
+
targets: ["ReactAppDependencyProvider"]),
|
|
39
|
+
.library(
|
|
40
|
+
name: "ReactAppHeaders",
|
|
41
|
+
targets: ["ReactAppHeaders"]),
|
|
42
|
+
],
|
|
43
|
+
dependencies: [
|
|
44
|
+
.package(name: "ReactNative", path: "../../xcframeworks"),
|
|
45
|
+
],
|
|
46
|
+
targets: [
|
|
47
|
+
.target(
|
|
48
|
+
name: "ReactCodegen",
|
|
49
|
+
dependencies: headersDep,
|
|
50
|
+
path: "ReactCodegen",
|
|
51
|
+
exclude: ["ReactCodegen.podspec"],
|
|
52
|
+
publicHeadersPath: ".",
|
|
53
|
+
cSettings: [.headerSearchPath("headers")],
|
|
54
|
+
// DEBUG/NDEBUG match the prebuilt React.framework's config-gated C++
|
|
55
|
+
// ABI: NDEBUG (Release) strips DebugStringConvertible's vtable and
|
|
56
|
+
// shifts the ShadowNode layout that codegen'd Props inherit, so this
|
|
57
|
+
// target must compile with the same NDEBUG state or the Release link
|
|
58
|
+
// fails (undefined "vtable for DebugStringConvertible"). Mirrors
|
|
59
|
+
// packages/react-native/Package.swift.
|
|
60
|
+
cxxSettings: [
|
|
61
|
+
.headerSearchPath("headers"),
|
|
62
|
+
.define("DEBUG", .when(configuration: .debug)),
|
|
63
|
+
.define("NDEBUG", .when(configuration: .release)),
|
|
64
|
+
],
|
|
65
|
+
linkerSettings: [
|
|
66
|
+
.linkedFramework("Foundation")
|
|
67
|
+
]
|
|
68
|
+
),
|
|
69
|
+
.target(
|
|
70
|
+
name: "ReactAppDependencyProvider",
|
|
71
|
+
dependencies: ["ReactCodegen"] + headersDep,
|
|
72
|
+
path: "ReactAppDependencyProvider",
|
|
73
|
+
exclude: ["ReactAppDependencyProvider.podspec"],
|
|
74
|
+
publicHeadersPath: ".",
|
|
75
|
+
cSettings: [.headerSearchPath(".."), .headerSearchPath("headers")],
|
|
76
|
+
cxxSettings: [
|
|
77
|
+
.headerSearchPath(".."),
|
|
78
|
+
.headerSearchPath("headers"),
|
|
79
|
+
// Match the prebuilt React.framework NDEBUG-gated C++ ABI (see above).
|
|
80
|
+
.define("DEBUG", .when(configuration: .debug)),
|
|
81
|
+
.define("NDEBUG", .when(configuration: .release)),
|
|
82
|
+
],
|
|
83
|
+
linkerSettings: [
|
|
84
|
+
.linkedFramework("Foundation")
|
|
85
|
+
]
|
|
86
|
+
),
|
|
87
|
+
// The per-app generated-headers farm (built by spm sync), vended as a
|
|
88
|
+
// normal SPM headers target.
|
|
89
|
+
.target(
|
|
90
|
+
name: "ReactAppHeaders",
|
|
91
|
+
path: "ReactAppHeaders",
|
|
92
|
+
publicHeadersPath: "."
|
|
93
|
+
),
|
|
94
|
+
],
|
|
95
|
+
// React Native headers require C++20 (concepts, std::optional, etc.)
|
|
96
|
+
cxxLanguageStandard: .cxx20
|
|
97
|
+
)
|
|
@@ -80,6 +80,26 @@ source "$REACT_NATIVE_DIR/scripts/node-binary.sh"
|
|
|
80
80
|
HERMES_ENGINE_PATH="$PODS_ROOT/hermes-engine"
|
|
81
81
|
[ -z "$HERMES_CLI_PATH" ] && HERMES_CLI_PATH="$HERMES_ENGINE_PATH/destroot/bin/hermesc"
|
|
82
82
|
|
|
83
|
+
# SwiftPM consumers have no Pods directory to provide hermesc. When there is
|
|
84
|
+
# no Pods installation at all and the current HERMES_CLI_PATH does not exist
|
|
85
|
+
# (unset, or an injector-baked path gone stale after a package-store move),
|
|
86
|
+
# resolve the hermes-compiler npm package THROUGH react-native's own dependency
|
|
87
|
+
# graph — react-native pins the hermes-compiler version, so the compiler's
|
|
88
|
+
# bytecode version always matches the prebuilt hermes VM artifacts (a
|
|
89
|
+
# mismatched pair crashes at launch with "Wrong bytecode version").
|
|
90
|
+
# STRICTLY SwiftPM-scoped: in a CocoaPods build the hermes-engine pod owns both
|
|
91
|
+
# the VM and hermesc, and its hermes train may legitimately differ from the npm
|
|
92
|
+
# hermes-compiler — falling back there would compile bundles the podded VM
|
|
93
|
+
# rejects.
|
|
94
|
+
if [[ ( -z "$PODS_ROOT" || ! -d "$PODS_ROOT" ) && ! -f "$HERMES_CLI_PATH" ]]; then
|
|
95
|
+
NODE_HERMESC=$(RN_DIR="$REACT_NATIVE_DIR" "$NODE_BINARY" --print \
|
|
96
|
+
"require('path').join(require('path').dirname(require.resolve('hermes-compiler/package.json', {paths: [process.env.RN_DIR]})), 'hermesc', 'osx-bin', 'hermesc')" \
|
|
97
|
+
2>/dev/null || true)
|
|
98
|
+
if [[ -n "$NODE_HERMESC" && -f "$NODE_HERMESC" ]]; then
|
|
99
|
+
HERMES_CLI_PATH="$NODE_HERMESC"
|
|
100
|
+
fi
|
|
101
|
+
fi
|
|
102
|
+
|
|
83
103
|
# If hermesc is not available and USE_HERMES is not set to false, show error.
|
|
84
104
|
if [[ $USE_HERMES != false && -f "$HERMES_ENGINE_PATH" && ! -f "$HERMES_CLI_PATH" ]]; then
|
|
85
105
|
echo "error: Hermes is enabled but the hermesc binary could not be found at ${HERMES_CLI_PATH}." \
|
|
@@ -21,6 +21,8 @@ require_relative './cocoapods/helpers.rb'
|
|
|
21
21
|
require_relative './cocoapods/privacy_manifest_utils.rb'
|
|
22
22
|
require_relative './cocoapods/spm.rb'
|
|
23
23
|
require_relative './cocoapods/rncore.rb'
|
|
24
|
+
require_relative './cocoapods/rncore_facades.rb'
|
|
25
|
+
require_relative './cocoapods/rndeps_facades.rb'
|
|
24
26
|
# Importing to expose use_native_modules!
|
|
25
27
|
require_relative './cocoapods/autolinking.rb'
|
|
26
28
|
|
|
@@ -52,6 +54,28 @@ def prepare_react_native_project!
|
|
|
52
54
|
ReactNativePodsUtils.create_xcode_env_if_missing
|
|
53
55
|
end
|
|
54
56
|
|
|
57
|
+
# Declares a React core pod, choosing source vs prebuilt facade. In prebuilt
|
|
58
|
+
# mode, pods in the RNCoreFacades manifest are installed as dependency-only
|
|
59
|
+
# facades (no source/headers) so they can't shadow the prebuilt artifact; their
|
|
60
|
+
# code + headers come from React-Core-prebuilt. Everything else (and the whole
|
|
61
|
+
# source build) is unaffected. See cocoapods/rncore_facades.rb.
|
|
62
|
+
def rncore_pod(name, **opts)
|
|
63
|
+
base = name.split('/').first
|
|
64
|
+
if !ReactNativeCoreUtils.build_rncore_from_source() && RNCoreFacades.facade?(base)
|
|
65
|
+
# Install as a LOCAL pod (`:path`) from the generated facade directory, so
|
|
66
|
+
# CocoaPods never fetches the placeholder git source (a `:podspec` external
|
|
67
|
+
# source would). Both the pod and any subspec declaration point at the SAME
|
|
68
|
+
# directory, so CocoaPods sees one consistent source for the name (a bare
|
|
69
|
+
# subspec declaration would otherwise default to the spec repo and conflict).
|
|
70
|
+
# Preserve the caller's options (e.g. :modular_headers) but replace :path with
|
|
71
|
+
# the facade directory.
|
|
72
|
+
facade_opts = opts.reject { |k, _| k == :path }
|
|
73
|
+
pod name, **facade_opts, :path => RNCoreFacades.facade_path(base)
|
|
74
|
+
else
|
|
75
|
+
pod name, **opts
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
55
79
|
# Function that setup all the react native dependencies
|
|
56
80
|
#
|
|
57
81
|
# Parameters
|
|
@@ -123,19 +147,25 @@ def use_react_native! (
|
|
|
123
147
|
# Update ReactNativeCoreUtils so that we can easily switch between source and prebuilt
|
|
124
148
|
ReactNativeCoreUtils.setup_rncore(prefix, react_native_version)
|
|
125
149
|
|
|
150
|
+
# In prebuilt mode, generate the facade podspecs the core pods are installed as
|
|
151
|
+
# (instead of their source podspecs) so they don't ship shadowing headers.
|
|
152
|
+
unless ReactNativeCoreUtils.build_rncore_from_source()
|
|
153
|
+
RNCoreFacades.generate(react_native_path, Pod::Config.instance.installation_root, react_native_version, min_ios_version_supported)
|
|
154
|
+
end
|
|
155
|
+
|
|
126
156
|
Pod::UI.puts "Configuring the target with the New Architecture\n"
|
|
127
157
|
|
|
128
158
|
# The Pods which should be included in all projects
|
|
129
|
-
|
|
130
|
-
|
|
159
|
+
rncore_pod 'FBLazyVector', :path => "#{prefix}/Libraries/FBLazyVector"
|
|
160
|
+
rncore_pod 'RCTRequired', :path => "#{prefix}/Libraries/Required"
|
|
131
161
|
pod 'RCTTypeSafety', :path => "#{prefix}/Libraries/TypeSafety", :modular_headers => true
|
|
132
162
|
pod 'React', :path => "#{prefix}/"
|
|
133
163
|
if !ReactNativeCoreUtils.build_rncore_from_source()
|
|
134
164
|
pod 'React-Core-prebuilt', :podspec => "#{prefix}/React-Core-prebuilt.podspec", :modular_headers => true
|
|
135
165
|
end
|
|
136
|
-
|
|
166
|
+
rncore_pod 'React-Core', :path => "#{prefix}/"
|
|
137
167
|
pod 'React-CoreModules', :path => "#{prefix}/React/CoreModules"
|
|
138
|
-
|
|
168
|
+
rncore_pod 'React-RCTRuntime', :path => "#{prefix}/React/Runtime"
|
|
139
169
|
pod 'React-RCTAppDelegate', :path => "#{prefix}/Libraries/AppDelegate"
|
|
140
170
|
pod 'React-RCTActionSheet', :path => "#{prefix}/Libraries/ActionSheetIOS"
|
|
141
171
|
pod 'React-RCTAnimation', :path => "#{prefix}/Libraries/NativeAnimation"
|
|
@@ -146,7 +176,7 @@ def use_react_native! (
|
|
|
146
176
|
pod 'React-RCTSettings', :path => "#{prefix}/Libraries/Settings"
|
|
147
177
|
pod 'React-RCTText', :path => "#{prefix}/Libraries/Text"
|
|
148
178
|
pod 'React-RCTVibration', :path => "#{prefix}/Libraries/Vibration"
|
|
149
|
-
|
|
179
|
+
rncore_pod 'React-Core/RCTWebSocket', :path => "#{prefix}/"
|
|
150
180
|
pod 'React-cxxreact', :path => "#{prefix}/ReactCommon/cxxreact"
|
|
151
181
|
pod 'React-cxxstableapi', :path => "#{prefix}/ReactCommon/react/cxxstableapi"
|
|
152
182
|
pod 'React-debug', :path => "#{prefix}/ReactCommon/react/debug"
|
|
@@ -164,7 +194,7 @@ def use_react_native! (
|
|
|
164
194
|
pod 'React-Mapbuffer', :path => "#{prefix}/ReactCommon"
|
|
165
195
|
pod 'React-bridging', :path => "#{prefix}/ReactCommon/react/bridging", :modular_headers => true
|
|
166
196
|
pod 'React-jserrorhandler', :path => "#{prefix}/ReactCommon/jserrorhandler"
|
|
167
|
-
|
|
197
|
+
rncore_pod 'RCTDeprecation', :path => "#{prefix}/ReactApple/Libraries/RCTFoundation/RCTDeprecation"
|
|
168
198
|
pod 'React-RCTFBReactNativeSpec', :path => "#{prefix}/React"
|
|
169
199
|
pod 'React-jsi', :path => "#{prefix}/ReactCommon/jsi"
|
|
170
200
|
pod 'RCTSwiftUI', :path => "#{prefix}/ReactApple/RCTSwiftUI"
|
|
@@ -197,7 +227,7 @@ def use_react_native! (
|
|
|
197
227
|
pod 'React-logger', :path => "#{prefix}/ReactCommon/logger"
|
|
198
228
|
pod 'ReactCommon/turbomodule/core', :path => "#{prefix}/ReactCommon", :modular_headers => true
|
|
199
229
|
pod 'React-NativeModulesApple', :path => "#{prefix}/ReactCommon/react/nativemodule/core/platform/ios", :modular_headers => true
|
|
200
|
-
|
|
230
|
+
rncore_pod 'Yoga', :path => "#{prefix}/ReactCommon/yoga", :modular_headers => true
|
|
201
231
|
setup_fabric!(:react_native_path => prefix)
|
|
202
232
|
setup_bridgeless!(:react_native_path => prefix, :use_hermes => hermes_enabled)
|
|
203
233
|
|
|
@@ -214,6 +244,17 @@ def use_react_native! (
|
|
|
214
244
|
ReactNativeCoreUtils.rncore_log("Using React Native Core and React Native Dependencies prebuilt versions.")
|
|
215
245
|
pod 'ReactNativeDependencies', :podspec => "#{prefix}/third-party-podspecs/ReactNativeDependencies.podspec", :modular_headers => true
|
|
216
246
|
|
|
247
|
+
# Facades: community pods' hardcoded s.dependency "RCT-Folly"/"glog"/... must
|
|
248
|
+
# resolve locally instead of from trunk. See __docs__/prebuilt-deps.md.
|
|
249
|
+
RNDepsFacades.generate(react_native_path, Pod::Config.instance.installation_root, min_ios_version_supported)
|
|
250
|
+
pod 'DoubleConversion', :path => RNDepsFacades.facade_path('DoubleConversion')
|
|
251
|
+
pod 'glog', :path => RNDepsFacades.facade_path('glog')
|
|
252
|
+
pod 'boost', :path => RNDepsFacades.facade_path('boost')
|
|
253
|
+
pod 'fast_float', :path => RNDepsFacades.facade_path('fast_float')
|
|
254
|
+
pod 'fmt', :path => RNDepsFacades.facade_path('fmt')
|
|
255
|
+
pod 'RCT-Folly', :path => RNDepsFacades.facade_path('RCT-Folly')
|
|
256
|
+
pod 'SocketRocket', :path => RNDepsFacades.facade_path('SocketRocket')
|
|
257
|
+
|
|
217
258
|
if !ReactNativeCoreUtils.build_rncore_from_source()
|
|
218
259
|
pod 'React-Core-prebuilt', :podspec => "#{prefix}/React-Core-prebuilt.podspec", :modular_headers => true
|
|
219
260
|
end
|
|
@@ -569,18 +610,26 @@ def react_native_post_install(
|
|
|
569
610
|
ReactNativePodsUtils.add_ndebug_flag_to_pods_in_release(installer)
|
|
570
611
|
|
|
571
612
|
if !ReactNativeCoreUtils.build_rncore_from_source()
|
|
572
|
-
#
|
|
573
|
-
#
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
#
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
# Configure xcconfig for prebuilt usage (VFS overlay, header paths, cleanup redundant paths)
|
|
613
|
+
# The Xcode-26 SWIFT_ENABLE_EXPLICIT_MODULES=NO workaround (#53457) is removed:
|
|
614
|
+
# the modular ReactNativeHeaders layout + React-Core-prebuilt module-map
|
|
615
|
+
# activation + header-less facades let the React module precompile cleanly with
|
|
616
|
+
# explicit modules ON (verified cold-DD green), so the override is unnecessary.
|
|
617
|
+
|
|
618
|
+
# Make the prebuilt React.xcframework headers resolvable from aggregate (main app)
|
|
619
|
+
# and third-party pod targets that don't go through add_rncore_dependency. The headers
|
|
620
|
+
# are served directly from the xcframework's headers-spec layout — no clang VFS overlay.
|
|
581
621
|
ReactNativeCoreUtils.configure_aggregate_xcconfig(installer)
|
|
582
622
|
end
|
|
583
623
|
|
|
624
|
+
if !ReactNativeDependenciesUtils.build_react_native_deps_from_source()
|
|
625
|
+
# Prebuilt-deps mode: make the deps artifact headers (folly/glog/...)
|
|
626
|
+
# resolvable from the aggregate and every pod target, mirroring the rncore
|
|
627
|
+
# injection above. ReactNativeHeaders is pure-RN, so the flattened
|
|
628
|
+
# ReactNativeDependencies/Headers dir is the single global home of the
|
|
629
|
+
# third-party namespaces (see scripts/cocoapods/__docs__/prebuilt-deps.md).
|
|
630
|
+
ReactNativeDependenciesUtils.configure_aggregate_xcconfig(installer)
|
|
631
|
+
end
|
|
632
|
+
|
|
584
633
|
SPM.apply_on_post_install(installer)
|
|
585
634
|
|
|
586
635
|
if privacy_file_aggregation_enabled
|