From f661037d72905a1566fddca6d3cd121a6bf37c15 Mon Sep 17 00:00:00 2001 From: Christian Falch Date: Mon, 6 Jul 2026 10:43:08 +0200 Subject: [PATCH 1/4] fix(cocoapods): harden prebuilt-deps header search paths and artifact handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - rndependencies.rb: the previous "||= [] << path" only added the deps header search path when HEADER_SEARCH_PATHS was unset — with an existing value the path was silently dropped. Normalize string values and always append. Also point the search path at the pod-local flattened Headers/ (single header home) instead of the artifact root. - ReactNativeDependencies.podspec: prepare_command exited 0 when XCFRAMEWORK_PATH/HEADERS_PATH resolved empty, producing a silent no-link pod; fail closed with exit 1. - reactNativeDependencies.js: an artifact without a version marker logged "we are going to use it anyway" but then fell through to rmSync + re-download, destroying locally staged deps builds; honor the message and use it as-is. Co-Authored-By: Claude Fable 5 --- .../scripts/cocoapods/rndependencies.rb | 13 ++++++++++++- .../scripts/ios-prebuild/reactNativeDependencies.js | 4 ++++ .../ReactNativeDependencies.podspec | 4 ++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/react-native/scripts/cocoapods/rndependencies.rb b/packages/react-native/scripts/cocoapods/rndependencies.rb index 1c7fac1a6cb7..20445517ed69 100644 --- a/packages/react-native/scripts/cocoapods/rndependencies.rb +++ b/packages/react-native/scripts/cocoapods/rndependencies.rb @@ -49,8 +49,19 @@ def add_rn_third_party_dependencies(s) current_pod_target_xcconfig["HEADER_SEARCH_PATHS"] = header_search_paths else + # Prebuilt-deps mode: this pod SELF-SERVES the third-party headers from its + # own xcframework (incl. SocketRocket - sole supplier in this mode). See + # scripts/cocoapods/__docs__/prebuilt-deps.md for the full contract. s.dependency "ReactNativeDependencies" - current_pod_target_xcconfig["HEADER_SEARCH_PATHS"] ||= [] << "$(PODS_ROOT)/ReactNativeDependencies" + + 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 + # Artifact headers are flattened into the pod-local Headers/ by the podspec + # prepare_command (see __docs__/prebuilt-deps.md). + header_search_paths << "$(PODS_ROOT)/ReactNativeDependencies/Headers" + current_pod_target_xcconfig["HEADER_SEARCH_PATHS"] = header_search_paths end s.pod_target_xcconfig = current_pod_target_xcconfig diff --git a/packages/react-native/scripts/ios-prebuild/reactNativeDependencies.js b/packages/react-native/scripts/ios-prebuild/reactNativeDependencies.js index f497338bef8b..43c40d9e51bd 100644 --- a/packages/react-native/scripts/ios-prebuild/reactNativeDependencies.js +++ b/packages/react-native/scripts/ios-prebuild/reactNativeDependencies.js @@ -161,6 +161,10 @@ function checkExistingVersion( dependencyLog( `React Native Dependencies found on disk at: ${artifactsPath}.\nNo version file has been found. We are going to use it anyway, but there might be some unexpected behaviors.`, ); + // Honor the message above: an artifact without a version marker is a + // locally-staged one (e.g. a freshly composed deps build) — falling + // through here rmSync'd it and re-downloaded. Use it as-is. + return true; } } else { dependencyLog('React Native Dependencies not found on disk'); diff --git a/packages/react-native/third-party-podspecs/ReactNativeDependencies.podspec b/packages/react-native/third-party-podspecs/ReactNativeDependencies.podspec index e08e6c2b0995..a006f2c1e4ca 100644 --- a/packages/react-native/third-party-podspecs/ReactNativeDependencies.podspec +++ b/packages/react-native/third-party-podspecs/ReactNativeDependencies.podspec @@ -53,13 +53,13 @@ Pod::Spec.new do |spec| # Check if XCFRAMEWORK_PATH is empty if [ -z "$XCFRAMEWORK_PATH" ]; then echo "ERROR: XCFRAMEWORK_PATH is empty." - exit 0 + exit 1 fi # Check if HEADERS_PATH is empty if [ -z "$HEADERS_PATH" ]; then echo "ERROR: HEADERS_PATH is empty." - exit 0 + exit 1 fi cp -R "$HEADERS_PATH/." Headers From 14d328280b0bba8d9bbaf8132a46987ef145bc3b Mon Sep 17 00:00:00 2001 From: Christian Falch Date: Mon, 6 Jul 2026 10:43:08 +0200 Subject: [PATCH 2/4] feat(cocoapods): dependency-only facades for third-party pods in prebuilt-deps mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In prebuilt-deps mode the real source pods (RCT-Folly, glog, boost, DoubleConversion, fmt, fast_float, SocketRocket) are not declared in the Podfile, so a community podspec's hardcoded 's.dependency "RCT-Folly"' would resolve from the CocoaPods trunk and compile from source next to the prebuilt binary — the dual-copy bug class behind the 2026-07-03 SocketRocket regression. RNDepsFacades generates dependency-only local facade podspecs (build/rndeps-facades//): no sources, no headers, a single dependency on ReactNativeDependencies. Versions and subspecs are derived from the real podspecs in third-party-podspecs/ (RCT-Folly keeps /Default + /Fabric with default_subspecs = ["Default"]; SocketRocket is synthesized from socket_rocket_config, fail-closed if absent). Declared as :path pods so Podfile-local resolution beats trunk and nothing is fetched. ReactNativeDependencies remains the single header authority. Docs: scripts/cocoapods/__docs__/prebuilt-deps.md describes the full prebuilt-deps header/facade contract and the mode-by-mode supplier table. Co-Authored-By: Claude Fable 5 --- .../cocoapods/__docs__/prebuilt-deps.md | 72 +++++++ .../scripts/cocoapods/rndeps_facades.rb | 185 ++++++++++++++++++ .../react-native/scripts/react_native_pods.rb | 12 ++ 3 files changed, 269 insertions(+) create mode 100644 packages/react-native/scripts/cocoapods/__docs__/prebuilt-deps.md create mode 100644 packages/react-native/scripts/cocoapods/rndeps_facades.rb diff --git a/packages/react-native/scripts/cocoapods/__docs__/prebuilt-deps.md b/packages/react-native/scripts/cocoapods/__docs__/prebuilt-deps.md new file mode 100644 index 000000000000..7105a88afa1f --- /dev/null +++ b/packages/react-native/scripts/cocoapods/__docs__/prebuilt-deps.md @@ -0,0 +1,72 @@ +# Prebuilt ReactNativeDependencies — self-serving headers + deps facades + +How the third-party C/C++ deps (`RCT-Folly`, `glog`, `boost`, `DoubleConversion`, +`fmt`, `fast_float`, `SocketRocket`) are served when +`ReactNativeDependenciesUtils.build_react_native_deps_from_source()` is false +(prebuilt-deps mode). Source-deps mode is unaffected by everything below. + +## Pod-served headers, CocoaPods only (`rndependencies.rb`) + +In prebuilt-deps mode the `ReactNativeDependencies` POD (CocoaPods) is the single authority +for the third-party deps: compiled code lives in its xcframework binary, and the +artifact's own `Headers/{folly,glog,boost,fmt,double-conversion,fast_float, +SocketRocket}` are flattened into the pod's `Headers/` by the podspec's +`prepare_command`. Consumers resolve bare `` / `` +via CocoaPods public-header linkage from `s.dependency "ReactNativeDependencies"`, +plus an explicit `HEADER_SEARCH_PATHS` entry +(`$(PODS_ROOT)/ReactNativeDependencies/Headers`). The real source pods are neither depended on nor searched. + +NOTE: this is a CocoaPods-level contract. The deps XCFRAMEWORK itself is NOT +self-serving: it is framework-type without `HeadersPath`, so its root `Headers/` +is invisible to SPM binaryTargets (verified 2026-07-04 — `HeadersPath` is +rejected on framework entries). In SPM the six C++ namespaces are served by +ReactNativeHeaders.xcframework; serving them from the deps side requires the +phase-2 headers-only library sidecar (see rn-deps-self-serving plan). + +## Why SocketRocket is vended here + +React-Core compiled from source (source-core + prebuilt-deps mix) imports +`` (`RCTReconnectingWebSocket.m`), and in +prebuilt-deps mode there is NO real SocketRocket pod in the graph — the artifact +is the sole supplier. This does not reintroduce the 2026-07-03 dual-copy +regression: that bug relocated SocketRocket copies onto every pod's search path +(via ReactNativeHeaders → React-Core-prebuilt) while a REAL SocketRocket pod +coexisted. Here there is exactly one physical copy and no coexisting pod. + +## Deps facades (`rndeps_facades.rb`, declared in `react_native_pods.rb`) + +The real source pods are only declared in the deps-from-source branch, so in +prebuilt-deps mode a community podspec's hardcoded `s.dependency "RCT-Folly"` / +`"RCT-Folly/Fabric"` / `"glog"` would resolve from the CocoaPods trunk and +compile from source next to the prebuilt binary. `RNDepsFacades` generates +dependency-only facade podspecs (`build/rndeps-facades//`), installed as +LOCAL pods (`:path`, so Podfile-local resolution beats trunk, nothing fetched): +no sources, no headers, single dependency on `ReactNativeDependencies`. +Versions + subspecs are DERIVED from the real podspecs in `third-party-podspecs/` +(RCT-Folly keeps `/Default` + `/Fabric`, `default_subspecs = ["Default"]`). +SocketRocket has no local podspec — its facade version is SYNTHESIZED from +`Helpers::Constants::socket_rocket_config[:version]`, fail-closed if absent. +`:modular_headers` is intentionally dropped on facade declarations: a +dependency-only placeholder builds no module; consumers get modules from +`ReactNativeDependencies`. + +## Mode × supplier table + +| core × deps | real 3P pods in graph | SocketRocket headers supplier | +|---|---|---| +| source + source | yes (`react_native_pods.rb` deps-source branch) | real pod | +| source + prebuilt | no | RNDeps artifact (sole supplier) | +| prebuilt + source | yes | real pod | +| prebuilt + prebuilt | no | RNDeps artifact | + +## SocketRocket privacy manifest + +Upstream SocketRocket ships NO privacy manifest, and the deps artifact +historically carried bundles only for boost/folly/glog. Fixed alongside this +work: the deps prebuild (`scripts/releases/ios-prebuild/configuration.js`) now +embeds `ReactNativeDependencies_SocketRocket.bundle/PrivacyInfo.xcprivacy`, +sourced from an RN-authored manifest at +`scripts/releases/ios-prebuild/resources/SocketRocket/PrivacyInfo.xcprivacy` +(accurate-empty: +SocketRocket uses no Required Reason APIs). Facades remain resource-free by +design. diff --git a/packages/react-native/scripts/cocoapods/rndeps_facades.rb b/packages/react-native/scripts/cocoapods/rndeps_facades.rb new file mode 100644 index 000000000000..0606afe763d5 --- /dev/null +++ b/packages/react-native/scripts/cocoapods/rndeps_facades.rb @@ -0,0 +1,185 @@ +# 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 'fileutils' + +# Dependency-only facade podspecs for the third-party deps in prebuilt-deps +# mode (deps-side analogue of RNCoreFacades). Design + rationale: +# scripts/cocoapods/__docs__/prebuilt-deps.md +module RNDepsFacades + # The name of the umbrella prebuilt-deps pod every facade depends on. Its pod + # self-serves the third-party headers + carries the binary (see + # rndependencies.rb, ReactNativeDependencies.podspec). + DEPS_POD = "ReactNativeDependencies" + + # pod name => podspec path (relative to the react-native package root), or + # :synthesized for a pod with no local podspec (SocketRocket). Version + + # subspecs + default_subspecs are DERIVED from the real podspec where one + # exists; synthesized entries derive their version from a constant. + FACADE_PODS = { + "RCT-Folly" => "third-party-podspecs/RCT-Folly.podspec", + "glog" => "third-party-podspecs/glog.podspec", + "boost" => "third-party-podspecs/boost.podspec", + "DoubleConversion" => "third-party-podspecs/DoubleConversion.podspec", + "fmt" => "third-party-podspecs/fmt.podspec", + "fast_float" => "third-party-podspecs/fast_float.podspec", + "SocketRocket" => :synthesized, + } + + # Sub-directory (relative to the install root) that holds the generated + # deps facades. Kept separate from RNCoreFacades' `build/rncore-facades` so + # the two families never collide. + FACADE_RELDIR = File.join("build", "rndeps-facades") + + @@install_root = nil + + # Generates the facade podspecs and returns the base directory holding them. + # Each facade gets its OWN sub-directory containing a single + # `.podspec.json`, so it can be installed as a LOCAL pod via + # `:path => ` (PathSource uses the spec in place and never downloads + # `spec.source`). Idempotent; safe to call once per `pod install`. + # + # `react_native_path` locates the real third-party podspecs we mirror. + # version + subspecs + default_subspecs are DERIVED from the real spec (or, + # for SocketRocket, synthesized from the socket_rocket_config version) so the + # facade stays graph-equivalent to the source pod. NO source_files and NO + # headers are emitted — the ReactNativeDependencies pod supplies both. A + # facaded pod whose real podspec can't be read is a hard error (see + # load_real_spec) — silently shipping an empty facade would hide drift. + def self.generate(react_native_path, install_root, ios_version) + @@install_root = install_root.to_s + abs_base = File.join(@@install_root, FACADE_RELDIR) + FileUtils.mkdir_p(abs_base) + FACADE_PODS.each do |name, podspec_rel_path| + dir = File.join(abs_base, name) + FileUtils.mkdir_p(dir) + + if podspec_rel_path == :synthesized + spec = synthesized_spec(name, ios_version) + else + podspec_path = File.join(react_native_path.to_s, podspec_rel_path) + real = load_real_spec(podspec_path, name) + spec = derived_spec(name, real, ios_version) + end + + File.write(File.join(dir, "#{name}.podspec.json"), JSON.pretty_generate(spec)) + end + abs_base + end + + # Facade dir for ``, RELATIVE to the install root — pass to `pod :path =>`. + # Relative (not absolute) so the path CocoaPods records in Podfile.lock is + # portable rather than machine-specific. + def self.facade_path(name) + File.join(FACADE_RELDIR, name) + end + + # Base spec skeleton shared by derived + synthesized facades: dependency-only, + # no source_files, no headers. Depends solely on ReactNativeDependencies. + def self.base_spec(name, version, ios_version) + { + "name" => name, + "version" => version, + "summary" => "Prebuilt facade for #{name} (code + headers live in #{DEPS_POD}).", + "homepage" => "https://reactnative.dev/", + "license" => "MIT", + "authors" => "Meta Platforms, Inc. and its affiliates", + "platforms" => { "ios" => ios_version }, + # Required podspec attribute, but never fetched: installed as a LOCAL + # pod (`:path => `), which uses this spec in place and ships no + # source_files. Placeholder only. + "source" => { "git" => "https://github.com/facebook/react-native.git" }, + "dependencies" => { DEPS_POD => [] }, + } + end + private_class_method :base_spec + + # Facade derived from a real third-party podspec: version + subspecs + + # default_subspecs mirror the real spec so a bare `pod ''` and any + # `pod '/'` resolve to the SAME graph (e.g. RCT-Folly's + # bare + /Default + /Fabric). Each subspec is also dependency-only and + # depends on ReactNativeDependencies. + # + # NOTE: resources (e.g. RCT-Folly's PrivacyInfo.xcprivacy) are intentionally + # NOT carried. In prebuilt-deps mode the third-party code — and its privacy + # manifest — is embedded in the ReactNativeDependencies artifact; the facade + # only needs to declare the dependency (see the design note in the PR). + def self.derived_spec(name, real, ios_version) + spec = base_spec(name, real.version.to_s, ios_version) + + defaults = Array(real.default_subspecs) + spec["default_subspecs"] = defaults unless defaults.empty? + + subspecs = derive_subspecs(real) + unless subspecs.empty? + spec["subspecs"] = subspecs.map do |ss| + { "name" => ss, "dependencies" => { DEPS_POD => [] } } + end + end + + spec + end + private_class_method :derived_spec + + # Facade synthesized for a pod with NO local podspec (SocketRocket, a trunk + # pod). Version comes from Helpers::Constants::socket_rocket_config; no + # subspecs. A missing/blank constant is a hard error rather than a silent + # versionless facade — a bare `pod 'SocketRocket'` in the source path is + # `"~> #{socket_rocket_config[:version]}"`, so the facade MUST carry a version + # that satisfies that constraint. + def self.synthesized_spec(name, ios_version) + version = synthesized_version(name) + base_spec(name, version, ios_version) + end + private_class_method :synthesized_spec + + # Resolves the synthesized version for a no-podspec facade. Fail-closed on a + # missing constant/version. Only SocketRocket is synthesized today. + def self.synthesized_version(name) + case name + when "SocketRocket" + unless defined?(Helpers::Constants) && Helpers::Constants.respond_to?(:socket_rocket_config) + raise "[RNDepsFacades] Cannot synthesize facade for '#{name}': " \ + "Helpers::Constants.socket_rocket_config is unavailable." + end + version = Helpers::Constants.socket_rocket_config[:version] + if version.nil? || version.to_s.strip.empty? + raise "[RNDepsFacades] Cannot synthesize facade for '#{name}': " \ + "socket_rocket_config[:version] is missing or empty." + end + version.to_s + else + raise "[RNDepsFacades] No synthesized version rule for facaded pod '#{name}'. " \ + "Add one to synthesized_version or give it a real podspec in FACADE_PODS." + end + end + private_class_method :synthesized_version + + # Loads the real podspec so we can mirror its structure. A facaded pod with a + # declared podspec path MUST have a readable real podspec — if it's missing or + # unparseable we raise rather than ship an empty facade (which would silently + # drop subspecs / the version, the very drift this mechanism prevents). + def self.load_real_spec(path, name) + unless File.exist?(path) + raise "[RNDepsFacades] Real podspec for facaded pod '#{name}' not found at #{path}. " \ + "Update FACADE_PODS in rndeps_facades.rb if the podspec moved." + end + Pod::Specification.from_file(path) + rescue => e + raise "[RNDepsFacades] Failed to read real podspec for facaded pod '#{name}' at #{path}: #{e.message}" + end + private_class_method :load_real_spec + + # Library (non-test, non-app) subspec names of the real spec, so third-party + # libs depending on `/` (e.g. `RCT-Folly/Fabric`) keep + # resolving. Derived, never hand-listed. + def self.derive_subspecs(real) + real.subspecs + .reject { |ss| ss.test_specification? || (ss.respond_to?(:app_specification?) && ss.app_specification?) } + .map(&:base_name) + end + private_class_method :derive_subspecs +end diff --git a/packages/react-native/scripts/react_native_pods.rb b/packages/react-native/scripts/react_native_pods.rb index 38a0619f1708..4214e23b20da 100644 --- a/packages/react-native/scripts/react_native_pods.rb +++ b/packages/react-native/scripts/react_native_pods.rb @@ -22,6 +22,7 @@ require_relative './cocoapods/spm.rb' require_relative './cocoapods/rncore.rb' require_relative './cocoapods/rncore_facades.rb' +require_relative './cocoapods/rndeps_facades.rb' # Importing to expose use_native_modules! require_relative './cocoapods/autolinking.rb' @@ -243,6 +244,17 @@ def use_react_native! ( ReactNativeCoreUtils.rncore_log("Using React Native Core and React Native Dependencies prebuilt versions.") pod 'ReactNativeDependencies', :podspec => "#{prefix}/third-party-podspecs/ReactNativeDependencies.podspec", :modular_headers => true + # Facades: community pods' hardcoded s.dependency "RCT-Folly"/"glog"/... must + # resolve locally instead of from trunk. See __docs__/prebuilt-deps.md. + RNDepsFacades.generate(react_native_path, Pod::Config.instance.installation_root, min_ios_version_supported) + pod 'DoubleConversion', :path => RNDepsFacades.facade_path('DoubleConversion') + pod 'glog', :path => RNDepsFacades.facade_path('glog') + pod 'boost', :path => RNDepsFacades.facade_path('boost') + pod 'fast_float', :path => RNDepsFacades.facade_path('fast_float') + pod 'fmt', :path => RNDepsFacades.facade_path('fmt') + pod 'RCT-Folly', :path => RNDepsFacades.facade_path('RCT-Folly') + pod 'SocketRocket', :path => RNDepsFacades.facade_path('SocketRocket') + if !ReactNativeCoreUtils.build_rncore_from_source() pod 'React-Core-prebuilt', :podspec => "#{prefix}/React-Core-prebuilt.podspec", :modular_headers => true end From 43304770a8a209fee73177ed68af95a1e67d35e6 Mon Sep 17 00:00:00 2001 From: Christian Falch Date: Mon, 6 Jul 2026 10:43:08 +0200 Subject: [PATCH 3/4] feat(ios-prebuild): SocketRocket privacy manifest + Xcode 26 header layout - Embed an RN-authored, accurate-empty PrivacyInfo.xcprivacy for SocketRocket in the deps prebuild (upstream ships no privacy manifest; the deps artifact historically carried resource bundles only for boost/folly/glog). SocketRocket uses no Required Reason APIs. - Xcode 26's SwiftPM rejects a public-headers directory where the umbrella header has sibling directories ("target 'SocketRocket' has invalid header layout"): stage the flat public headers into include/ via prepareScript and point publicHeaderFiles there. Xcode 16 accepts both layouts; the artifact's Headers/SocketRocket namespace is unaffected. - Rename the dependency 'socket-rocket' -> 'SocketRocket' so the bundle and header-namespace naming line up (ReactNativeDependencies_SocketRocket.bundle). Co-Authored-By: Claude Fable 5 --- scripts/releases/ios-prebuild/configuration.js | 16 ++++++++++++---- .../resources/SocketRocket/PrivacyInfo.xcprivacy | 12 ++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 scripts/releases/ios-prebuild/resources/SocketRocket/PrivacyInfo.xcprivacy diff --git a/scripts/releases/ios-prebuild/configuration.js b/scripts/releases/ios-prebuild/configuration.js index 8bf6f5db12aa..dee7a161be56 100644 --- a/scripts/releases/ios-prebuild/configuration.js +++ b/scripts/releases/ios-prebuild/configuration.js @@ -136,17 +136,25 @@ const dependencies /*: ReadonlyArray */ = [ }, }, { - name: 'socket-rocket', + name: 'SocketRocket', version: '0.7.1', + // Xcode 26's SwiftPM rejects a public-headers dir where the umbrella + // header (SocketRocket.h) has sibling directories (SocketRocket/Internal): + // "target 'SocketRocket' has invalid header layout". Stage the flat public + // headers into include/ and point publicHeaderFiles there. The artifact's + // Headers/SocketRocket namespace (files.headers) is unaffected, and + // Xcode 16 accepts both layouts. + prepareScript: 'mkdir -p include && cp SocketRocket/*.h include/', url: new URL( 'https://github.com/facebookincubator/SocketRocket/archive/refs/tags/0.7.1.tar.gz', ), files: { - sources: ['SocketRocket/**/*.{h,m}'], + sources: ['SocketRocket/**/*.{h,m}', 'include/*.h'], headers: ['SocketRocket/*.h'], + resources: ['../../../scripts/releases/ios-prebuild/resources/SocketRocket/PrivacyInfo.xcprivacy'], }, settings: { - publicHeaderFiles: './SocketRocket', + publicHeaderFiles: './include', headerSearchPaths: [ './', 'SocketRocket', @@ -254,7 +262,7 @@ const dependencies /*: ReadonlyArray */ = [ 'fmt', 'boost', 'fast_float', - 'socket-rocket', + 'SocketRocket', ], settings: { publicHeaderFiles: './', diff --git a/scripts/releases/ios-prebuild/resources/SocketRocket/PrivacyInfo.xcprivacy b/scripts/releases/ios-prebuild/resources/SocketRocket/PrivacyInfo.xcprivacy new file mode 100644 index 000000000000..23a9697f383d --- /dev/null +++ b/scripts/releases/ios-prebuild/resources/SocketRocket/PrivacyInfo.xcprivacy @@ -0,0 +1,12 @@ + + + + + NSPrivacyAccessedAPITypes + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + + From 017ca51a9a173cf7e23157fd1e183b899d71d716 Mon Sep 17 00:00:00 2001 From: Christian Falch Date: Mon, 6 Jul 2026 14:09:15 +0200 Subject: [PATCH 4/4] chore: prettier formatting for prebuilt-deps doc and configuration.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pure formatting — no content change. Fixes the format-check lint lane. Co-Authored-By: Claude Fable 5 --- .../cocoapods/__docs__/prebuilt-deps.md | 46 ++++++++++--------- .../releases/ios-prebuild/configuration.js | 4 +- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/packages/react-native/scripts/cocoapods/__docs__/prebuilt-deps.md b/packages/react-native/scripts/cocoapods/__docs__/prebuilt-deps.md index 7105a88afa1f..f52ed738480a 100644 --- a/packages/react-native/scripts/cocoapods/__docs__/prebuilt-deps.md +++ b/packages/react-native/scripts/cocoapods/__docs__/prebuilt-deps.md @@ -1,20 +1,22 @@ # Prebuilt ReactNativeDependencies — self-serving headers + deps facades -How the third-party C/C++ deps (`RCT-Folly`, `glog`, `boost`, `DoubleConversion`, -`fmt`, `fast_float`, `SocketRocket`) are served when +How the third-party C/C++ deps (`RCT-Folly`, `glog`, `boost`, +`DoubleConversion`, `fmt`, `fast_float`, `SocketRocket`) are served when `ReactNativeDependenciesUtils.build_react_native_deps_from_source()` is false (prebuilt-deps mode). Source-deps mode is unaffected by everything below. ## Pod-served headers, CocoaPods only (`rndependencies.rb`) -In prebuilt-deps mode the `ReactNativeDependencies` POD (CocoaPods) is the single authority -for the third-party deps: compiled code lives in its xcframework binary, and the -artifact's own `Headers/{folly,glog,boost,fmt,double-conversion,fast_float, -SocketRocket}` are flattened into the pod's `Headers/` by the podspec's -`prepare_command`. Consumers resolve bare `` / `` -via CocoaPods public-header linkage from `s.dependency "ReactNativeDependencies"`, -plus an explicit `HEADER_SEARCH_PATHS` entry -(`$(PODS_ROOT)/ReactNativeDependencies/Headers`). The real source pods are neither depended on nor searched. +In prebuilt-deps mode the `ReactNativeDependencies` POD (CocoaPods) is the +single authority for the third-party deps: compiled code lives in its +xcframework binary, and the artifact's own +`Headers/{folly,glog,boost,fmt,double-conversion,fast_float, SocketRocket}` are +flattened into the pod's `Headers/` by the podspec's `prepare_command`. +Consumers resolve bare `` / `` via CocoaPods +public-header linkage from `s.dependency "ReactNativeDependencies"`, plus an +explicit `HEADER_SEARCH_PATHS` entry +(`$(PODS_ROOT)/ReactNativeDependencies/Headers`). The real source pods are +neither depended on nor searched. NOTE: this is a CocoaPods-level contract. The deps XCFRAMEWORK itself is NOT self-serving: it is framework-type without `HeadersPath`, so its root `Headers/` @@ -42,9 +44,10 @@ compile from source next to the prebuilt binary. `RNDepsFacades` generates dependency-only facade podspecs (`build/rndeps-facades//`), installed as LOCAL pods (`:path`, so Podfile-local resolution beats trunk, nothing fetched): no sources, no headers, single dependency on `ReactNativeDependencies`. -Versions + subspecs are DERIVED from the real podspecs in `third-party-podspecs/` -(RCT-Folly keeps `/Default` + `/Fabric`, `default_subspecs = ["Default"]`). -SocketRocket has no local podspec — its facade version is SYNTHESIZED from +Versions + subspecs are DERIVED from the real podspecs in +`third-party-podspecs/` (RCT-Folly keeps `/Default` + `/Fabric`, +`default_subspecs = ["Default"]`). SocketRocket has no local podspec — its +facade version is SYNTHESIZED from `Helpers::Constants::socket_rocket_config[:version]`, fail-closed if absent. `:modular_headers` is intentionally dropped on facade declarations: a dependency-only placeholder builds no module; consumers get modules from @@ -52,12 +55,12 @@ dependency-only placeholder builds no module; consumers get modules from ## Mode × supplier table -| core × deps | real 3P pods in graph | SocketRocket headers supplier | -|---|---|---| -| source + source | yes (`react_native_pods.rb` deps-source branch) | real pod | -| source + prebuilt | no | RNDeps artifact (sole supplier) | -| prebuilt + source | yes | real pod | -| prebuilt + prebuilt | no | RNDeps artifact | +| core × deps | real 3P pods in graph | SocketRocket headers supplier | +| ------------------- | ----------------------------------------------- | ------------------------------- | +| source + source | yes (`react_native_pods.rb` deps-source branch) | real pod | +| source + prebuilt | no | RNDeps artifact (sole supplier) | +| prebuilt + source | yes | real pod | +| prebuilt + prebuilt | no | RNDeps artifact | ## SocketRocket privacy manifest @@ -67,6 +70,5 @@ work: the deps prebuild (`scripts/releases/ios-prebuild/configuration.js`) now embeds `ReactNativeDependencies_SocketRocket.bundle/PrivacyInfo.xcprivacy`, sourced from an RN-authored manifest at `scripts/releases/ios-prebuild/resources/SocketRocket/PrivacyInfo.xcprivacy` -(accurate-empty: -SocketRocket uses no Required Reason APIs). Facades remain resource-free by -design. +(accurate-empty: SocketRocket uses no Required Reason APIs). Facades remain +resource-free by design. diff --git a/scripts/releases/ios-prebuild/configuration.js b/scripts/releases/ios-prebuild/configuration.js index dee7a161be56..3259ac632974 100644 --- a/scripts/releases/ios-prebuild/configuration.js +++ b/scripts/releases/ios-prebuild/configuration.js @@ -151,7 +151,9 @@ const dependencies /*: ReadonlyArray */ = [ files: { sources: ['SocketRocket/**/*.{h,m}', 'include/*.h'], headers: ['SocketRocket/*.h'], - resources: ['../../../scripts/releases/ios-prebuild/resources/SocketRocket/PrivacyInfo.xcprivacy'], + resources: [ + '../../../scripts/releases/ios-prebuild/resources/SocketRocket/PrivacyInfo.xcprivacy', + ], }, settings: { publicHeaderFiles: './include',