0
# Build Phases
1
2
Build phase management for controlling compilation, resource copying, framework linking, and custom script execution with support for all Xcode build phase types.
3
4
## Capabilities
5
6
### Custom Build Phase Creation
7
8
Create custom build phases for advanced build workflows.
9
10
```javascript { .api }
11
/**
12
* Add custom build phase to target
13
* Creates and configures build phase with specified files and options
14
* @param {string[]} filePathsArray - Files to include in build phase
15
* @param {string} buildPhaseType - Build phase type (PBXSourcesBuildPhase, etc.)
16
* @param {string} comment - Build phase name/comment displayed in Xcode
17
* @param {string} target - Target UUID (optional, defaults to first target)
18
* @param {object|string} options - Build phase options or folder type for copy phases
19
* @param {string} subfolderPath - Subfolder path for copy phases
20
* @returns {object} Build phase object with UUID and configuration
21
*/
22
addBuildPhase(filePathsArray, buildPhaseType, comment, target, options, subfolderPath);
23
```
24
25
**Usage Examples:**
26
27
```javascript
28
// Add custom sources build phase
29
const sourcePhase = proj.addBuildPhase(
30
['src/CustomCode.m', 'src/Helper.m'],
31
'PBXSourcesBuildPhase',
32
'Custom Sources'
33
);
34
35
// Add custom resources build phase
36
const resourcePhase = proj.addBuildPhase(
37
['assets/config.plist', 'assets/data.json'],
38
'PBXResourcesBuildPhase',
39
'Configuration Resources'
40
);
41
42
// Add copy files build phase for frameworks
43
const copyPhase = proj.addBuildPhase(
44
['Frameworks/Custom.framework'],
45
'PBXCopyFilesBuildPhase',
46
'Embed Custom Frameworks',
47
null, // Use default target
48
'frameworks', // Destination folder type
49
'$(BUILT_PRODUCTS_DIR)'
50
);
51
52
// Add shell script build phase
53
const scriptPhase = proj.addBuildPhase(
54
[], // No files for script phases
55
'PBXShellScriptBuildPhase',
56
'Run SwiftLint',
57
null,
58
{
59
shellPath: '/bin/sh',
60
shellScript: 'if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo "warning: SwiftLint not installed"\nfi',
61
inputPaths: ['$(SRCROOT)/.swiftlint.yml'],
62
outputPaths: []
63
}
64
);
65
```
66
67
### Build Phase Access
68
69
Access existing build phases and their objects.
70
71
```javascript { .api }
72
/**
73
* Get sources build phase object for target
74
* @param {string} target - Target UUID
75
* @returns {object} Sources build phase object
76
*/
77
pbxSourcesBuildPhaseObj(target);
78
79
/**
80
* Get resources build phase object for target
81
* @param {string} target - Target UUID
82
* @returns {object} Resources build phase object
83
*/
84
pbxResourcesBuildPhaseObj(target);
85
86
/**
87
* Get frameworks build phase object for target
88
* @param {string} target - Target UUID
89
* @returns {object} Frameworks build phase object
90
*/
91
pbxFrameworksBuildPhaseObj(target);
92
93
/**
94
* Get embed frameworks build phase object for target
95
* @param {string} target - Target UUID
96
* @returns {object} Embed frameworks build phase object
97
*/
98
pbxEmbedFrameworksBuildPhaseObj(target);
99
100
/**
101
* Get copy files build phase object for target
102
* @param {string} target - Target UUID
103
* @returns {object} Copy files build phase object
104
*/
105
pbxCopyfilesBuildPhaseObj(target);
106
107
/**
108
* Find build phase by group and target
109
* @param {string} group - Build phase group name
110
* @param {string} target - Target UUID
111
* @returns {string} Build phase comment key
112
*/
113
buildPhase(group, target);
114
115
/**
116
* Get build phase object by name, group, and target
117
* @param {string} name - Build phase type name
118
* @param {string} group - Build phase group
119
* @param {string} target - Target UUID
120
* @returns {object} Build phase object
121
*/
122
buildPhaseObject(name, group, target);
123
```
124
125
**Usage Examples:**
126
127
```javascript
128
// Get default build phases
129
const mainTarget = proj.getFirstTarget().uuid;
130
131
const sourcesPhase = proj.pbxSourcesBuildPhaseObj(mainTarget);
132
console.log('Sources files:', sourcesPhase.files.length);
133
134
const resourcesPhase = proj.pbxResourcesBuildPhaseObj(mainTarget);
135
console.log('Resource files:', resourcesPhase.files.length);
136
137
const frameworksPhase = proj.pbxFrameworksBuildPhaseObj(mainTarget);
138
console.log('Linked frameworks:', frameworksPhase.files.length);
139
140
// Find custom build phase
141
const customPhase = proj.buildPhaseObject('PBXShellScriptBuildPhase', 'Run Script', mainTarget);
142
if (customPhase) {
143
console.log('Script phase found:', customPhase.name);
144
}
145
```
146
147
### Build Phase File Management
148
149
Add and remove files from specific build phases.
150
151
```javascript { .api }
152
// Internal methods typically called by higher-level file management functions
153
154
/**
155
* Add file to sources build phase
156
* @param {object} file - File object to add
157
*/
158
addToPbxSourcesBuildPhase(file);
159
160
/**
161
* Remove file from sources build phase
162
* @param {object} file - File object to remove
163
*/
164
removeFromPbxSourcesBuildPhase(file);
165
166
/**
167
* Add file to resources build phase
168
* @param {object} file - File object to add
169
*/
170
addToPbxResourcesBuildPhase(file);
171
172
/**
173
* Remove file from resources build phase
174
* @param {object} file - File object to remove
175
*/
176
removeFromPbxResourcesBuildPhase(file);
177
178
/**
179
* Add file to frameworks build phase
180
* @param {object} file - File object to add
181
*/
182
addToPbxFrameworksBuildPhase(file);
183
184
/**
185
* Remove file from frameworks build phase
186
* @param {object} file - File object to remove
187
*/
188
removeFromPbxFrameworksBuildPhase(file);
189
190
/**
191
* Add file to embed frameworks build phase
192
* @param {object} file - File object to add
193
*/
194
addToPbxEmbedFrameworksBuildPhase(file);
195
196
/**
197
* Remove file from embed frameworks build phase
198
* @param {object} file - File object to remove
199
*/
200
removeFromPbxEmbedFrameworksBuildPhase(file);
201
202
/**
203
* Add file to copy files build phase
204
* @param {object} file - File object to add
205
*/
206
addToPbxCopyfilesBuildPhase(file);
207
208
/**
209
* Remove file from copy files build phase
210
* @param {object} file - File object to remove
211
*/
212
removeFromPbxCopyfilesBuildPhase(file);
213
```
214
215
**Usage Examples:**
216
217
```javascript
218
// These methods are typically called automatically by addSourceFile, addFramework, etc.
219
// but can be used directly for fine-grained control
220
221
// Add file to specific build phases manually
222
const sourceFile = { uuid: 'FILE_UUID', fileRef: 'FILE_REF_UUID', basename: 'MyFile.m' };
223
224
proj.addToPbxBuildFileSection(sourceFile); // Must add to build file section first
225
proj.addToPbxSourcesBuildPhase(sourceFile);
226
227
// Remove from build phases
228
proj.removeFromPbxSourcesBuildPhase(sourceFile);
229
proj.removeFromPbxBuildFileSection(sourceFile);
230
```
231
232
### Build Phase Types and Options
233
234
```javascript { .api }
235
/**
236
* Supported build phase types
237
*/
238
const BUILD_PHASE_TYPES = {
239
'PBXSourcesBuildPhase': 'Compile Sources',
240
'PBXResourcesBuildPhase': 'Copy Bundle Resources',
241
'PBXFrameworksBuildPhase': 'Link Binary With Libraries',
242
'PBXCopyFilesBuildPhase': 'Copy Files',
243
'PBXShellScriptBuildPhase': 'Run Script'
244
};
245
246
/**
247
* Copy files destination types
248
*/
249
const COPY_DESTINATIONS = {
250
'absolute_path': 0,
251
'wrapper': 1,
252
'executables': 6,
253
'resources': 7,
254
'frameworks': 10,
255
'shared_frameworks': 11,
256
'shared_support': 12,
257
'plugins': 13,
258
'products_directory': 16,
259
'java_resources': 15,
260
'xpc_services': 0
261
};
262
263
/**
264
* Target type to destination mapping for copy phases
265
*/
266
const DESTINATION_BY_TARGET_TYPE = {
267
'application': 'wrapper',
268
'app_extension': 'plugins',
269
'bundle': 'wrapper',
270
'command_line_tool': 'wrapper',
271
'dynamic_library': 'products_directory',
272
'framework': 'shared_frameworks',
273
'frameworks': 'frameworks',
274
'static_library': 'products_directory',
275
'unit_test_bundle': 'wrapper',
276
'watch_app': 'wrapper',
277
'watch2_app': 'products_directory',
278
'watch_extension': 'plugins',
279
'watch2_extension': 'plugins'
280
};
281
```
282
283
### Shell Script Build Phase Options
284
285
```javascript { .api }
286
/**
287
* Options for shell script build phases
288
*/
289
interface ShellScriptOptions {
290
/** Shell path (e.g., '/bin/sh', '/usr/bin/python3') */
291
shellPath: string;
292
293
/** Shell script content */
294
shellScript: string;
295
296
/** Input file paths for dependency tracking */
297
inputPaths?: string[];
298
299
/** Output file paths for dependency tracking */
300
outputPaths?: string[];
301
302
/** Show environment variables in build log */
303
showEnvVarsInLog?: boolean;
304
305
/** Run script only when installing */
306
runOnlyForDeploymentPostprocessing?: boolean;
307
}
308
```
309
310
### Copy Files Build Phase Options
311
312
```javascript { .api }
313
/**
314
* Options for copy files build phases
315
*/
316
interface CopyFilesOptions {
317
/** Destination folder type */
318
folderType: string;
319
320
/** Subfolder path within destination */
321
subfolderPath?: string;
322
323
/** Only copy when installing */
324
runOnlyForDeploymentPostprocessing?: boolean;
325
}
326
```
327
328
### Build Phase Structure Types
329
330
```javascript { .api }
331
/**
332
* Base build phase structure
333
*/
334
interface BuildPhase {
335
/** Build phase type */
336
isa: string;
337
338
/** Build action mask */
339
buildActionMask: number;
340
341
/** Files in build phase */
342
files: BuildFile[];
343
344
/** Run only for deployment post-processing */
345
runOnlyForDeploymentPostprocessing: number;
346
}
347
348
interface PBXShellScriptBuildPhase extends BuildPhase {
349
/** Script name */
350
name: string;
351
352
/** Input file paths */
353
inputPaths: string[];
354
355
/** Output file paths */
356
outputPaths: string[];
357
358
/** Shell path */
359
shellPath: string;
360
361
/** Shell script content */
362
shellScript: string;
363
}
364
365
interface PBXCopyFilesBuildPhase extends BuildPhase {
366
/** Copy phase name */
367
name: string;
368
369
/** Destination path */
370
dstPath: string;
371
372
/** Destination subfolder specification */
373
dstSubfolderSpec: number;
374
}
375
376
interface BuildFile {
377
/** Build file UUID */
378
value: string;
379
380
/** Build file comment */
381
comment: string;
382
}
383
```
384
385
### Advanced Build Phase Examples
386
387
**SwiftLint Integration:**
388
```javascript
389
const swiftLintPhase = proj.addBuildPhase(
390
[],
391
'PBXShellScriptBuildPhase',
392
'SwiftLint',
393
null,
394
{
395
shellPath: '/bin/sh',
396
shellScript: `if which swiftlint >/dev/null; then
397
swiftlint
398
else
399
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
400
fi`,
401
inputPaths: [],
402
outputPaths: []
403
}
404
);
405
```
406
407
**Code Generation Script:**
408
```javascript
409
const codeGenPhase = proj.addBuildPhase(
410
[],
411
'PBXShellScriptBuildPhase',
412
'Generate Code',
413
null,
414
{
415
shellPath: '/usr/bin/python3',
416
shellScript: `import os
417
import sys
418
419
# Add your code generation logic here
420
print("Generating code...")`,
421
inputPaths: ['$(SRCROOT)/Templates/'],
422
outputPaths: ['$(DERIVED_FILE_DIR)/Generated.swift']
423
}
424
);
425
```
426
427
**Framework Embedding:**
428
```javascript
429
// Embed custom frameworks for app extensions
430
const embedPhase = proj.addBuildPhase(
431
['CustomFramework.framework', 'ThirdPartySDK.framework'],
432
'PBXCopyFilesBuildPhase',
433
'Embed Frameworks',
434
extensionTarget.uuid,
435
'frameworks',
436
''
437
);
438
```
439
440
**Resource Processing:**
441
```javascript
442
// Custom resource processing
443
const processResourcesPhase = proj.addBuildPhase(
444
[],
445
'PBXShellScriptBuildPhase',
446
'Process Resources',
447
null,
448
{
449
shellPath: '/bin/sh',
450
shellScript: `# Process and optimize images
451
if which imageoptim >/dev/null; then
452
find "$SRCROOT" -name "*.png" -exec imageoptim {} \\;
453
fi
454
455
# Validate plist files
456
find "$SRCROOT" -name "*.plist" -exec plutil -lint {} \\;`,
457
inputPaths: ['$(SRCROOT)/Resources/'],
458
outputPaths: []
459
}
460
);
461
```
462
463
**Multi-Target Build Phase:**
464
```javascript
465
// Add the same script phase to multiple targets
466
const targets = [
467
proj.getFirstTarget(),
468
proj.pbxTargetByName('MyExtension'),
469
proj.pbxTargetByName('MyFramework')
470
];
471
472
targets.forEach(target => {
473
if (target) {
474
proj.addBuildPhase(
475
[],
476
'PBXShellScriptBuildPhase',
477
'Common Build Script',
478
target.uuid || proj.findTargetKey(target.name),
479
{
480
shellPath: '/bin/sh',
481
shellScript: 'echo "Building target: ${TARGET_NAME}"',
482
inputPaths: [],
483
outputPaths: []
484
}
485
);
486
}
487
});
488
```
489
490
**Conditional Build Phases:**
491
```javascript
492
// Build phase that runs only in specific configurations
493
const debugOnlyPhase = proj.addBuildPhase(
494
[],
495
'PBXShellScriptBuildPhase',
496
'Debug Only Script',
497
null,
498
{
499
shellPath: '/bin/sh',
500
shellScript: `if [ "$CONFIGURATION" = "Debug" ]; then
501
echo "Running debug-only operations..."
502
# Debug-specific operations here
503
fi`,
504
inputPaths: [],
505
outputPaths: []
506
}
507
);
508
```
509
510
### Build Phase Best Practices
511
512
**Script Phase Ordering:**
513
- Place code generation scripts before compile sources phases
514
- Place linting/validation scripts after compile sources phases
515
- Place resource processing scripts before copy bundle resources phases
516
517
**Dependency Tracking:**
518
- Always specify `inputPaths` and `outputPaths` for scripts that generate files
519
- Use `$(SRCROOT)`, `$(BUILT_PRODUCTS_DIR)`, and other Xcode variables for portability
520
- Avoid hardcoded absolute paths
521
522
**Performance Optimization:**
523
- Use conditional checks in scripts to avoid unnecessary work
524
- Cache intermediate results when possible
525
- Run expensive operations only when inputs have changed