From 06b5526dabcba74164d4d8f329450585e5e77dfb Mon Sep 17 00:00:00 2001 From: Christian Falch Date: Tue, 12 May 2026 21:29:10 +0200 Subject: [PATCH] fix(cocoapods) Podfile.lock SPEC CHECKSUMS drift for React XCFrameworks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Symptom:** Two developers (or one developer on two paths, or CI vs. local) running pod install on the same React Native project at the same commit get different SPEC CHECKSUMS entries for React-Core-prebuilt and ReactNativeDependencies in Podfile.lock. That breaks pod install-deployment style verification and any workflow that expects Podfile.lock to be reproducible. Root cause: CocoaPods derives each SPEC CHECKSUMS entry by hashing the in-memory podspec JSON. So anything embedded in source.http, prepare_command, user_target_xcconfig, etc. becomes part of the hash. Two podspec-resolution sites in this repo build their source.http from an absolute on-disk path. Because project_pods_root is an absolute path, the resulting file:///... URL differs across machines or working-tree paths, so the hashed JSON differs, so the checksum differs. **Fix: ** The Maven URL for each tarball is already computed inside both functions (stable_tarball_url(...) / nightly_tarball_url(...) / release_tarball_url(...)). Returning that URL — a stable string identical across machines — instead of the local file:// URL makes source.http path-free. CocoaPods downloads from Maven and caches the tarball itself, so functionality is preserved. The pre-existing local-tarball download is kept untouched (its only remaining consumer is the opt-in `RCT_SYMBOLICATE_PREBUILT_FRAMEWORKS=1` dSYM-injection path in rncore.rb, which still needs file:// to feed CocoaPods a mutated tarball — gated by unless @@download_dsyms so the leak is preserved only for that flag). **Out of scope: ** hermes-engine.podspec has the same shape of leak in user_target_xcconfig.HERMES_CLI_PATH. Fixing it requires a paired change to ensure hermesc lands at the new ${PODS_ROOT}-relative path; that's a separate PR. --- packages/react-native/scripts/cocoapods/rncore.rb | 2 ++ .../react-native/scripts/cocoapods/rndependencies.rb | 9 ++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/react-native/scripts/cocoapods/rncore.rb b/packages/react-native/scripts/cocoapods/rncore.rb index 09cd88363d75..aaa4e5d33250 100644 --- a/packages/react-native/scripts/cocoapods/rncore.rb +++ b/packages/react-native/scripts/cocoapods/rncore.rb @@ -160,6 +160,7 @@ def self.podspec_source_download_prebuild_stable_tarball() rncore_log(" #{Pathname.new(destinationDebug).relative_path_from(Pathname.pwd).to_s}") rncore_log(" #{Pathname.new(destinationRelease).relative_path_from(Pathname.pwd).to_s}") + return {:http => stable_tarball_url(@@react_native_version, :debug) } unless @@download_dsyms return {:http => URI::File.build(path: destinationDebug).to_s } end @@ -196,6 +197,7 @@ def self.podspec_source_download_prebuilt_nightly_tarball() rncore_log("Resolved nightly ReactNativeCore-prebuilt version:") rncore_log(" #{Pathname.new(destinationDebug).relative_path_from(Pathname.pwd).to_s}") rncore_log(" #{Pathname.new(destinationRelease).relative_path_from(Pathname.pwd).to_s}") + return {:http => nightly_tarball_url(@@react_native_version, :debug) } unless @@download_dsyms return {:http => URI::File.build(path: destinationDebug).to_s } end diff --git a/packages/react-native/scripts/cocoapods/rndependencies.rb b/packages/react-native/scripts/cocoapods/rndependencies.rb index a90184034071..2000e316cf73 100644 --- a/packages/react-native/scripts/cocoapods/rndependencies.rb +++ b/packages/react-native/scripts/cocoapods/rndependencies.rb @@ -158,10 +158,10 @@ def self.podspec_source_download_prebuild_release_tarball() url = release_tarball_url(@@react_native_version, :debug) rndeps_log("Using tarball from URL: #{url}") - destinationDebug = download_stable_rndeps(@@react_native_path, @@react_native_version, :debug) + download_stable_rndeps(@@react_native_path, @@react_native_version, :debug) download_stable_rndeps(@@react_native_path, @@react_native_version, :release) - return {:http => URI::File.build(path: destinationDebug).to_s } + return {:http => url } end def self.release_tarball_url(version, build_type) @@ -225,11 +225,10 @@ def self.podspec_source_download_prebuilt_nightly_tarball(version) url = nightly_tarball_url(version, :debug) rndeps_log("Using tarball from URL: #{url}") - destinationDebug = download_nightly_rndeps(@@react_native_path, @@react_native_version, :debug) + download_nightly_rndeps(@@react_native_path, @@react_native_version, :debug) download_nightly_rndeps(@@react_native_path, @@react_native_version, :release) - return {:http => URI::File.build(path: destinationDebug).to_s } - return {:http => url} + return {:http => url } end def self.download_rndeps_tarball(react_native_path, tarball_url, version, configuration)