react-native 0.86.0-rc.0 → 0.86.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.
Files changed (26) hide show
  1. package/Libraries/Components/Pressable/Pressable.d.ts +1 -0
  2. package/Libraries/Components/Pressable/useAndroidRippleForView.js +7 -8
  3. package/Libraries/Components/Touchable/TouchableNativeFeedback.js +6 -10
  4. package/Libraries/Components/View/ViewPropTypes.js +3 -1
  5. package/Libraries/Core/ReactNativeVersion.js +1 -1
  6. package/React/Base/RCTVersion.m +1 -1
  7. package/ReactAndroid/api/ReactAndroid.api +1 -0
  8. package/ReactAndroid/gradle.properties +1 -1
  9. package/ReactAndroid/src/main/java/com/facebook/react/modules/image/ImageLoaderModule.kt +59 -62
  10. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
  11. package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactDrawableHelper.kt +59 -20
  12. package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt +30 -0
  13. package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.kt +2 -7
  14. package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
  15. package/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/HostPlatformViewProps.cpp +19 -2
  16. package/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/NativeDrawable.h +47 -16
  17. package/package.json +9 -9
  18. package/scripts/cocoapods/rncore.rb +65 -11
  19. package/scripts/cocoapods/rndependencies.rb +65 -11
  20. package/scripts/cocoapods/utils.rb +52 -0
  21. package/scripts/codegen/generate-artifacts-executor/generateReactCodegenPodspec.js +8 -3
  22. package/scripts/react_native_pods.rb +15 -2
  23. package/sdks/hermes-engine/hermes-utils.rb +92 -5
  24. package/types_generated/Libraries/Components/Pressable/useAndroidRippleForView.d.ts +5 -2
  25. package/types_generated/Libraries/Components/Touchable/TouchableNativeFeedback.d.ts +8 -6
  26. package/types_generated/Libraries/Components/View/ViewPropTypes.d.ts +4 -2
@@ -10,6 +10,7 @@
10
10
  #include <glog/logging.h>
11
11
  #include <react/debug/react_native_expect.h>
12
12
  #include <react/renderer/core/PropsParserContext.h>
13
+ #include <react/renderer/core/graphicsConversions.h>
13
14
  #include <react/renderer/graphics/Float.h>
14
15
  #include <unordered_map>
15
16
 
@@ -22,14 +23,16 @@ struct NativeDrawable {
22
23
  };
23
24
 
24
25
  struct Ripple {
25
- std::optional<int32_t> color{};
26
+ std::optional<SharedColor> color{};
27
+ std::optional<std::vector<std::string>> colorResourcePaths{};
26
28
  std::optional<Float> rippleRadius{};
27
29
  bool borderless{false};
30
+ std::optional<Float> alpha{};
28
31
 
29
32
  bool operator==(const Ripple &rhs) const
30
33
  {
31
- return std::tie(this->color, this->borderless, this->rippleRadius) ==
32
- std::tie(rhs.color, rhs.borderless, rhs.rippleRadius);
34
+ return std::tie(this->color, this->colorResourcePaths, this->borderless, this->rippleRadius, this->alpha) ==
35
+ std::tie(rhs.color, rhs.colorResourcePaths, rhs.borderless, rhs.rippleRadius, rhs.alpha);
33
36
  }
34
37
  };
35
38
 
@@ -59,8 +62,7 @@ struct NativeDrawable {
59
62
  ~NativeDrawable() = default;
60
63
  };
61
64
 
62
- static inline void
63
- fromRawValue(const PropsParserContext & /*context*/, const RawValue &rawValue, NativeDrawable &result)
65
+ static inline void fromRawValue(const PropsParserContext &context, const RawValue &rawValue, NativeDrawable &result)
64
66
  {
65
67
  auto map = (std::unordered_map<std::string, RawValue>)rawValue;
66
68
 
@@ -73,24 +75,53 @@ fromRawValue(const PropsParserContext & /*context*/, const RawValue &rawValue, N
73
75
  react_native_expect(attrIterator != map.end() && attrIterator->second.hasType<std::string>());
74
76
 
75
77
  result = NativeDrawable{
76
- (std::string)attrIterator->second,
77
- {},
78
- NativeDrawable::Kind::ThemeAttr,
78
+ .themeAttr = (std::string)attrIterator->second,
79
+ .ripple = {},
80
+ .kind = NativeDrawable::Kind::ThemeAttr,
79
81
  };
80
82
  } else if (type == "RippleAndroid") {
81
83
  auto color = map.find("color");
82
84
  auto borderless = map.find("borderless");
83
85
  auto rippleRadius = map.find("rippleRadius");
86
+ auto alpha = map.find("alpha");
87
+
88
+ std::optional<SharedColor> parsedColor{};
89
+ std::optional<std::vector<std::string>> parsedColorResourcePaths{};
90
+ if (color != map.end()) {
91
+ if (color->second.hasType<std::unordered_map<std::string, std::vector<std::string>>>()) {
92
+ auto colorMap = (std::unordered_map<std::string, std::vector<std::string>>)color->second;
93
+ auto pathsIt = colorMap.find("resource_paths");
94
+ if (pathsIt != colorMap.end()) {
95
+ parsedColorResourcePaths = pathsIt->second;
96
+ }
97
+ } else {
98
+ SharedColor resolved;
99
+ fromRawValue(context, color->second, resolved);
100
+ if (resolved) {
101
+ parsedColor = resolved;
102
+ }
103
+ }
104
+ }
105
+
106
+ std::optional<Float> parsedAlpha{};
107
+ if (alpha != map.end() && alpha->second.hasType<Float>()) {
108
+ parsedAlpha = (Float)alpha->second;
109
+ }
84
110
 
85
111
  result = NativeDrawable{
86
- std::string{},
87
- NativeDrawable::Ripple{
88
- color != map.end() && color->second.hasType<int32_t>() ? (int32_t)color->second : std::optional<int32_t>{},
89
- rippleRadius != map.end() && rippleRadius->second.hasType<Float>() ? (Float)rippleRadius->second
90
- : std::optional<Float>{},
91
- borderless != map.end() && borderless->second.hasType<bool>() ? (bool)borderless->second : false,
92
- },
93
- NativeDrawable::Kind::Ripple,
112
+ .themeAttr = std::string{},
113
+ .ripple =
114
+ NativeDrawable::Ripple{
115
+ .color = parsedColor,
116
+ .colorResourcePaths = parsedColorResourcePaths,
117
+ .rippleRadius = rippleRadius != map.end() && rippleRadius->second.hasType<Float>()
118
+ ? (Float)rippleRadius->second
119
+ : std::optional<Float>{},
120
+ .borderless =
121
+ borderless != map.end() && borderless->second.hasType<bool>() ? (bool)borderless->second : false,
122
+ .alpha = parsedAlpha,
123
+ },
124
+ .kind = NativeDrawable::Kind::Ripple,
94
125
  };
95
126
  } else {
96
127
  LOG(ERROR) << "Unknown native drawable type: " << type;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native",
3
- "version": "0.86.0-rc.0",
3
+ "version": "0.86.0-rc.2",
4
4
  "description": "A framework for building native apps using React",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -149,7 +149,7 @@
149
149
  "featureflags": "node ./scripts/featureflags/index.js"
150
150
  },
151
151
  "peerDependencies": {
152
- "@react-native/jest-preset": "0.86.0-rc.0",
152
+ "@react-native/jest-preset": "0.86.0-rc.2",
153
153
  "@types/react": "^19.1.1",
154
154
  "react": "^19.2.3"
155
155
  },
@@ -162,13 +162,13 @@
162
162
  }
163
163
  },
164
164
  "dependencies": {
165
- "@react-native/assets-registry": "0.86.0-rc.0",
166
- "@react-native/codegen": "0.86.0-rc.0",
167
- "@react-native/community-cli-plugin": "0.86.0-rc.0",
168
- "@react-native/gradle-plugin": "0.86.0-rc.0",
169
- "@react-native/js-polyfills": "0.86.0-rc.0",
170
- "@react-native/normalize-colors": "0.86.0-rc.0",
171
- "@react-native/virtualized-lists": "0.86.0-rc.0",
165
+ "@react-native/assets-registry": "0.86.0-rc.2",
166
+ "@react-native/codegen": "0.86.0-rc.2",
167
+ "@react-native/community-cli-plugin": "0.86.0-rc.2",
168
+ "@react-native/gradle-plugin": "0.86.0-rc.2",
169
+ "@react-native/js-polyfills": "0.86.0-rc.2",
170
+ "@react-native/normalize-colors": "0.86.0-rc.2",
171
+ "@react-native/virtualized-lists": "0.86.0-rc.2",
172
172
  "abort-controller": "^3.0.0",
173
173
  "anser": "^1.4.9",
174
174
  "ansi-regex": "^5.0.0",
@@ -103,7 +103,7 @@ class ReactNativeCoreUtils
103
103
  if ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"]
104
104
  abort_if_use_local_rncore_with_no_file()
105
105
  rncore_log("Using local xcframework at #{ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"]}")
106
- return {:http => "file://#{ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"]}" }
106
+ return {:http => ReactNativePodsUtils.local_file_uri(ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"]) }
107
107
  end
108
108
 
109
109
  if ENV["RCT_USE_PREBUILT_RNCORE"] == "1"
@@ -160,7 +160,8 @@ class ReactNativeCoreUtils
160
160
  rncore_log(" #{Pathname.new(destinationDebug).relative_path_from(Pathname.pwd).to_s}")
161
161
  rncore_log(" #{Pathname.new(destinationRelease).relative_path_from(Pathname.pwd).to_s}")
162
162
 
163
- return {:http => URI::File.build(path: destinationDebug).to_s }
163
+ return {:http => stable_tarball_url(@@react_native_version, :debug) } unless @@download_dsyms
164
+ return {:http => ReactNativePodsUtils.local_file_uri(destinationDebug) }
164
165
  end
165
166
 
166
167
  def self.podspec_source_download_prebuilt_nightly_tarball()
@@ -196,7 +197,8 @@ class ReactNativeCoreUtils
196
197
  rncore_log("Resolved nightly ReactNativeCore-prebuilt version:")
197
198
  rncore_log(" #{Pathname.new(destinationDebug).relative_path_from(Pathname.pwd).to_s}")
198
199
  rncore_log(" #{Pathname.new(destinationRelease).relative_path_from(Pathname.pwd).to_s}")
199
- return {:http => URI::File.build(path: destinationDebug).to_s }
200
+ return {:http => nightly_tarball_url(@@react_native_version, :debug) } unless @@download_dsyms
201
+ return {:http => ReactNativePodsUtils.local_file_uri(destinationDebug) }
200
202
  end
201
203
 
202
204
  def self.process_dsyms(frameworkTarball, dSymsTarball)
@@ -404,17 +406,69 @@ class ReactNativeCoreUtils
404
406
  end
405
407
 
406
408
  def self.download_rncore_tarball(react_native_path, tarball_url, version, configuration, dsyms = false)
407
- destination_path = configuration == nil ?
408
- "#{artifacts_dir()}/reactnative-core-#{version}#{dsyms ? "-dSYM" : ""}.tar.gz" :
409
- "#{artifacts_dir()}/reactnative-core-#{version}#{dsyms ? "-dSYM" : ""}-#{configuration}.tar.gz"
409
+ filename = configuration == nil ?
410
+ "reactnative-core-#{version}#{dsyms ? "-dSYM" : ""}.tar.gz" :
411
+ "reactnative-core-#{version}#{dsyms ? "-dSYM" : ""}-#{configuration}.tar.gz"
412
+ destination_path = "#{artifacts_dir()}/#{filename}"
413
+
414
+ if File.exist?(destination_path)
415
+ rncore_log("Tarball #{filename} already exists in Pods. Skipping download.")
416
+ return destination_path
417
+ end
410
418
 
411
- unless File.exist?(destination_path)
412
- # Download to a temporary file first so we don't cache incomplete downloads.
413
- rncore_log("Downloading ReactNativeCore-prebuilt #{dsyms ? "dSYMs " : ""}#{configuration ? configuration.to_s : ""} tarball from #{tarball_url} to #{Pathname.new(destination_path).relative_path_from(Pathname.pwd).to_s}")
419
+ `mkdir -p "#{artifacts_dir()}"`
420
+
421
+ if ReactNativePodsUtils.skip_caches?
422
+ rncore_log("RCT_SKIP_CACHES is set. Downloading #{filename} directly (bypassing shared cache).")
414
423
  tmp_file = "#{artifacts_dir()}/reactnative-core.download"
415
- `mkdir -p "#{artifacts_dir()}" && curl "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
424
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
425
+ unless File.exist?(destination_path)
426
+ abort("[ReactNativeCore] Failed to download #{filename} from #{tarball_url}. Aborting.")
427
+ end
428
+ return destination_path
429
+ end
430
+
431
+ cached_path = File.join(ReactNativePodsUtils.shared_cache_dir(), filename)
432
+ if File.exist?(cached_path)
433
+ rncore_log("Verifying checksum for cached #{filename}...")
434
+ if ReactNativePodsUtils.validate_tarball(cached_path, tarball_url)
435
+ rncore_log("Cache hit: copying #{filename} from shared cache (#{ReactNativePodsUtils.shared_cache_dir()})")
436
+ FileUtils.cp(cached_path, destination_path)
437
+ else
438
+ rncore_log("Shared cache file #{filename} failed SHA verification. Re-downloading.")
439
+ File.delete(cached_path)
440
+ tmp_file = "#{artifacts_dir()}/reactnative-core.download"
441
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
442
+ unless File.exist?(destination_path)
443
+ abort("[ReactNativeCore] Failed to download #{filename} from #{tarball_url}. Aborting.")
444
+ end
445
+ rncore_log("Verifying checksum for downloaded #{filename}...")
446
+ if ReactNativePodsUtils.validate_tarball(destination_path, tarball_url)
447
+ FileUtils.cp(destination_path, cached_path)
448
+ rncore_log("Saved #{filename} to shared cache (#{ReactNativePodsUtils.shared_cache_dir()})")
449
+ else
450
+ File.delete(destination_path) if File.exist?(destination_path)
451
+ abort("[ReactNativeCore] Downloaded file #{filename} failed SHA verification. Aborting.")
452
+ end
453
+ end
416
454
  else
417
- rncore_log("Using downloaded ReactNativeCore-prebuilt #{dsyms ? "dSYMs " : ""}#{configuration ? configuration.to_s : ""} tarball at #{Pathname.new(destination_path).relative_path_from(Pathname.pwd).to_s}")
455
+ rncore_log("Cache miss: downloading #{filename} from #{tarball_url}")
456
+ # Download to a temporary file first so we don't cache incomplete downloads.
457
+ tmp_file = "#{artifacts_dir()}/reactnative-core.download"
458
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
459
+ unless File.exist?(destination_path)
460
+ abort("[ReactNativeCore] Failed to download #{filename} from #{tarball_url}. Aborting.")
461
+ end
462
+ rncore_log("Verifying checksum for downloaded #{filename}...")
463
+ if ReactNativePodsUtils.validate_tarball(destination_path, tarball_url)
464
+ # Save to shared cache for future use
465
+ `mkdir -p "#{ReactNativePodsUtils.shared_cache_dir()}"`
466
+ FileUtils.cp(destination_path, cached_path)
467
+ rncore_log("Saved #{filename} to shared cache (#{ReactNativePodsUtils.shared_cache_dir()})")
468
+ else
469
+ File.delete(destination_path) if File.exist?(destination_path)
470
+ abort("[ReactNativeCore] Downloaded file #{filename} failed SHA verification. Aborting.")
471
+ end
418
472
  end
419
473
 
420
474
  return destination_path
@@ -70,7 +70,7 @@ class ReactNativeDependenciesUtils
70
70
  if ENV["RCT_USE_LOCAL_RN_DEP"]
71
71
  abort_if_use_local_rndeps_with_no_file()
72
72
  rndeps_log("Using local xcframework at #{ENV["RCT_USE_LOCAL_RN_DEP"]}")
73
- return {:http => "file://#{ENV["RCT_USE_LOCAL_RN_DEP"]}" }
73
+ return {:http => ReactNativePodsUtils.local_file_uri(ENV["RCT_USE_LOCAL_RN_DEP"]) }
74
74
  end
75
75
 
76
76
  if ENV["RCT_USE_RN_DEP"] && ENV["RCT_USE_RN_DEP"] == "1"
@@ -158,10 +158,10 @@ class ReactNativeDependenciesUtils
158
158
 
159
159
  url = release_tarball_url(@@react_native_version, :debug)
160
160
  rndeps_log("Using tarball from URL: #{url}")
161
- destinationDebug = download_stable_rndeps(@@react_native_path, @@react_native_version, :debug)
161
+ download_stable_rndeps(@@react_native_path, @@react_native_version, :debug)
162
162
  download_stable_rndeps(@@react_native_path, @@react_native_version, :release)
163
163
 
164
- return {:http => URI::File.build(path: destinationDebug).to_s }
164
+ return {:http => url }
165
165
  end
166
166
 
167
167
  def self.release_tarball_url(version, build_type)
@@ -225,22 +225,76 @@ class ReactNativeDependenciesUtils
225
225
 
226
226
  url = nightly_tarball_url(version, :debug)
227
227
  rndeps_log("Using tarball from URL: #{url}")
228
- destinationDebug = download_nightly_rndeps(@@react_native_path, @@react_native_version, :debug)
228
+ download_nightly_rndeps(@@react_native_path, @@react_native_version, :debug)
229
229
  download_nightly_rndeps(@@react_native_path, @@react_native_version, :release)
230
230
 
231
- return {:http => URI::File.build(path: destinationDebug).to_s }
232
- return {:http => url}
231
+ return {:http => url }
233
232
  end
234
233
 
235
234
  def self.download_rndeps_tarball(react_native_path, tarball_url, version, configuration)
236
- destination_path = configuration == nil ?
237
- "#{artifacts_dir()}/reactnative-dependencies-#{version}.tar.gz" :
238
- "#{artifacts_dir()}/reactnative-dependencies-#{version}-#{configuration}.tar.gz"
235
+ filename = configuration == nil ?
236
+ "reactnative-dependencies-#{version}.tar.gz" :
237
+ "reactnative-dependencies-#{version}-#{configuration}.tar.gz"
238
+ destination_path = "#{artifacts_dir()}/#{filename}"
239
+
240
+ if File.exist?(destination_path)
241
+ rndeps_log("Tarball #{filename} already exists in Pods. Skipping download.")
242
+ return destination_path
243
+ end
244
+
245
+ `mkdir -p "#{artifacts_dir()}"`
246
+
247
+ if ReactNativePodsUtils.skip_caches?
248
+ rndeps_log("RCT_SKIP_CACHES is set. Downloading #{filename} directly (bypassing shared cache).")
249
+ tmp_file = "#{artifacts_dir()}/reactnative-dependencies.download"
250
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
251
+ unless File.exist?(destination_path)
252
+ abort("[ReactNativeDependencies] Failed to download #{filename} from #{tarball_url}. Aborting.")
253
+ end
254
+ return destination_path
255
+ end
239
256
 
240
- unless File.exist?(destination_path)
257
+ cached_path = File.join(ReactNativePodsUtils.shared_cache_dir(), filename)
258
+ if File.exist?(cached_path)
259
+ rndeps_log("Verifying checksum for cached #{filename}...")
260
+ if ReactNativePodsUtils.validate_tarball(cached_path, tarball_url)
261
+ rndeps_log("Cache hit: copying #{filename} from shared cache (#{ReactNativePodsUtils.shared_cache_dir()})")
262
+ FileUtils.cp(cached_path, destination_path)
263
+ else
264
+ rndeps_log("Shared cache file #{filename} failed SHA verification. Re-downloading.")
265
+ File.delete(cached_path)
266
+ tmp_file = "#{artifacts_dir()}/reactnative-dependencies.download"
267
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
268
+ unless File.exist?(destination_path)
269
+ abort("[ReactNativeDependencies] Failed to download #{filename} from #{tarball_url}. Aborting.")
270
+ end
271
+ rndeps_log("Verifying checksum for downloaded #{filename}...")
272
+ if ReactNativePodsUtils.validate_tarball(destination_path, tarball_url)
273
+ FileUtils.cp(destination_path, cached_path)
274
+ rndeps_log("Saved #{filename} to shared cache (#{ReactNativePodsUtils.shared_cache_dir()})")
275
+ else
276
+ File.delete(destination_path) if File.exist?(destination_path)
277
+ abort("[ReactNativeDependencies] Downloaded file #{filename} failed SHA verification. Aborting.")
278
+ end
279
+ end
280
+ else
281
+ rndeps_log("Cache miss: downloading #{filename} from #{tarball_url}")
241
282
  # Download to a temporary file first so we don't cache incomplete downloads.
242
283
  tmp_file = "#{artifacts_dir()}/reactnative-dependencies.download"
243
- `mkdir -p "#{artifacts_dir()}" && curl "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
284
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
285
+ unless File.exist?(destination_path)
286
+ abort("[ReactNativeDependencies] Failed to download #{filename} from #{tarball_url}. Aborting.")
287
+ end
288
+ rndeps_log("Verifying checksum for downloaded #{filename}...")
289
+ if ReactNativePodsUtils.validate_tarball(destination_path, tarball_url)
290
+ # Save to shared cache for future use
291
+ `mkdir -p "#{ReactNativePodsUtils.shared_cache_dir()}"`
292
+ FileUtils.cp(destination_path, cached_path)
293
+ rndeps_log("Saved #{filename} to shared cache (#{ReactNativePodsUtils.shared_cache_dir()})")
294
+ else
295
+ File.delete(destination_path) if File.exist?(destination_path)
296
+ abort("[ReactNativeDependencies] Downloaded file #{filename} failed SHA verification. Aborting.")
297
+ end
244
298
  end
245
299
 
246
300
  return destination_path
@@ -4,12 +4,19 @@
4
4
  # LICENSE file in the root directory of this source tree.
5
5
 
6
6
  require 'shellwords'
7
+ require 'digest'
8
+ require 'uri'
7
9
 
8
10
  require_relative "./helpers.rb"
9
11
  require_relative "./jsengine.rb"
10
12
 
11
13
  # Utilities class for React Native Cocoapods
12
14
  class ReactNativePodsUtils
15
+ # URI::File.build validates path components as ASCII, so escape the filesystem path first.
16
+ def self.local_file_uri(path)
17
+ URI::File.build(path: URI::DEFAULT_PARSER.escape(path)).to_s
18
+ end
19
+
13
20
  def self.warn_if_not_on_arm64
14
21
  if SysctlChecker.new().call_sysctl_arm64() == 1 && !Environment.new().ruby_platform().include?('arm64')
15
22
  Pod::UI.warn 'Do not use "pod install" from inside Rosetta2 (x86_64 emulation on arm64).'
@@ -727,4 +734,49 @@ class ReactNativePodsUtils
727
734
  spec.header_mappings_dir = header_mappings_dir
728
735
  end
729
736
  end
737
+
738
+ # ==================== #
739
+ # Shared download cache #
740
+ # ==================== #
741
+
742
+ def self.skip_caches?
743
+ ENV['RCT_SKIP_CACHES'] == '1'
744
+ end
745
+
746
+ def self.shared_cache_dir()
747
+ return File.join(Dir.home, "Library", "Caches", "ReactNative")
748
+ end
749
+
750
+ def self.fetch_maven_sha1(tarball_url)
751
+ sha1 = `curl -sL "#{tarball_url}.sha1"`.strip
752
+ return sha1.downcase if $?.success? && sha1.match?(/\A[a-fA-F0-9]{40}\z/)
753
+ nil
754
+ end
755
+
756
+ def self.validate_tarball(path, tarball_url)
757
+ expected_sha1 = fetch_maven_sha1(tarball_url)
758
+ basename = File.basename(path)
759
+ if expected_sha1.nil?
760
+ cache_log("SHA1 not available from Maven for #{basename}. Skipping validation.")
761
+ return true
762
+ end
763
+ actual_sha1 = Digest::SHA1.file(path).hexdigest
764
+ if actual_sha1 == expected_sha1
765
+ cache_log("SHA1 verified for #{basename}")
766
+ return true
767
+ end
768
+ cache_log("SHA1 mismatch for #{basename}: expected #{expected_sha1}, got #{actual_sha1}", :error)
769
+ return false
770
+ end
771
+
772
+ def self.cache_log(message, level = :info)
773
+ return unless Object.const_defined?("Pod::UI")
774
+ prefix = '[Cache] '
775
+ case level
776
+ when :error
777
+ Pod::UI.puts prefix.red + message
778
+ else
779
+ Pod::UI.puts prefix.green + message
780
+ end
781
+ end
730
782
  end
@@ -49,8 +49,13 @@ function getInputFiles(appPath /*: string */, appPkgJson /*: $FlowFixMe */) {
49
49
  return '[]';
50
50
  }
51
51
 
52
+ // Normalize appPath so any "Pods/.." segment is collapsed before find runs.
53
+ // Otherwise every find result inherits the search-root prefix containing
54
+ // "/Pods/" and gets dropped by the exclusion filter below.
55
+ const resolvedAppPath = path.resolve(appPath);
56
+
52
57
  const xcodeproj = String(
53
- execSync(`find ${appPath} -type d -name "*.xcodeproj"`),
58
+ execSync(`find ${resolvedAppPath} -type d -name "*.xcodeproj"`),
54
59
  )
55
60
  .trim()
56
61
  .split('\n')
@@ -61,12 +66,12 @@ function getInputFiles(appPath /*: string */, appPkgJson /*: $FlowFixMe */) {
61
66
  )[0];
62
67
  if (!xcodeproj) {
63
68
  throw new Error(
64
- `Cannot find .xcodeproj file inside ${appPath}. This is required to determine codegen spec paths relative to native project.`,
69
+ `Cannot find .xcodeproj file inside ${resolvedAppPath}. This is required to determine codegen spec paths relative to native project.`,
65
70
  );
66
71
  }
67
72
  const jsFiles = '-name "Native*.js" -or -name "*NativeComponent.js"';
68
73
  const tsFiles = '-name "Native*.ts" -or -name "*NativeComponent.ts"';
69
- const findCommand = `find ${path.join(appPath, jsSrcsDir)} -type f -not -path "*/__mocks__/*" -and \\( ${jsFiles} -or ${tsFiles} \\)`;
74
+ const findCommand = `find ${path.join(resolvedAppPath, jsSrcsDir)} -type f -not -path "*/__mocks__/*" -and \\( ${jsFiles} -or ${tsFiles} \\)`;
70
75
  const list = String(execSync(findCommand))
71
76
  .trim()
72
77
  .split('\n')
@@ -539,8 +539,21 @@ def react_native_post_install(
539
539
  rn_relative_to_pods = rn_real.relative_path_from(pods_dir_real)
540
540
  ReactNativePodsUtils.set_build_setting(installer, build_setting: "REACT_NATIVE_PATH", value: File.join("${PODS_ROOT}", rn_relative_to_pods.to_s))
541
541
  # Store the Podfile directory as a build setting so that shell scripts can
542
- # locate it without relying on PODS_ROOT/.. (breaks when Pods/ is a symlink).
543
- ReactNativePodsUtils.set_build_setting(installer, build_setting: "PODFILE_DIR", value: Pod::Config.instance.installation_root.to_s)
542
+ # locate it without hardcoding an absolute path. Use Xcode variable
543
+ # substitution per-project so the value persisted in project.pbxproj is
544
+ # portable across machines: $(SRCROOT) is the Podfile dir for user projects
545
+ # (also avoids the PODS_ROOT/.. traversal that breaks when Pods/ is a
546
+ # symlink), and $(SRCROOT)/.. for the Pods project.
547
+ installer.aggregate_targets.map(&:user_project).uniq(&:path).each do |user_project|
548
+ user_project.build_configurations.each do |config|
549
+ config.build_settings['PODFILE_DIR'] = '$(SRCROOT)'
550
+ end
551
+ user_project.save
552
+ end
553
+ installer.pods_project.build_configurations.each do |config|
554
+ config.build_settings['PODFILE_DIR'] = '$(SRCROOT)/..'
555
+ end
556
+ installer.pods_project.save
544
557
  ReactNativePodsUtils.set_build_setting(installer, build_setting: "SWIFT_ACTIVE_COMPILATION_CONDITIONS", value: ['$(inherited)', 'DEBUG'], config_name: "Debug")
545
558
 
546
559
  if (ENV['RCT_REMOVE_LEGACY_ARCH'] == '1')
@@ -3,6 +3,7 @@
3
3
  # This source code is licensed under the MIT license found in the
4
4
  # LICENSE file in the root directory of this source tree.
5
5
 
6
+ require 'digest'
6
7
  require 'net/http'
7
8
  require 'rexml/document'
8
9
 
@@ -236,16 +237,102 @@ def download_stable_hermes(react_native_path, version, configuration)
236
237
  download_hermes_tarball(react_native_path, tarball_url, version, configuration)
237
238
  end
238
239
 
240
+ def shared_cache_dir()
241
+ return File.join(Dir.home, "Library", "Caches", "ReactNative")
242
+ end
243
+
244
+ def fetch_maven_sha1(tarball_url)
245
+ sha1 = `curl -sL "#{tarball_url}.sha1"`.strip
246
+ return sha1.downcase if $?.success? && sha1.match?(/\A[a-fA-F0-9]{40}\z/)
247
+ nil
248
+ end
249
+
250
+ def skip_caches?
251
+ ENV['RCT_SKIP_CACHES'] == '1'
252
+ end
253
+
254
+ def validate_hermes_tarball(path, tarball_url)
255
+ expected_sha1 = fetch_maven_sha1(tarball_url)
256
+ basename = File.basename(path)
257
+ if expected_sha1.nil?
258
+ hermes_log("SHA1 not available from Maven for #{basename}. Skipping validation.", :info)
259
+ return true
260
+ end
261
+ actual_sha1 = Digest::SHA1.file(path).hexdigest
262
+ if actual_sha1 == expected_sha1
263
+ hermes_log("SHA1 verified for #{basename}", :info)
264
+ return true
265
+ end
266
+ hermes_log("SHA1 mismatch for #{basename}: expected #{expected_sha1}, got #{actual_sha1}", :error)
267
+ return false
268
+ end
269
+
239
270
  def download_hermes_tarball(react_native_path, tarball_url, version, configuration)
240
- destination_path = configuration == nil ?
241
- "#{artifacts_dir()}/hermes-ios-#{version}.tar.gz" :
242
- "#{artifacts_dir()}/hermes-ios-#{version}-#{configuration}.tar.gz"
271
+ filename = configuration == nil ?
272
+ "hermes-ios-#{version}.tar.gz" :
273
+ "hermes-ios-#{version}-#{configuration}.tar.gz"
274
+ destination_path = "#{artifacts_dir()}/#{filename}"
275
+
276
+ if File.exist?(destination_path)
277
+ hermes_log("Tarball #{filename} already exists in Pods. Skipping download.", :info)
278
+ return destination_path
279
+ end
280
+
281
+ `mkdir -p "#{artifacts_dir()}"`
282
+
283
+ if skip_caches?
284
+ hermes_log("RCT_SKIP_CACHES is set. Downloading #{filename} directly (bypassing shared cache).", :info)
285
+ tmp_file = "#{artifacts_dir()}/hermes-ios.download"
286
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
287
+ unless File.exist?(destination_path)
288
+ abort("[Hermes] Failed to download #{filename} from #{tarball_url}. Aborting.")
289
+ end
290
+ return destination_path
291
+ end
243
292
 
244
- unless File.exist?(destination_path)
293
+ cached_path = File.join(shared_cache_dir(), filename)
294
+ if File.exist?(cached_path)
295
+ hermes_log("Verifying checksum for cached #{filename}...", :info)
296
+ if validate_hermes_tarball(cached_path, tarball_url)
297
+ hermes_log("Cache hit: copying #{filename} from shared cache (#{shared_cache_dir()})", :info)
298
+ FileUtils.cp(cached_path, destination_path)
299
+ else
300
+ hermes_log("Shared cache file #{filename} failed SHA verification. Re-downloading.", :info)
301
+ File.delete(cached_path)
302
+ tmp_file = "#{artifacts_dir()}/hermes-ios.download"
303
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
304
+ unless File.exist?(destination_path)
305
+ abort("[Hermes] Failed to download #{filename} from #{tarball_url}. Aborting.")
306
+ end
307
+ hermes_log("Verifying checksum for downloaded #{filename}...", :info)
308
+ if validate_hermes_tarball(destination_path, tarball_url)
309
+ FileUtils.cp(destination_path, cached_path)
310
+ hermes_log("Saved #{filename} to shared cache (#{shared_cache_dir()})", :info)
311
+ else
312
+ File.delete(destination_path) if File.exist?(destination_path)
313
+ abort("[Hermes] Downloaded file #{filename} failed SHA verification. Aborting.")
314
+ end
315
+ end
316
+ else
317
+ hermes_log("Cache miss: downloading #{filename} from #{tarball_url}", :info)
245
318
  # Download to a temporary file first so we don't cache incomplete downloads.
246
319
  tmp_file = "#{artifacts_dir()}/hermes-ios.download"
247
- `mkdir -p "#{artifacts_dir()}" && curl "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
320
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
321
+ unless File.exist?(destination_path)
322
+ abort("[Hermes] Failed to download #{filename} from #{tarball_url}. Aborting.")
323
+ end
324
+ hermes_log("Verifying checksum for downloaded #{filename}...", :info)
325
+ if validate_hermes_tarball(destination_path, tarball_url)
326
+ # Save to shared cache for future use
327
+ `mkdir -p "#{shared_cache_dir()}"`
328
+ FileUtils.cp(destination_path, cached_path)
329
+ hermes_log("Saved #{filename} to shared cache (#{shared_cache_dir()})", :info)
330
+ else
331
+ File.delete(destination_path) if File.exist?(destination_path)
332
+ abort("[Hermes] Downloaded file #{filename} failed SHA verification. Aborting.")
333
+ end
248
334
  end
335
+
249
336
  return destination_path
250
337
  end
251
338
 
@@ -4,27 +4,30 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @generated SignedSource<<63db1ca1373b98ac95b88f2b3a707ea3>>
7
+ * @generated SignedSource<<92efce69dca1861d7bdfc6d9c5ee3a62>>
8
8
  *
9
9
  * This file was translated from Flow by scripts/js-api/build-types/index.js.
10
10
  * Original file: packages/react-native/Libraries/Components/Pressable/useAndroidRippleForView.js
11
11
  */
12
12
 
13
+ import type { ProcessedColorValue } from "../../StyleSheet/processColor";
13
14
  import type { ColorValue } from "../../StyleSheet/StyleSheet";
14
15
  import type { GestureResponderEvent } from "../../Types/CoreEventTypes";
15
16
  import View from "../View/View";
16
17
  import * as React from "react";
17
18
  type NativeBackgroundProp = Readonly<{
18
19
  type: "RippleAndroid";
19
- color: number | undefined;
20
+ color: ProcessedColorValue | undefined;
20
21
  borderless: boolean;
21
22
  rippleRadius: number | undefined;
23
+ alpha: number | undefined;
22
24
  }>;
23
25
  export type PressableAndroidRippleConfig = {
24
26
  color?: ColorValue;
25
27
  borderless?: boolean;
26
28
  radius?: number;
27
29
  foreground?: boolean;
30
+ alpha?: number;
28
31
  };
29
32
  /**
30
33
  * Provides the event handlers and props for configuring the ripple effect on