diff --git a/packages/react-native/scripts/cocoapods/rncore.rb b/packages/react-native/scripts/cocoapods/rncore.rb index 7108f147cf1ddb..71930859197fa2 100644 --- a/packages/react-native/scripts/cocoapods/rncore.rb +++ b/packages/react-native/scripts/cocoapods/rncore.rb @@ -66,7 +66,6 @@ def self.setup_rncore(react_native_path, react_native_version) rncore_log("No prebuilt artifacts found, reverting to building from source.") end rncore_log("Building from source: #{@@build_from_source}") - rncore_log("Source: #{self.resolve_podspec_source()}") end end @@ -89,7 +88,6 @@ def self.resolve_podspec_source() if ENV["RCT_USE_PREBUILT_RNCORE"] == "1" if @@use_nightly - rncore_log("Using nightly tarball") begin return self.podspec_source_download_prebuilt_nightly_tarball(@@react_native_version) rescue => e @@ -122,7 +120,6 @@ def self.podspec_source_download_prebuild_stable_tarball() if @@build_from_source return end - url = stable_tarball_url(@@react_native_version, :debug) rncore_log("Using tarball from URL: #{url}") download_stable_rncore(@@react_native_path, @@react_native_version, :debug) @@ -130,6 +127,154 @@ def self.podspec_source_download_prebuild_stable_tarball() return {:http => url} end + def self.process_dsyms(frameworkTarball, dSymsTarball) + if !@@download_dsyms + return + end + + if @@react_native_path == "" + rncore_log("react_native_path is not set", :error) + return + end + + if @@react_native_version == "" + rncore_log("react_native_version is not set", :error) + return + end + + if @@build_from_source + return + end + + # gunzip the dSymsTarball and the frameworkTarball into a temporary folder + # and then copy the dSYMs into the framework folder and then tar/gz the framework folder again + # into the same location as the original frameworkTarball + + rncore_log("Adding symbols #{Pathname.new(dSymsTarball).relative_path_from(Pathname.pwd).to_s} to framework tarball #{Pathname.new(frameworkTarball).relative_path_from(Pathname.pwd).to_s}") + + FileUtils.mkdir_p(File.dirname(frameworkTarball)) + FileUtils.cp(frameworkTarball, "#{frameworkTarball}.orig") + + rncore_log(" Backed up original tarballs") + + begin + # Now let's gunzip the framework tarball into a .tar file + # Get filename and foldername from the tarball path + frameworkFolder = File.dirname(frameworkTarball) + frameworkFilename = File.basename(frameworkTarball, ".tar.gz") + frameworkTarPath = File.join(frameworkFolder, frameworkFilename + ".tar") + + # Now gunzip the tarball into the frameworkFolder - this will remove the .gz file and leave us with a .tar file + rncore_log(" Unpacking framework tarball") + `gunzip "#{frameworkTarball}"` + + # Now let's untar the dSyms tarball into a temporary folder / dSYMs subfolder + dsyms_tmp_dir = "#{artifacts_dir}/dSYMs" + rncore_log(" Unpacking dSYMs to temporary folder") + `mkdir -p "#{dsyms_tmp_dir}" && tar -xzf "#{dSymsTarball}" -C "#{dsyms_tmp_dir}"` + + # Now we need to remap the symbol files to be relative to the framework folder + remap_sourcemaps_for_symbols(dsyms_tmp_dir) + + # Add the dSYMs folder to the framework folder + rncore_log(" Adding dSYMs to framework tarball") + `(cd "$(dirname "#{dsyms_tmp_dir}")" && mkdir -p React.xcframework && cp -r "$(basename "#{dsyms_tmp_dir}")" React.xcframework/dSYMs && tar -rf "#{frameworkTarPath}" React.xcframework/dSYMs && rm -rf React.xcframework)` + + # Now gzip the framework tarball again - remember to use the .tar file and not the .gz file + rncore_log(" Packing #{Pathname.new(frameworkTarPath).relative_path_from(Pathname.pwd).to_s}") + `gzip -1 "#{frameworkTarPath}"` + + # Clean up the temporary folder + FileUtils.remove_entry(dsyms_tmp_dir) + rncore_log(" Processed dSYMs into framework tarball #{Pathname.new(frameworkTarball).relative_path_from(Pathname.pwd).to_s}") + + # Remove backup of original tarballs + FileUtils.rm_f("#{frameworkTarball}.orig") + + rescue => e + rncore_log("Failed to process dSYMs: #{e.message}", :error) + # Restore the original tarballs + FileUtils.mv("#{frameworkTarball}.orig", frameworkTarball) if File.exist?("#{frameworkTarball}.orig") + rncore_log("Restored original tarballs", :error) + abort "Couldn't process dSYMs: #{e.message}" + end + end + + def self.remap_sourcemaps_for_symbols(symbolsPath) + rncore_log(" Remapping dSYMs to be relative to framework folder") + + # Find all .dSYM bundles in the symbols path + dsym_bundles = [] + Dir.glob(File.join(symbolsPath, "**", "*.dSYM")).each do |path| + if File.directory?(path) + # Check if it's a valid dSYM bundle with Info.plist + info_plist = File.join(path, 'Contents', 'Info.plist') + dsym_bundles << path if File.exist?(info_plist) + end + end + + return if dsym_bundles.empty? + + # Define source path mappings - from absolute build paths to relative framework paths + mappings = [ + # Make sure to make react_native_path absolute + ["/Users/runner/work/react-native/react-native/packages/react-native", "#{File.expand_path(@@react_native_path)}"], + ] + + dsym_bundles.each do |dsym_path| begin + # Get UUIDs for this dSYM bundle + uuid_output = `dwarfdump --uuid "#{dsym_path}" 2>/dev/null` + uuids = uuid_output.scan(/UUID:\s+([0-9A-F-]{36})/i).flatten + + next if uuids.empty? + + # Create Resources directory if it doesn't exist + resources_dir = File.join(dsym_path, 'Contents', 'Resources') + FileUtils.mkdir_p(resources_dir) + + # Generate plist content with path mappings + plist_content = generate_plist_content(mappings) + + # Write plist for each UUID + uuids.each do |uuid| + plist_path = File.join(resources_dir, "#{uuid}.plist") + File.write(plist_path, plist_content) + end + + rescue => e + rncore_log(" Failed to process dSYM #{dsym_path}: #{e.message}", :error) + end + end + + rncore_log(" Completed dSYM remapping for #{dsym_bundles.length} bundles") + end + + def self.generate_plist_content(mappings) + # Generate the source path remapping entries + remapping_entries = mappings.map do |from, to| + " #{from}#{to}" + end.join("\n") + + # Use the first mapping for legacy keys + first_from, first_to = mappings.first + + return <<~PLIST + + + + + DBGVersion3 + DBGBuildSourcePath#{first_from} + DBGSourcePath#{first_to} + DBGSourcePathRemapping + + #{remapping_entries} + + + + PLIST + end + def self.stable_tarball_url(version, build_type) ## You can use the `ENTERPRISE_REPOSITORY` ariable to customise the base url from which artifacts will be downloaded. ## The mirror's structure must be the same of the Maven repo the react-native core team publishes on Maven Central. @@ -210,14 +355,14 @@ def self.rncore_log(message, level = :info) if !Object.const_defined?("Pod::UI") return end - log_message = '[ReactNativeCore] ' + message + log_message = '[ReactNativeCore] ' case level when :info - Pod::UI.puts log_message.green + Pod::UI.puts log_message.green + message when :error - Pod::UI.puts log_message.red + Pod::UI.puts log_message.red + message else - Pod::UI.puts log_message.yellow + Pod::UI.puts log_message.yellow + message end end diff --git a/packages/react-native/scripts/cocoapods/rndependencies.rb b/packages/react-native/scripts/cocoapods/rndependencies.rb index 2717ab09e6b7a8..33a13c96f4f983 100644 --- a/packages/react-native/scripts/cocoapods/rndependencies.rb +++ b/packages/react-native/scripts/cocoapods/rndependencies.rb @@ -75,7 +75,6 @@ def self.resolve_podspec_source() if ENV["RCT_USE_RN_DEP"] && ENV["RCT_USE_RN_DEP"] == "1" if @@use_nightly - rndeps_log("Using nightly tarball") begin return self.podspec_source_download_prebuilt_nightly_tarball(@@react_native_version) rescue => e @@ -84,7 +83,6 @@ def self.resolve_podspec_source() end end - rndeps_log("Using release tarball") begin return self.podspec_source_download_prebuild_release_tarball() rescue => e @@ -160,9 +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}") - download_stable_rndeps(@@react_native_path, @@react_native_version, :debug) + destinationDebug = download_stable_rndeps(@@react_native_path, @@react_native_version, :debug) download_stable_rndeps(@@react_native_path, @@react_native_version, :release) - return {:http => url} + + return {:http => URI::File.build(path: destinationDebug).to_s } end def self.release_tarball_url(version, build_type) @@ -204,7 +203,6 @@ def self.download_stable_rndeps(react_native_path, version, configuration) def self.podspec_source_download_prebuilt_nightly_tarball(version) url = nightly_tarball_url(version) - rndeps_log("Using nightly tarball from URL: #{url}") return {:http => url} end @@ -245,14 +243,13 @@ def self.rndeps_log(message, level = :info) if !Object.const_defined?("Pod::UI") return end - log_message = '[ReactNativeDependencies] ' + message case level when :info - Pod::UI.puts log_message.green + Pod::UI.puts '[ReactNativeDependencies] '.green + message when :error - Pod::UI.puts log_message.red + Pod::UI.puts '[ReactNativeDependencies] '.red + message else - Pod::UI.puts log_message.yellow + Pod::UI.puts '[ReactNativeDependencies] '.yellow + message end end