Skip to content

feat(iOS): serve third-party deps from the prebuilt ReactNativeDependencies pod via dependency-only facades#57440

Open
chrfalch wants to merge 4 commits into
chrfalch/prebuilt-resourcesfrom
chrfalch/prebuilt-deps-facades
Open

feat(iOS): serve third-party deps from the prebuilt ReactNativeDependencies pod via dependency-only facades#57440
chrfalch wants to merge 4 commits into
chrfalch/prebuilt-resourcesfrom
chrfalch/prebuilt-deps-facades

Conversation

@chrfalch

@chrfalch chrfalch commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Step 1 of making the prebuilt ReactNativeDependencies pod the single header authority for the third-party C/C++ deps (RCT-Folly, glog, boost, DoubleConversion, fmt, fast_float, SocketRocket) in prebuilt-deps mode.

Today the deps binary replaces the source pods' code, but the pod still s.dependency's the real source pods and borrows their headers via $(PODS_ROOT)/<pod> search paths. That split header authority is the dual-copy bug class behind the 2026-07-03 SocketRocket regression (duplicate @interface under use_frameworks! — SocketRocket's ObjC headers have no include guards).

Three commits:

  1. fix(cocoapods): harden prebuilt-deps header search paths and artifact handlingrndependencies.rb's ||= [] << path only added the deps header search path when HEADER_SEARCH_PATHS was unset (silently dropped otherwise); normalize and always append, and point at the pod-local flattened Headers/. ReactNativeDependencies.podspec prepare_command now fails closed (exit 1) instead of silently producing a no-link pod. reactNativeDependencies.js no longer deletes + re-downloads a locally staged artifact that lacks a version marker.

  2. feat(cocoapods): dependency-only facades for third-party pods in prebuilt-deps mode — in prebuilt-deps mode the real source pods are not declared, so a community podspec's hardcoded s.dependency "RCT-Folly" would resolve from trunk and compile from source next to the prebuilt binary. RNDepsFacades generates dependency-only local facade podspecs (no sources, no headers, a single dependency on ReactNativeDependencies); versions/subspecs are derived from the real podspecs in third-party-podspecs/ (SocketRocket synthesized fail-closed from socket_rocket_config). Full contract documented in scripts/cocoapods/__docs__/prebuilt-deps.md.

  3. feat(ios-prebuild): SocketRocket privacy manifest + Xcode 26 header layout — embed an RN-authored, accurate-empty PrivacyInfo.xcprivacy for SocketRocket (upstream ships none), and stage flat public headers into include/ so Xcode 26's SwiftPM accepts the header layout.

Stacked on #57305 (base: chrfalch/prebuilt-resources); the SwiftPM preview (#57332) rebases on top of this. Follow-up (separate PR): headers-only ReactNativeDependenciesHeaders.xcframework sidecar so SPM auto-serves the deps namespaces and ReactNativeHeaders goes pure-RN.

Changelog:

[IOS][CHANGED] - Prebuilt-deps mode: serve third-party headers from the ReactNativeDependencies pod itself and resolve community s.dependency on RCT-Folly/glog/boost/etc. via dependency-only facade pods

Test Plan

E2E matrix (2026-07-06, locally built deps artifact via prepare-ios-prebuilds.js):

  • rn-tester, prebuilt core + prebuilt deps, static linkage — builds
  • rn-tester, prebuilt core + prebuilt deps, USE_FRAMEWORKS=dynamic — builds (the SocketRocket-regression config)
  • helloworld (private), prebuilt core + prebuilt deps, static — builds
  • source-mode control: no facades generated, Podfile.lock identical to baseline

🤖 Generated with Claude Code

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jul 6, 2026
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

Caution

Invalid Base Branch

The base branch for this PR is chrfalch/prebuilt-resources, which is not main or a -stable branch.
Are you sure you want to target this branch?

chrfalch and others added 4 commits July 6, 2026 18:36
… handling

- 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 <noreply@anthropic.com>
…uilt-deps mode

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/<Name>/): 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 <noreply@anthropic.com>
…ayout

- 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 <noreply@anthropic.com>
Pure formatting — no content change. Fixes the format-check lint lane.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@chrfalch chrfalch force-pushed the chrfalch/prebuilt-resources branch from 8158f41 to 562985d Compare July 6, 2026 16:37
@chrfalch chrfalch force-pushed the chrfalch/prebuilt-deps-facades branch from 069c350 to 017ca51 Compare July 6, 2026 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Expo Partner: Expo Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant