@@ -14,15 +14,56 @@ public final class PBXCopyFilesBuildPhase: PBXBuildPhase {
1414 case sharedSupport = 12
1515 case plugins = 13
1616 case other
17+
18+ /// Human-readable string representation used in Xcode 16+
19+ public var stringValue : String {
20+ switch self {
21+ case . absolutePath: return " AbsolutePath "
22+ case . productsDirectory: return " ProductsDirectory "
23+ case . wrapper: return " Wrapper "
24+ case . executables: return " Executables "
25+ case . resources: return " Resources "
26+ case . javaResources: return " JavaResources "
27+ case . frameworks: return " Frameworks "
28+ case . sharedFrameworks: return " SharedFrameworks "
29+ case . sharedSupport: return " SharedSupport "
30+ case . plugins: return " Plugins "
31+ case . other: return " Other "
32+ }
33+ }
34+
35+ /// Initialize from string value (Xcode 16+ format)
36+ public init ? ( string: String ) {
37+ switch string {
38+ case " AbsolutePath " : self = . absolutePath
39+ case " ProductsDirectory " : self = . productsDirectory
40+ case " Wrapper " : self = . wrapper
41+ case " Executables " : self = . executables
42+ case " Resources " : self = . resources
43+ case " JavaResources " : self = . javaResources
44+ case " Frameworks " : self = . frameworks
45+ case " SharedFrameworks " : self = . sharedFrameworks
46+ case " SharedSupport " : self = . sharedSupport
47+ case " Plugins " : self = . plugins
48+ default : return nil
49+ }
50+ }
1751 }
1852
1953 // MARK: - Attributes
2054
2155 /// Element destination path
2256 public var dstPath : String ?
2357
58+ /// Element destination subfolder (Xcode 16+ format, human-readable string)
59+ public var dstSubfolder : SubFolder ?
60+
2461 /// Element destination subfolder spec
25- public var dstSubfolderSpec : SubFolder ?
62+ @available ( * , deprecated, renamed: " dstSubfolder " )
63+ public var dstSubfolderSpec : SubFolder ? {
64+ get { dstSubfolder }
65+ set { dstSubfolder = newValue }
66+ }
2667
2768 /// Copy files build phase name
2869 public var name : String ?
@@ -37,37 +78,59 @@ public final class PBXCopyFilesBuildPhase: PBXBuildPhase {
3778 ///
3879 /// - Parameters:
3980 /// - dstPath: Destination path.
40- /// - dstSubfolderSpec : Destination subfolder spec .
81+ /// - dstSubfolder : Destination subfolder.
4182 /// - buildActionMask: Build action mask.
4283 /// - files: Build files to copy.
4384 /// - runOnlyForDeploymentPostprocessing: Run only for deployment post processing.
4485 public init ( dstPath: String ? = nil ,
45- dstSubfolderSpec : SubFolder ? = nil ,
86+ dstSubfolder : SubFolder ? = nil ,
4687 name: String ? = nil ,
4788 buildActionMask: UInt = defaultBuildActionMask,
4889 files: [ PBXBuildFile ] = [ ] ,
4990 runOnlyForDeploymentPostprocessing: Bool = false ) {
5091 self . dstPath = dstPath
51- self . dstSubfolderSpec = dstSubfolderSpec
92+ self . dstSubfolder = dstSubfolder
5293 self . name = name
5394 super. init ( files: files,
5495 buildActionMask: buildActionMask,
5596 runOnlyForDeploymentPostprocessing:
5697 runOnlyForDeploymentPostprocessing)
5798 }
5899
100+ /// Initializes the copy files build phase with its attributes (deprecated parameter name).
101+ @available ( * , deprecated, renamed: " init(dstPath:dstSubfolder:name:buildActionMask:files:runOnlyForDeploymentPostprocessing:) " )
102+ public convenience init ( dstPath: String ? = nil ,
103+ dstSubfolderSpec: SubFolder ? ,
104+ name: String ? = nil ,
105+ buildActionMask: UInt = defaultBuildActionMask,
106+ files: [ PBXBuildFile ] = [ ] ,
107+ runOnlyForDeploymentPostprocessing: Bool = false ) {
108+ self . init ( dstPath: dstPath,
109+ dstSubfolder: dstSubfolderSpec,
110+ name: name,
111+ buildActionMask: buildActionMask,
112+ files: files,
113+ runOnlyForDeploymentPostprocessing: runOnlyForDeploymentPostprocessing)
114+ }
115+
59116 // MARK: - Decodable
60117
61118 fileprivate enum CodingKeys : String , CodingKey {
62119 case dstPath
120+ case dstSubfolder
63121 case dstSubfolderSpec
64122 case name
65123 }
66124
67125 public required init ( from decoder: Decoder ) throws {
68126 let container = try decoder. container ( keyedBy: CodingKeys . self)
69127 dstPath = try container. decodeIfPresent ( . dstPath)
70- dstSubfolderSpec = try container. decodeIntIfPresent ( . dstSubfolderSpec) . flatMap ( SubFolder . init)
128+ // Try to decode dstSubfolder (Xcode 16+ string format) first, fallback to dstSubfolderSpec (legacy integer format)
129+ if let dstSubfolderString: String = try container. decodeIfPresent ( . dstSubfolder) {
130+ dstSubfolder = SubFolder ( string: dstSubfolderString)
131+ } else {
132+ dstSubfolder = try container. decodeIntIfPresent ( . dstSubfolderSpec) . flatMap ( SubFolder . init)
133+ }
71134 name = try container. decodeIfPresent ( . name)
72135 try super. init ( from: decoder)
73136 }
@@ -90,8 +153,9 @@ extension PBXCopyFilesBuildPhase: PlistSerializable {
90153 if let name {
91154 dictionary [ " name " ] = . string( CommentedString ( name) )
92155 }
93- if let dstSubfolderSpec {
94- dictionary [ " dstSubfolderSpec " ] = . string( CommentedString ( " \( dstSubfolderSpec. rawValue) " ) )
156+ if let dstSubfolder {
157+ // Write using the new Xcode 16+ format (dstSubfolder with string value)
158+ dictionary [ " dstSubfolder " ] = . string( CommentedString ( dstSubfolder. stringValue) )
95159 }
96160 return ( key: CommentedString ( reference, comment: name ?? " CopyFiles " ) , value: . dictionary( dictionary) )
97161 }
0 commit comments