@@ -164,45 +164,54 @@ struct ContentView: View {
164164
165165 // Zsign usually writes changes in-place inside the .app. Rezip Payload -> signed IPA
166166 let signedIpa = tmp. appendingPathComponent ( " signed_ \( appName) .ipa " )
167- // create archive with Payload directory
167+ // ensure output folder exists
168168 try fm. createDirectory ( at: signedIpa. deletingLastPathComponent ( ) , withIntermediateDirectories: true )
169169 let writeArchive = try Archive ( url: signedIpa, accessMode: . create)
170170
171- // recursively add Payload
172- let enumerator = fm. enumerator ( at: payload, includingPropertiesForKeys: nil ) !
171+ // ===== Walk Payload and collect directories and files =====
172+ let enumerator = fm. enumerator ( at: payload, includingPropertiesForKeys: [ . isDirectoryKey] , options: [ ] , errorHandler: nil ) !
173+ var directories : [ URL ] = [ ]
174+ var filesList : [ URL ] = [ ]
173175 for case let file as URL in enumerator {
174- let relative = file. path. replacingOccurrences ( of: tmp. path + " / " , with: " " )
175- if file. hasDirectoryPath {
176- try writeArchive. addEntry (
177- with: relative + " / " ,
178- type: . directory,
179- uncompressedSize: 0 ,
180- modificationDate: Date ( ) ,
181- permissions: nil ,
182- compressionMethod: . deflate,
183- bufferSize: 16 * 1024 ,
184- progress: nil ,
185- provider: { _, _ in Data ( ) }
186- )
176+ // Skip the Payload root itself (we want entries relative to tmp)
177+ if file == payload { continue }
178+ let isDirResource = try file. resourceValues ( forKeys: [ . isDirectoryKey] ) . isDirectory ?? file. hasDirectoryPath
179+ if isDirResource {
180+ directories. append ( file)
187181 } else {
188- let data = try Data ( contentsOf: file)
189- try writeArchive. addEntry (
190- with: relative,
191- type: . file,
192- uncompressedSize: UInt32 ( data. count) ,
193- modificationDate: Date ( ) ,
194- permissions: nil ,
195- compressionMethod: . deflate,
196- bufferSize: 16 * 1024 ,
197- progress: nil ,
198- provider: { ( position, size) in
199- data. subdata ( in: Int ( position) ..< Int ( position + size) )
200- }
201- )
182+ filesList. append ( file)
202183 }
203184 }
204185
205- // share file (move to Documents to be easily accessible)
186+ // Sort directories so parent directories come before children (shorter path first)
187+ directories. sort { $0. path. count < $1. path. count }
188+
189+ // Base for relative paths is tmp
190+ let base = tmp
191+
192+ // Add directories first (use .none compression and trailing slash)
193+ for dir in directories {
194+ let relative = dir. path. replacingOccurrences ( of: tmp. path + " / " , with: " " )
195+ // ensure trailing slash for directory entries inside zip
196+ let entryPath = relative. hasSuffix ( " / " ) ? relative : relative + " / "
197+ try writeArchive. addEntry (
198+ with: entryPath,
199+ relativeTo: base,
200+ compressionMethod: . none
201+ )
202+ }
203+
204+ // Add files (let ZIPFoundation read from disk)
205+ for file in filesList {
206+ let relative = file. path. replacingOccurrences ( of: tmp. path + " / " , with: " " )
207+ try writeArchive. addEntry (
208+ with: relative,
209+ relativeTo: base,
210+ compressionMethod: . deflate
211+ )
212+ }
213+
214+ // Finalise: copy to Documents so user can share
206215 let docs = fm. urls ( for: . documentDirectory, in: . userDomainMask) . first!
207216 let outURL = docs. appendingPathComponent ( " signed_ \( UUID ( ) . uuidString) .ipa " )
208217 if fm. fileExists ( atPath: outURL. path) { try fm. removeItem ( at: outURL) }
0 commit comments