@@ -120,14 +120,161 @@ def self.podspec_source_download_prebuild_stable_tarball()
120120 if @@build_from_source
121121 return
122122 end
123-
124123 url = stable_tarball_url ( @@react_native_version , :debug )
125124 rncore_log ( "Using tarball from URL: #{ url } " )
126125 download_stable_rncore ( @@react_native_path , @@react_native_version , :debug )
127126 download_stable_rncore ( @@react_native_path , @@react_native_version , :release )
128127 return { :http => url }
129128 end
130129
130+ def self . process_dsyms ( frameworkTarball , dSymsTarball )
131+ if !@@download_dsyms
132+ return
133+ end
134+
135+ if @@react_native_path == ""
136+ rncore_log ( "react_native_path is not set" , :error )
137+ return
138+ end
139+
140+ if @@react_native_version == ""
141+ rncore_log ( "react_native_version is not set" , :error )
142+ return
143+ end
144+
145+ if @@build_from_source
146+ return
147+ end
148+
149+ # gunzip the dSymsTarball and the frameworkTarball into a temporary folder
150+ # and then copy the dSYMs into the framework folder and then tar/gz the framework folder again
151+ # into the same location as the original frameworkTarball
152+
153+ 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 } " )
154+
155+ FileUtils . mkdir_p ( File . dirname ( frameworkTarball ) )
156+ FileUtils . cp ( frameworkTarball , "#{ frameworkTarball } .orig" )
157+
158+ rncore_log ( " Backed up original tarballs" )
159+
160+ begin
161+ # Now let's gunzip the framework tarball into a .tar file
162+ # Get filename and foldername from the tarball path
163+ frameworkFolder = File . dirname ( frameworkTarball )
164+ frameworkFilename = File . basename ( frameworkTarball , ".tar.gz" )
165+ frameworkTarPath = File . join ( frameworkFolder , frameworkFilename + ".tar" )
166+
167+ # Now gunzip the tarball into the frameworkFolder - this will remove the .gz file and leave us with a .tar file
168+ rncore_log ( " Unpacking framework tarball" )
169+ `gunzip "#{ frameworkTarball } "`
170+
171+ # Now let's untar the dSyms tarball into a temporary folder / dSYMs subfolder
172+ dsyms_tmp_dir = "#{ artifacts_dir } /dSYMs"
173+ rncore_log ( " Unpacking dSYMs to temporary folder" )
174+ `mkdir -p "#{ dsyms_tmp_dir } " && tar -xzf "#{ dSymsTarball } " -C "#{ dsyms_tmp_dir } "`
175+
176+ # Now we need to remap the symbol files to be relative to the framework folder
177+ remap_sourcemaps_for_symbols ( dsyms_tmp_dir )
178+
179+ # Add the dSYMs folder to the framework folder
180+ rncore_log ( " Adding dSYMs to framework tarball" )
181+ `(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)`
182+
183+ # Now gzip the framework tarball again - remember to use the .tar file and not the .gz file
184+ rncore_log ( " Packing #{ Pathname . new ( frameworkTarPath ) . relative_path_from ( Pathname . pwd ) . to_s } " )
185+ `gzip -1 "#{ frameworkTarPath } "`
186+
187+ # Clean up the temporary folder
188+ FileUtils . remove_entry ( dsyms_tmp_dir )
189+ rncore_log ( " Processed dSYMs into framework tarball #{ Pathname . new ( frameworkTarball ) . relative_path_from ( Pathname . pwd ) . to_s } " )
190+
191+ # Remove backup of original tarballs
192+ FileUtils . rm_f ( "#{ frameworkTarball } .orig" )
193+
194+ rescue => e
195+ rncore_log ( "Failed to process dSYMs: #{ e . message } " , :error )
196+ # Restore the original tarballs
197+ FileUtils . mv ( "#{ frameworkTarball } .orig" , frameworkTarball ) if File . exist? ( "#{ frameworkTarball } .orig" )
198+ rncore_log ( "Restored original tarballs" , :error )
199+ abort "Couldn't process dSYMs: #{ e . message } "
200+ end
201+ end
202+
203+ def self . remap_sourcemaps_for_symbols ( symbolsPath )
204+ rncore_log ( " Remapping dSYMs to be relative to framework folder" )
205+
206+ # Find all .dSYM bundles in the symbols path
207+ dsym_bundles = [ ]
208+ Dir . glob ( File . join ( symbolsPath , "**" , "*.dSYM" ) ) . each do |path |
209+ if File . directory? ( path )
210+ # Check if it's a valid dSYM bundle with Info.plist
211+ info_plist = File . join ( path , 'Contents' , 'Info.plist' )
212+ dsym_bundles << path if File . exist? ( info_plist )
213+ end
214+ end
215+
216+ return if dsym_bundles . empty?
217+
218+ # Define source path mappings - from absolute build paths to relative framework paths
219+ mappings = [
220+ # Make sure to make react_native_path absolute
221+ [ "/Users/runner/work/react-native/react-native/packages/react-native" , "#{ File . expand_path ( @@react_native_path ) } " ] ,
222+ ]
223+
224+ dsym_bundles . each do |dsym_path | begin
225+ # Get UUIDs for this dSYM bundle
226+ uuid_output = `dwarfdump --uuid "#{ dsym_path } " 2>/dev/null`
227+ uuids = uuid_output . scan ( /UUID:\s +([0-9A-F-]{36})/i ) . flatten
228+
229+ next if uuids . empty?
230+
231+ # Create Resources directory if it doesn't exist
232+ resources_dir = File . join ( dsym_path , 'Contents' , 'Resources' )
233+ FileUtils . mkdir_p ( resources_dir )
234+
235+ # Generate plist content with path mappings
236+ plist_content = generate_plist_content ( mappings )
237+
238+ # Write plist for each UUID
239+ uuids . each do |uuid |
240+ plist_path = File . join ( resources_dir , "#{ uuid } .plist" )
241+ File . write ( plist_path , plist_content )
242+ end
243+
244+ rescue => e
245+ rncore_log ( " Failed to process dSYM #{ dsym_path } : #{ e . message } " , :error )
246+ end
247+ end
248+
249+ rncore_log ( " Completed dSYM remapping for #{ dsym_bundles . length } bundles" )
250+ end
251+
252+ def self . generate_plist_content ( mappings )
253+ # Generate the source path remapping entries
254+ remapping_entries = mappings . map do |from , to |
255+ " <key>#{ from } </key><string>#{ to } </string>"
256+ end . join ( "\n " )
257+
258+ # Use the first mapping for legacy keys
259+ first_from , first_to = mappings . first
260+
261+ return <<~PLIST
262+ <?xml version="1.0" encoding="UTF-8"?>
263+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
264+ <plist version="1.0">
265+ <dict>
266+ <key>DBGVersion</key><string>3</string>
267+ <key>DBGBuildSourcePath</key><string>#{ first_from } </string>
268+ <key>DBGSourcePath</key><string>#{ first_to } </string>
269+ <key>DBGSourcePathRemapping</key>
270+ <dict>
271+ #{ remapping_entries }
272+ </dict>
273+ </dict>
274+ </plist>
275+ PLIST
276+ end
277+
131278 def self . stable_tarball_url ( version , build_type )
132279 ## You can use the `ENTERPRISE_REPOSITORY` ariable to customise the base url from which artifacts will be downloaded.
133280 ## The mirror's structure must be the same of the Maven repo the react-native core team publishes on Maven Central.
0 commit comments