diff --git a/packages/react-native/scripts/cocoapods/rncore.rb b/packages/react-native/scripts/cocoapods/rncore.rb index b9d394f9142..71930859197 100644 --- a/packages/react-native/scripts/cocoapods/rncore.rb +++ b/packages/react-native/scripts/cocoapods/rncore.rb @@ -120,7 +120,6 @@ class ReactNativeCoreUtils 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) @@ -128,6 +127,154 @@ class ReactNativeCoreUtils 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.