Skip to content

Commit d45ba85

Browse files
committed
fix(cocoapods): escape local file URIs for unicode paths
## Summary #56878 shows that using unicode characters in paths fails with pod install. Expo fixed this internally here: expo/expo#45779 #fixes Unicode filesystem paths break iOS precompiled xcframework resolution due to unescaped URI handling Fixes #56878 ## How Build local file:// sources through a shared helper that percent-encodes filesystem paths before passing them to URI::File.build. This avoids Ruby/CocoaPods URI failures when React Native projects or local prebuilt tarballs live under paths containing Unicode characters or spaces. Apply the helper to RNCore and ReactNativeDependencies local tarball sources, including RNCore dSYM-processed prebuilt paths, while leaving remote Maven and Sonatype URLs unchanged. Add focused coverage for Unicode, spaces, ASCII paths, and the raw URI::File.build regression case.
1 parent 5a3f37c commit d45ba85

4 files changed

Lines changed: 57 additions & 4 deletions

File tree

packages/react-native/scripts/cocoapods/__tests__/utils-test.rb

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,53 @@ def teardown
3939
$RN_PLATFORMS = nil
4040
end
4141

42+
# ===================== #
43+
# TEST - localFileUri #
44+
# ===================== #
45+
46+
def test_localFileUri_whenPathContainsUnicode_returnsEscapedFileUri
47+
# Arrange
48+
path = "/tmp/rn-unicode/💻dev/React-Core-prebuilt.tar.gz"
49+
50+
# Act
51+
result = ReactNativePodsUtils.local_file_uri(path)
52+
53+
# Assert
54+
assert_equal("file:///tmp/rn-unicode/%F0%9F%92%BBdev/React-Core-prebuilt.tar.gz", result)
55+
end
56+
57+
def test_localFileUri_whenPathContainsSpaces_returnsEscapedFileUri
58+
# Arrange
59+
path = "/tmp/rn space/React Core.tar.gz"
60+
61+
# Act
62+
result = ReactNativePodsUtils.local_file_uri(path)
63+
64+
# Assert
65+
assert_equal("file:///tmp/rn%20space/React%20Core.tar.gz", result)
66+
end
67+
68+
def test_localFileUri_whenPathContainsOnlyAscii_returnsFileUri
69+
# Arrange
70+
path = "/tmp/rn-ascii/React-Core-prebuilt.tar.gz"
71+
72+
# Act
73+
result = ReactNativePodsUtils.local_file_uri(path)
74+
75+
# Assert
76+
assert_equal("file:///tmp/rn-ascii/React-Core-prebuilt.tar.gz", result)
77+
end
78+
79+
def test_localFileUri_whenPathContainsUnicode_withoutEscapingUriFileBuildRaises
80+
# Arrange
81+
path = "/tmp/rn-unicode/💻dev/React-Core-prebuilt.tar.gz"
82+
83+
# Act & Assert
84+
assert_raise(URI::InvalidComponentError) do
85+
URI::File.build(path: path).to_s
86+
end
87+
end
88+
4289
# ======================= #
4390
# TEST - warnIfNotOnArm64 #
4491
# ======================= #

packages/react-native/scripts/cocoapods/rncore.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def self.resolve_podspec_source()
103103
if ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"]
104104
abort_if_use_local_rncore_with_no_file()
105105
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"]) }
107107
end
108108

109109
if ENV["RCT_USE_PREBUILT_RNCORE"] == "1"
@@ -161,7 +161,7 @@ def self.podspec_source_download_prebuild_stable_tarball()
161161
rncore_log(" #{Pathname.new(destinationRelease).relative_path_from(Pathname.pwd).to_s}")
162162

163163
return {:http => stable_tarball_url(@@react_native_version, :debug) } unless @@download_dsyms
164-
return {:http => URI::File.build(path: destinationDebug).to_s }
164+
return {:http => ReactNativePodsUtils.local_file_uri(destinationDebug) }
165165
end
166166

167167
def self.podspec_source_download_prebuilt_nightly_tarball()
@@ -198,7 +198,7 @@ def self.podspec_source_download_prebuilt_nightly_tarball()
198198
rncore_log(" #{Pathname.new(destinationDebug).relative_path_from(Pathname.pwd).to_s}")
199199
rncore_log(" #{Pathname.new(destinationRelease).relative_path_from(Pathname.pwd).to_s}")
200200
return {:http => nightly_tarball_url(@@react_native_version, :debug) } unless @@download_dsyms
201-
return {:http => URI::File.build(path: destinationDebug).to_s }
201+
return {:http => ReactNativePodsUtils.local_file_uri(destinationDebug) }
202202
end
203203

204204
def self.process_dsyms(frameworkTarball, dSymsTarball)

packages/react-native/scripts/cocoapods/rndependencies.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def self.resolve_podspec_source()
7070
if ENV["RCT_USE_LOCAL_RN_DEP"]
7171
abort_if_use_local_rndeps_with_no_file()
7272
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"]) }
7474
end
7575

7676
if ENV["RCT_USE_RN_DEP"] && ENV["RCT_USE_RN_DEP"] == "1"

packages/react-native/scripts/cocoapods/utils.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@
55

66
require 'shellwords'
77
require 'digest'
8+
require 'uri'
89

910
require_relative "./helpers.rb"
1011
require_relative "./jsengine.rb"
1112

1213
# Utilities class for React Native Cocoapods
1314
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+
1420
def self.warn_if_not_on_arm64
1521
if SysctlChecker.new().call_sysctl_arm64() == 1 && !Environment.new().ruby_platform().include?('arm64')
1622
Pod::UI.warn 'Do not use "pod install" from inside Rosetta2 (x86_64 emulation on arm64).'

0 commit comments

Comments
 (0)