How to declare commands in Xcode extensions

Issue #638

Use commandDefinitions in XCSourceEditorExtension.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import Foundation
import XcodeKit

class SourceEditorExtension: NSObject, XCSourceEditorExtension {
func extensionDidFinishLaunching() {

}

var commandDefinitions: [[XCSourceEditorCommandDefinitionKey: Any]] {
func makeDef(
_ className: String,
_ commandName: String
) -> [XCSourceEditorCommandDefinitionKey: Any] {
guard let bundleId = Bundle(for: type(of: self)).bundleIdentifier else { return [:] }

return [
XCSourceEditorCommandDefinitionKey.identifierKey: bundleId + className,
XCSourceEditorCommandDefinitionKey.classNameKey: className,
XCSourceEditorCommandDefinitionKey.nameKey: commandName
]
}

return [
makeDef(TypeCommand.className(), "Type"),
makeDef(ReloadCommand.className(), "Reload"),
]
}
}

There is a weird crash that we can’t seem to declare functions or use commandDefinitions, the workaround is to declare in plist

Read more

How to declare commands in Xcode extenstions

Issue #638

Use commandDefinitions in XCSourceEditorExtension.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import Foundation
import XcodeKit

class SourceEditorExtension: NSObject, XCSourceEditorExtension {
func extensionDidFinishLaunching() {

}

var commandDefinitions: [[XCSourceEditorCommandDefinitionKey: Any]] {
func makeDef(
_ className: String,
_ commandName: String
) -> [XCSourceEditorCommandDefinitionKey: Any] {
guard let bundleId = Bundle(for: type(of: self)).bundleIdentifier else { return [:] }

return [
XCSourceEditorCommandDefinitionKey.identifierKey: bundleId + className,
XCSourceEditorCommandDefinitionKey.classNameKey: className,
XCSourceEditorCommandDefinitionKey.nameKey: commandName
]
}

return [
makeDef(TypeCommand.className(), "Type"),
makeDef(ReloadCommand.className(), "Reload"),
]
}
}

There is a weird crash that we can’t seem to declare functions or use commandDefinitions, the workaround is to declare in plist

Read more

How to use application will terminate in macOS

Issue #601

On Xcode 11, applicationWillTerminate is not called because of default automatic termination on in Info.plist. Removing NSSupportsSuddenTermination to trigger will terminate notification

1
2
3
func applicationWillTerminate(_ notification: Notification) {
save()
}
1
2
3
4
<key>NSSupportsAutomaticTermination</key>
<true/>
<key>NSSupportsSuddenTermination</key>
<true/>

How to fix library not found with SPM and CocoaPods in Xcode

Issue #572

After migrating a few pods to use SPM, some libraries fail to load. This is because the workspace now uses both SPM and cocoapods

code signature in … not valid for use in process using Library Validation: mapped file has no Team ID and is not a platform binary (signed with custom identity or adhoc?)

The workaround is to disable Library validation

Screenshot 2020-01-08 at 22 48 28

How to use xcodebuild

Issue #544

man xcodebuild

1
man xcodebuild
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939

XCODEBUILD(1) BSD General Commands Manual XCODEBUILD(1)

NAME
xcodebuild -- build Xcode projects and workspaces

SYNOPSIS
xcodebuild [-project name.xcodeproj] [[-target targetname] ... | -alltargets] [-configuration configurationname]
[-sdk [sdkfullpath | sdkname]] [action ...] [buildsetting=value ...] [-userdefault=value ...]

xcodebuild [-project name.xcodeproj] -scheme schemename [[-destination destinationspecifier] ...] [-destination-timeout value]
[-configuration configurationname] [-sdk [sdkfullpath | sdkname]] [action ...] [buildsetting=value ...]
[-userdefault=value ...]

xcodebuild -workspace name.xcworkspace -scheme schemename [[-destination destinationspecifier] ...] [-destination-timeout value]
[-configuration configurationname] [-sdk [sdkfullpath | sdkname]] [action ...] [buildsetting=value ...]
[-userdefault=value ...]

xcodebuild -version [-sdk [sdkfullpath | sdkname]] [infoitem]

xcodebuild -showsdks

xcodebuild -showBuildSettings [-project name.xcodeproj | [-workspace name.xcworkspace -scheme schemename]]

xcodebuild -showdestinations [-project name.xcodeproj | [-workspace name.xcworkspace -scheme schemename]]

xcodebuild -showTestPlans [-project name.xcodeproj | -workspace name.xcworkspace] -scheme schemename

xcodebuild -list [-project name.xcodeproj | -workspace name.xcworkspace]

xcodebuild -exportArchive -archivePath xcarchivepath -exportPath destinationpath -exportOptionsPlist path
xcodebuild -exportNotarizedApp -archivePath xcarchivepath -exportPath destinationpath

xcodebuild -exportLocalizations -project name.xcodeproj -localizationPath path [[-exportLanguage language] ...]
xcodebuild -importLocalizations -project name.xcodeproj -localizationPath path

DESCRIPTION
xcodebuild builds one or more targets contained in an Xcode project, or builds a scheme contained in an Xcode workspace or Xcode
project.

Usage
To build an Xcode project, run xcodebuild from the directory containing your project (i.e. the directory containing the
name.xcodeproj package). If you have multiple projects in the this directory you will need to use -project to indicate which
project should be built. By default, xcodebuild builds the first target listed in the project, with the default build configu-
ration. The order of the targets is a property of the project and is the same for all users of the project.

To build an Xcode workspace, you must pass both the -workspace and -scheme options to define the build. The parameters of the
scheme will control which targets are built and how they are built, although you may pass other options to xcodebuild to over-
ride some parameters of the scheme.

There are also several options that display info about the installed version of Xcode or about projects or workspaces in the
local directory, but which do not initiate an action. These include -list, -showBuildSettings, -showdestinations, -showsdks,
-showTestPlans, -usage, and -version.

Options
-project name.xcodeproj
Build the project name.xcodeproj. Required if there are multiple project files in the same directory.

-target targetname
Build the target specified by targetname.

-alltargets
Build all the targets in the specified project.

-workspace name.xcworkspace
Build the workspace name.xcworkspace.

-scheme schemename
Build the scheme specified by schemename. Required if building a workspace.

-destination destinationspecifier
Use the destination device described by destinationspecifier. Defaults to a destination that is compatible with the
selected scheme. See the Destinations section below for more details.

-destination-timeout timeout
Use the specified timeout when searching for a destination device. The default is 30 seconds.

-configuration configurationname
Use the build configuration specified by configurationname when building each target.

-arch architecture
Use the architecture specified by architecture when building each target.

-sdk [sdkfullpath | sdkname]
Build an Xcode project or workspace against the specified SDK, using build tools appropriate for that SDK. The argument
may be an absolute path to an SDK, or the canonical name of an SDK.

-showsdks
Lists all available SDKs that Xcode knows about, including their canonical names suitable for use with -sdk. Does not
initiate a build.

-showBuildSettings
Lists the build settings in a project or workspace and scheme. Does not initiate a build. Use with -project or -workspace
and -scheme.

-showdestinations
Lists the valid destinations for a project or workspace and scheme. Does not initiate a build. Use with -project or
-workspace and -scheme.

-showBuildTimingSummary
Display a report of the timings of all the commands invoked during the build.

-showTestPlans
Lists the test plans (if any) associated with the specified scheme. Does not initiate a build. Use with -scheme.

-list
Lists the targets and configurations in a project, or the schemes in a workspace. Does not initiate a build. Use with
-project or -workspace.

-enableAddressSanitizer [YES | NO]
Turns the address sanitizer on or off. This overrides the setting for the launch action of a scheme in a workspace.

-enableThreadSanitizer [YES | NO]
Turns the thread sanitizer on or off. This overrides the setting for the launch action of a scheme in a workspace.

-enableUndefinedBehaviorSanitizer [YES | NO]
Turns the undefined behavior sanitizer on or off. This overrides the setting for the launch action of a scheme in a
workspace.

-enableCodeCoverage [YES | NO]
Turns code coverage on or off during testing. This overrides the setting for the test action of a scheme in a workspace.

-testLanguage language
Specifies ISO 639-1 language during testing. This overrides the setting for the test action of a scheme in a workspace.

-testRegion region
Specifies ISO 3166-1 region during testing. This overrides the setting for the test action of a scheme in a workspace.

-derivedDataPath path
Overrides the folder that should be used for derived data when performing an action on a scheme in a workspace.

-resultBundlePath path
Writes a bundle to the specified path with results from performing an action on a scheme in a workspace. If the path
already exists, xcodebuild will exit with an error. Intermediate directories will be created automatically. The bundle
contains build logs, code coverage reports, XML property lists with test results, screenshots and other attachments col-
lected during testing, and various diagnostic logs.

-allowProvisioningUpdates
Allow xcodebuild to communicate with the Apple Developer website. For automatically signed targets, xcodebuild will create
and update profiles, app IDs, and certificates. For manually signed targets, xcodebuild will download missing or updated
provisioning profiles. Requires a developer account to have been added in Xcode's Accounts preference pane.

-allowProvisioningDeviceRegistration
Allow xcodebuild to register your destination device on the Apple Developer website if necessary. Requires
-allowProvisioningUpdates.

-exportArchive
Specifies that an archive should be distributed. Requires -archivePath and -exportOptionsPlist. For exporting, -exportPath
is also required. Cannot be passed along with an action.

-exportNotarizedApp
Export an archive that has been notarized by Apple. Requires -archivePath and -exportPath.

-archivePath xcarchivepath
Specifies the path for the archive produced by the archive action, or specifies the archive that should be exported when
-exportArchive or -exportNotarizedApp is passed.

-exportPath destinationpath
Specifies the destination for the exported product, including the name of the exported file.

-exportOptionsPlist path
Specifies options for -exportArchive. xcodebuild -help can print the full set of available options.

-exportLocalizations
Exports localizations to XLIFF files. Requires -project and -localizationPath. Cannot be passed along with an action.

-importLocalizations
Imports localizations from an XLIFF file. Requires -project and -localizationPath. Cannot be passed along with an action.

-localizationPath
Specifies a path to a directory or a single XLIFF localization file.

-exportLanguage language
Specifies optional ISO 639-1 languages included in a localization export. May be repeated to specify multiple languages.
May be excluded to specify an export includes only development language strings.

action ...
Specify one or more actions to perform. Available actions are:

build Build the target in the build root (SYMROOT). This is the default action, and is used if no action
is given.

build-for-testing Build the target and associated tests in the build root (SYMROOT). This will also produce an
xctestrun file in the build root. This requires specifying a scheme.

analyze Build and analyze a target or scheme from the build root (SYMROOT). This requires specifying a
scheme.

archive Archive a scheme from the build root (SYMROOT). This requires specifying a scheme.

test Test a scheme from the build root (SYMROOT). This requires specifying a scheme and optionally a
destination.

test-without-building Test compiled bundles. If a scheme is provided with -scheme then the command finds bundles in the
build root (SRCROOT). If an xctestrun file is provided with -xctestrun then the command finds bun-
dles at paths specified in the xctestrun file.

installsrc Copy the source of the project to the source root (SRCROOT).

install Build the target and install it into the target's installation directory in the distribution root
(DSTROOT).

clean Remove build products and intermediate files from the build root (SYMROOT).

-xcconfig filename
Load the build settings defined in filename when building all targets. These settings will override all other settings,
including settings passed individually on the command line.

-xctestrun xctestrunpath
Specifies test run parameters. Can only be used with the test-without-building action. Cannot be used with -workspace or
-project. See <x-man-page://5/xcodebuild.xctestrun> for file format details.

-testPlan test-plan-name
Specifies which test plan associated with the scheme should be used for testing. Pass the name of the .xctestplan file
without its extension.

-skip-testing test-identifier, -only-testing test-identifier
Constrain test targets, classes, or methods in test actions. -only-testing constrains a test action to only testing a
specified identifier, and excluding all other identifiers. -skip-testing constrains a test action to skip testing a spec-
ified identifier, but including all other identifiers. Test identifiers have the form TestTarget[/TestClass[/TestMethod]].
The TestTarget component of an identifier is the name of a unit or UI testing bundle as shown in the Test Navigator. An
xcodebuild command can combine multiple constraint options, but -only-testing has precedence over -skip-testing.

-skip-test-configuration test-configuration-name, -only-test-configuration test-configuration-name
Constrain test configurations in test actions. -only-test-configuration constrains a test action to only test a specified
test configuration within a test plan, and exclude all other test configurations. -skip-test-configuration constrains a
test action to skip a specified test configuration, but include all other test configurations. Each test configuration
name must match the name of a configuration specified in a test plan and is case-sensitive. An xcodebuild command can com-
bine multiple constraint options, but -only-test-configuration has precedence over -skip-test-configuration.

-disable-concurrent-destination-testing
Do not run tests on the specified destinations concurrently. The full test suite will run to completion on a given desti-
nation before it begins on the next.

-maximum-concurrent-test-device-destinations number
If multiple device destinations are specified (and -disable-concurrent-destination-testing is not passed), only test on
number devices at a time. For example, if four iOS devices are specified, but number is 2, the full test suite will run on
each device, but only two devices will be testing at a given time.

-maximum-concurrent-test-simulator-destinations number
If multiple simulator destinations are specified (and -disable-concurrent-destination-testing is not passed), only test on
number simulators at a time. For example, if four iOS simulators are specified, but number is 2, the full test suite will
run on each simulator, but only two simulators will be testing at a given time.

-parallel-testing-enabled [YES | NO]
Overrides the per-target setting in the scheme for running tests in parallel.

-parallel-testing-worker-count number
Spawn exactly number test runners when executing tests in parallel. Overrides -maximum-parallel-testing-workers, if it is
specified.

-maximum-parallel-testing-workers number
Limit the number of test runners that will be spawned when running tests in parallel to number.

-dry-run, -n
Print the commands that would be executed, but do not execute them.

-skipUnavailableActions
Skip actions that cannot be performed instead of failing. This option is only honored if -scheme is passed.

buildsetting=value
Set the build setting buildsetting to value.

A detailed reference of Xcode build settings can be found at: <https://help.apple.com/xcode/mac/current/#/itcaec37c2a6>

-userdefault=value
Set the user default userdefault to value.

-toolchain [identifier | name]
Use a given toolchain, specified with either an identifier or name.

-quiet
Do not print any output except for warnings and errors.

-verbose
Provide additional status output.

-version
Display version information for this install of Xcode. Does not initiate a build. When used in conjunction with -sdk, the
version of the specified SDK is displayed, or all SDKs if -sdk is given no argument. Additionally, a single line of the
reported version information may be returned if infoitem is specified.

-license
Show the Xcode and SDK license agreements. Allows for accepting the license agreements without launching Xcode itself,
which is useful for headless systems. Must be run as a privileged user.

-checkFirstLaunchStatus
Check if any First Launch tasks need to be performed.

-runFirstLaunch
Install packages and agree to the license.

-usage
Displays usage information for xcodebuild.

Destinations
The -destination option takes as its argument a destination specifier describing the device (or devices) to use as a destina-
tion. A destination specifier is a single argument consisting of a set of comma-separated key=value pairs. The -destination
option may be specified multiple times to cause xcodebuild to perform the specified action on multiple destinations.

Destination specifiers may include the platform key to specify one of the supported destination platforms. There are additional
keys which should be supplied depending on the platform of the device you are selecting.

Some devices may take time to look up. The -destination-timeout option can be used to specify the amount of time to wait before
a device is considered unavailable. If unspecified, the default timeout is 30 seconds.

Currently, xcodebuild supports these platforms:

macOS The local Mac, referred to in the Xcode interface as My Mac, and which supports the following key:

arch The architecture to use, either x86_64 (the default) or i386.

variant The optional variant to use, e.g. Mac Catalyst.

iOS An iOS device, which supports the following keys:

id The identifier of the device to use, as shown in the Devices window. A valid destination specifier must
provide either id or name, but not both.

name The name of the device to use. A valid destination specifier must provide either id or name, but not
both.

iOS Simulator A simulated iOS device, which supports the following keys:

id The identifier of the simulated device to use, as shown in the Devices window. A valid destination
specifier must provide either id or name, but not both.

name The name of the simulated device to use. A valid destination specifier must provide either id or name,
but not both.

OS When specifying the simulated device by name, the iOS version for that simulated device, such as 6.0,
or the string latest (the default) to indicate the most recent version of iOS supported by this version
of Xcode.

watchOS A watchOS app is always built and deployed nested inside of an iOS app. To use a watchOS device as your des-
tination, specify a scheme which is configured to run a WatchKit app, and specify the iOS platform destina-
tion that is paired with the watchOS device you want to use.

watchOS Simulator A watchOS Simulator app is always built and deployed nested inside of an iOS Simulator app. To use a watchOS
Simulator device as your destination, specify a scheme which is configured to run a WatchKit app, and specify
the iOS Simulator platform destination that is paired with the watchOS Simulator device you want to use.

tvOS A tvOS device, which supports the following keys:

id The identifier of the device to use, as shown in the Devices window. A valid destination specifier must
provide either id or name, but not both.

name The name of the device to use. A valid destination specifier must provide either id or name, but not
both.

tvOS Simulator A simulated tvOS device, which supports the following keys:

id The identifier of the simulated device to use, as shown in the Devices window. A valid destination
specifier must provide either id or name, but not both.

name The name of the simulated device to use. A valid destination specifier must provide either id or name,
but not both.

OS When specifying the simulated device by name, the tvOS version for that simulated device, such as 9.0,
or the string latest (the default) to indicate the most recent version of tvOS supported by this ver-
sion of Xcode.

Some actions (such as building) may be performed without an actual device present. To build against a platform generically
instead of a specific device, the destination specifier may be prefixed with the optional string "generic/", indicating that the
platform should be targeted generically. An example of a generic destination is the "Generic iOS Device" destination displayed
in Xcode's UI when no physical iOS device is present.

Testing on Multiple Destinations
When more than one destination is specified with the -destination option, xcodebuild tests on those destinations concurrently.
In this mode, xcodebuild automatically chooses the number of devices and simulators that are used simultaneously. All enabled
tests in the scheme or xctestrun file are run on each destination.

Distributing Archives
The -exportArchive option specifies that xcodebuild should distribute the archive specified by -archivePath using the options
specified by -exportOptionsPlist. xcodebuild -help can print the full set of available inputs to -exportOptionsPlist. The
product can either be uploaded to Apple or exported locally. The exported product will be placed at the path specified by
-exportPath.

Archives that have been uploaded to the Apple notary service can be distributed using the -exportNotarizedApp option. This spec-
ifies that xcodebuild should export a notarized app from the archive specified by -archivePath and place the exported product at
the path specified by -exportPath. If the archive has not completed processing by the notary service, or processing failed,
then xcodebuild will exit and emit informational or error messages.

When uploading an archive using the -exportArchive option, or exporting a notarized archive using the -exportNotarizedApp
option, an Apple ID account belonging to the archive's development team is required. Enter the credentials for the Apple ID
account using Xcode's Accounts preference pane before invoking xcodebuild.

Environment Variables
The following environment variables affect the execution of xcodebuild:

XCODE_XCCONFIG_FILE
Set to a path to a file, build settings in that file will be loaded and used when building all targets. These
settings will override all other settings, including settings passed individually on the command line, and those
in the file passed with the -xcconfig option.

Exit Codes
xcodebuild exits with codes defined by sysexits(3). It will exit with EX_OK on success. On failure, it will commonly exit with
EX_USAGE if any options appear malformed, EX_NOINPUT if any input files cannot be found, EX_IOERR if any files cannot be read or
written, and EX_SOFTWARE if the commands given to xcodebuild fail. It may exit with other codes in less common scenarios.

EXAMPLES
xcodebuild clean install

Cleans the build directory; then builds and installs the first target in the Xcode project in the directory from which
xcodebuild was started.

xcodebuild -project MyProject.xcodeproj -target Target1 -target Target2 -configuration Debug

Builds the targets Target1 and Target2 in the project MyProject.xcodeproj using the Debug configuration.

xcodebuild -target MyTarget OBJROOT=/Build/MyProj/Obj.root SYMROOT=/Build/MyProj/Sym.root

Builds the target MyTarget in the Xcode project in the directory from which xcodebuild was started, putting intermedi-
ate files in the directory /Build/MyProj/Obj.root and the products of the build in the directory
/Build/MyProj/Sym.root.

xcodebuild -sdk macosx10.6

Builds the Xcode project in the directory from which xcodebuild was started against the macOS 10.6 SDK. The canonical
names of all available SDKs can be viewed using the -showsdks option.

xcodebuild -workspace MyWorkspace.xcworkspace -scheme MyScheme

Builds the scheme MyScheme in the Xcode workspace MyWorkspace.xcworkspace.

xcodebuild archive -workspace MyWorkspace.xcworkspace -scheme MyScheme

Archives the scheme MyScheme in the Xcode workspace MyWorkspace.xcworkspace.

xcodebuild build-for-testing -workspace MyWorkspace.xcworkspace -scheme MyScheme -destination generic/platform=iOS

Build tests and associated targets in the scheme MyScheme in the Xcode workspace MyWorkspace.xcworkspace using the
generic iOS device destination. The command also writes test parameters from the scheme to an xctestrun file in the
built products directory.

xcodebuild test-without-building -workspace MyWorkspace.xcworkspace -scheme MyScheme -destination 'platform=iOS
Simulator,name=iPhone 5s' -destination 'platform=iOS,name=My iPad'

Tests the scheme MyScheme in the Xcode workspace MyWorkspace.xcworkspace using both the iOS Simulator and the device
named iPhone 5s for the latest version of iOS. The command assumes the test bundles are in the build root (SYMROOT).
(Note that the shell requires arguments to be quoted or otherwise escaped if they contain spaces.)

xcodebuild test-without-building -xctestrun MyTestRun.xctestrun -destination 'platform=iOS Simulator,name=iPhone 5s'
-destination 'platform=iOS,name=My iPad'

Tests using both the iOS Simulator and the device named iPhone 5s. Test bundle paths and other test parameters are
specified in MyTestRun.xctestrun. The command requires project binaries and does not require project source code.

xcodebuild test -workspace MyWorkspace.xcworkspace -scheme MyScheme -destination 'platform=macOS,arch=x86_64'

Tests the scheme MyScheme in the Xcode workspace MyWorkspace.xcworkspace using the destination described as My Mac
64-bit in Xcode.

XCODEBUILD(1) BSD General Commands Manual XCODEBUILD(1)

NAME
xcodebuild -- build Xcode projects and workspaces

SYNOPSIS
xcodebuild [-project name.xcodeproj] [[-target targetname] ... | -alltargets] [-configuration configurationname]
[-sdk [sdkfullpath | sdkname]] [action ...] [buildsetting=value ...] [-userdefault=value ...]

xcodebuild [-project name.xcodeproj] -scheme schemename [[-destination destinationspecifier] ...] [-destination-timeout value]
[-configuration configurationname] [-sdk [sdkfullpath | sdkname]] [action ...] [buildsetting=value ...]
[-userdefault=value ...]

xcodebuild -workspace name.xcworkspace -scheme schemename [[-destination destinationspecifier] ...] [-destination-timeout value]
[-configuration configurationname] [-sdk [sdkfullpath | sdkname]] [action ...] [buildsetting=value ...]
[-userdefault=value ...]

xcodebuild -version [-sdk [sdkfullpath | sdkname]] [infoitem]

xcodebuild -showsdks

xcodebuild -showBuildSettings [-project name.xcodeproj | [-workspace name.xcworkspace -scheme schemename]]

xcodebuild -showdestinations [-project name.xcodeproj | [-workspace name.xcworkspace -scheme schemename]]

xcodebuild -showTestPlans [-project name.xcodeproj | -workspace name.xcworkspace] -scheme schemename

xcodebuild -list [-project name.xcodeproj | -workspace name.xcworkspace]

xcodebuild -exportArchive -archivePath xcarchivepath -exportPath destinationpath -exportOptionsPlist path
xcodebuild -exportNotarizedApp -archivePath xcarchivepath -exportPath destinationpath

xcodebuild -exportLocalizations -project name.xcodeproj -localizationPath path [[-exportLanguage language] ...]
xcodebuild -importLocalizations -project name.xcodeproj -localizationPath path

DESCRIPTION
xcodebuild builds one or more targets contained in an Xcode project, or builds a scheme contained in an Xcode workspace or Xcode
project.

Usage
To build an Xcode project, run xcodebuild from the directory containing your project (i.e. the directory containing the
name.xcodeproj package). If you have multiple projects in the this directory you will need to use -project to indicate which
project should be built. By default, xcodebuild builds the first target listed in the project, with the default build configu-
ration. The order of the targets is a property of the project and is the same for all users of the project.

To build an Xcode workspace, you must pass both the -workspace and -scheme options to define the build. The parameters of the
scheme will control which targets are built and how they are built, although you may pass other options to xcodebuild to over-
ride some parameters of the scheme.

There are also several options that display info about the installed version of Xcode or about projects or workspaces in the
local directory, but which do not initiate an action. These include -list, -showBuildSettings, -showdestinations, -showsdks,
-showTestPlans, -usage, and -version.

Options
-project name.xcodeproj
Build the project name.xcodeproj. Required if there are multiple project files in the same directory.

-target targetname
Build the target specified by targetname.

-alltargets
Build all the targets in the specified project.

-workspace name.xcworkspace
Build the workspace name.xcworkspace.

-scheme schemename
Build the scheme specified by schemename. Required if building a workspace.

-destination destinationspecifier
Use the destination device described by destinationspecifier. Defaults to a destination that is compatible with the
selected scheme. See the Destinations section below for more details.

-destination-timeout timeout
Use the specified timeout when searching for a destination device. The default is 30 seconds.

-configuration configurationname
Use the build configuration specified by configurationname when building each target.

-arch architecture
Use the architecture specified by architecture when building each target.

-sdk [sdkfullpath | sdkname]
Build an Xcode project or workspace against the specified SDK, using build tools appropriate for that SDK. The argument
may be an absolute path to an SDK, or the canonical name of an SDK.

-showsdks
Lists all available SDKs that Xcode knows about, including their canonical names suitable for use with -sdk. Does not
initiate a build.

-showBuildSettings
Lists the build settings in a project or workspace and scheme. Does not initiate a build. Use with -project or -workspace
and -scheme.

-showdestinations
Lists the valid destinations for a project or workspace and scheme. Does not initiate a build. Use with -project or
-workspace and -scheme.

-showBuildTimingSummary
Display a report of the timings of all the commands invoked during the build.

-showTestPlans
Lists the test plans (if any) associated with the specified scheme. Does not initiate a build. Use with -scheme.

-list
Lists the targets and configurations in a project, or the schemes in a workspace. Does not initiate a build. Use with
-project or -workspace.

-enableAddressSanitizer [YES | NO]
Turns the address sanitizer on or off. This overrides the setting for the launch action of a scheme in a workspace.

-enableThreadSanitizer [YES | NO]
Turns the thread sanitizer on or off. This overrides the setting for the launch action of a scheme in a workspace.

-enableUndefinedBehaviorSanitizer [YES | NO]
Turns the undefined behavior sanitizer on or off. This overrides the setting for the launch action of a scheme in a
workspace.

-enableCodeCoverage [YES | NO]
Turns code coverage on or off during testing. This overrides the setting for the test action of a scheme in a workspace.

-testLanguage language
Specifies ISO 639-1 language during testing. This overrides the setting for the test action of a scheme in a workspace.

-testRegion region
Specifies ISO 3166-1 region during testing. This overrides the setting for the test action of a scheme in a workspace.

-derivedDataPath path
Overrides the folder that should be used for derived data when performing an action on a scheme in a workspace.

-resultBundlePath path
Writes a bundle to the specified path with results from performing an action on a scheme in a workspace. If the path
already exists, xcodebuild will exit with an error. Intermediate directories will be created automatically. The bundle
contains build logs, code coverage reports, XML property lists with test results, screenshots and other attachments col-
lected during testing, and various diagnostic logs.

-allowProvisioningUpdates
Allow xcodebuild to communicate with the Apple Developer website. For automatically signed targets, xcodebuild will create
and update profiles, app IDs, and certificates. For manually signed targets, xcodebuild will download missing or updated
provisioning profiles. Requires a developer account to have been added in Xcode's Accounts preference pane.

-allowProvisioningDeviceRegistration
Allow xcodebuild to register your destination device on the Apple Developer website if necessary. Requires
-allowProvisioningUpdates.

-exportArchive
Specifies that an archive should be distributed. Requires -archivePath and -exportOptionsPlist. For exporting, -exportPath
is also required. Cannot be passed along with an action.

-exportNotarizedApp
Export an archive that has been notarized by Apple. Requires -archivePath and -exportPath.

-archivePath xcarchivepath
Specifies the path for the archive produced by the archive action, or specifies the archive that should be exported when
-exportArchive or -exportNotarizedApp is passed.

-exportPath destinationpath
Specifies the destination for the exported product, including the name of the exported file.

-exportOptionsPlist path
Specifies options for -exportArchive. xcodebuild -help can print the full set of available options.

-exportLocalizations
Exports localizations to XLIFF files. Requires -project and -localizationPath. Cannot be passed along with an action.

-importLocalizations
Imports localizations from an XLIFF file. Requires -project and -localizationPath. Cannot be passed along with an action.

-localizationPath
Specifies a path to a directory or a single XLIFF localization file.

-exportLanguage language
Specifies optional ISO 639-1 languages included in a localization export. May be repeated to specify multiple languages.
May be excluded to specify an export includes only development language strings.

action ...
Specify one or more actions to perform. Available actions are:

build Build the target in the build root (SYMROOT). This is the default action, and is used if no action
is given.

build-for-testing Build the target and associated tests in the build root (SYMROOT). This will also produce an
xctestrun file in the build root. This requires specifying a scheme.

analyze Build and analyze a target or scheme from the build root (SYMROOT). This requires specifying a
scheme.

archive Archive a scheme from the build root (SYMROOT). This requires specifying a scheme.

test Test a scheme from the build root (SYMROOT). This requires specifying a scheme and optionally a
destination.

test-without-building Test compiled bundles. If a scheme is provided with -scheme then the command finds bundles in the
build root (SRCROOT). If an xctestrun file is provided with -xctestrun then the command finds bun-
dles at paths specified in the xctestrun file.

installsrc Copy the source of the project to the source root (SRCROOT).

install Build the target and install it into the target's installation directory in the distribution root
(DSTROOT).

clean Remove build products and intermediate files from the build root (SYMROOT).

-xcconfig filename
Load the build settings defined in filename when building all targets. These settings will override all other settings,
including settings passed individually on the command line.

-xctestrun xctestrunpath
Specifies test run parameters. Can only be used with the test-without-building action. Cannot be used with -workspace or
-project. See <x-man-page://5/xcodebuild.xctestrun> for file format details.

-testPlan test-plan-name
Specifies which test plan associated with the scheme should be used for testing. Pass the name of the .xctestplan file
without its extension.

-skip-testing test-identifier, -only-testing test-identifier
Constrain test targets, classes, or methods in test actions. -only-testing constrains a test action to only testing a
specified identifier, and excluding all other identifiers. -skip-testing constrains a test action to skip testing a spec-
ified identifier, but including all other identifiers. Test identifiers have the form TestTarget[/TestClass[/TestMethod]].
The TestTarget component of an identifier is the name of a unit or UI testing bundle as shown in the Test Navigator. An
xcodebuild command can combine multiple constraint options, but -only-testing has precedence over -skip-testing.

-skip-test-configuration test-configuration-name, -only-test-configuration test-configuration-name
Constrain test configurations in test actions. -only-test-configuration constrains a test action to only test a specified
test configuration within a test plan, and exclude all other test configurations. -skip-test-configuration constrains a
test action to skip a specified test configuration, but include all other test configurations. Each test configuration
name must match the name of a configuration specified in a test plan and is case-sensitive. An xcodebuild command can com-
bine multiple constraint options, but -only-test-configuration has precedence over -skip-test-configuration.

-disable-concurrent-destination-testing
Do not run tests on the specified destinations concurrently. The full test suite will run to completion on a given desti-
nation before it begins on the next.

-maximum-concurrent-test-device-destinations number
If multiple device destinations are specified (and -disable-concurrent-destination-testing is not passed), only test on
number devices at a time. For example, if four iOS devices are specified, but number is 2, the full test suite will run on
each device, but only two devices will be testing at a given time.

-maximum-concurrent-test-simulator-destinations number
If multiple simulator destinations are specified (and -disable-concurrent-destination-testing is not passed), only test on
number simulators at a time. For example, if four iOS simulators are specified, but number is 2, the full test suite will
run on each simulator, but only two simulators will be testing at a given time.

-parallel-testing-enabled [YES | NO]
Overrides the per-target setting in the scheme for running tests in parallel.

-parallel-testing-worker-count number
Spawn exactly number test runners when executing tests in parallel. Overrides -maximum-parallel-testing-workers, if it is
specified.

-maximum-parallel-testing-workers number
Limit the number of test runners that will be spawned when running tests in parallel to number.

-dry-run, -n
Print the commands that would be executed, but do not execute them.

-skipUnavailableActions
Skip actions that cannot be performed instead of failing. This option is only honored if -scheme is passed.

buildsetting=value
Set the build setting buildsetting to value.

A detailed reference of Xcode build settings can be found at: <https://help.apple.com/xcode/mac/current/#/itcaec37c2a6>

-userdefault=value
Set the user default userdefault to value.

-toolchain [identifier | name]
Use a given toolchain, specified with either an identifier or name.

-quiet
Do not print any output except for warnings and errors.

-verbose
Provide additional status output.

-version
Display version information for this install of Xcode. Does not initiate a build. When used in conjunction with -sdk, the
version of the specified SDK is displayed, or all SDKs if -sdk is given no argument. Additionally, a single line of the
reported version information may be returned if infoitem is specified.

-license
Show the Xcode and SDK license agreements. Allows for accepting the license agreements without launching Xcode itself,
which is useful for headless systems. Must be run as a privileged user.

-checkFirstLaunchStatus
Check if any First Launch tasks need to be performed.

-runFirstLaunch
Install packages and agree to the license.

-usage
Displays usage information for xcodebuild.

Destinations
The -destination option takes as its argument a destination specifier describing the device (or devices) to use as a destina-
tion. A destination specifier is a single argument consisting of a set of comma-separated key=value pairs. The -destination
option may be specified multiple times to cause xcodebuild to perform the specified action on multiple destinations.

Destination specifiers may include the platform key to specify one of the supported destination platforms. There are additional
keys which should be supplied depending on the platform of the device you are selecting.

Some devices may take time to look up. The -destination-timeout option can be used to specify the amount of time to wait before
a device is considered unavailable. If unspecified, the default timeout is 30 seconds.

Currently, xcodebuild supports these platforms:

macOS The local Mac, referred to in the Xcode interface as My Mac, and which supports the following key:

arch The architecture to use, either x86_64 (the default) or i386.

variant The optional variant to use, e.g. Mac Catalyst.

iOS An iOS device, which supports the following keys:

id The identifier of the device to use, as shown in the Devices window. A valid destination specifier must
provide either id or name, but not both.

name The name of the device to use. A valid destination specifier must provide either id or name, but not
both.

iOS Simulator A simulated iOS device, which supports the following keys:

id The identifier of the simulated device to use, as shown in the Devices window. A valid destination
specifier must provide either id or name, but not both.

name The name of the simulated device to use. A valid destination specifier must provide either id or name,
but not both.

OS When specifying the simulated device by name, the iOS version for that simulated device, such as 6.0,
or the string latest (the default) to indicate the most recent version of iOS supported by this version
of Xcode.

watchOS A watchOS app is always built and deployed nested inside of an iOS app. To use a watchOS device as your des-
tination, specify a scheme which is configured to run a WatchKit app, and specify the iOS platform destina-
tion that is paired with the watchOS device you want to use.

watchOS Simulator A watchOS Simulator app is always built and deployed nested inside of an iOS Simulator app. To use a watchOS
Simulator device as your destination, specify a scheme which is configured to run a WatchKit app, and specify
the iOS Simulator platform destination that is paired with the watchOS Simulator device you want to use.

tvOS A tvOS device, which supports the following keys:

id The identifier of the device to use, as shown in the Devices window. A valid destination specifier must
provide either id or name, but not both.

name The name of the device to use. A valid destination specifier must provide either id or name, but not
both.

tvOS Simulator A simulated tvOS device, which supports the following keys:

id The identifier of the simulated device to use, as shown in the Devices window. A valid destination
specifier must provide either id or name, but not both.

name The name of the simulated device to use. A valid destination specifier must provide either id or name,
but not both.

OS When specifying the simulated device by name, the tvOS version for that simulated device, such as 9.0,
or the string latest (the default) to indicate the most recent version of tvOS supported by this ver-
sion of Xcode.

Some actions (such as building) may be performed without an actual device present. To build against a platform generically
instead of a specific device, the destination specifier may be prefixed with the optional string "generic/", indicating that the
platform should be targeted generically. An example of a generic destination is the "Generic iOS Device" destination displayed
in Xcode's UI when no physical iOS device is present.

Testing on Multiple Destinations
When more than one destination is specified with the -destination option, xcodebuild tests on those destinations concurrently.
In this mode, xcodebuild automatically chooses the number of devices and simulators that are used simultaneously. All enabled
tests in the scheme or xctestrun file are run on each destination.

Distributing Archives
The -exportArchive option specifies that xcodebuild should distribute the archive specified by -archivePath using the options
specified by -exportOptionsPlist. xcodebuild -help can print the full set of available inputs to -exportOptionsPlist. The
product can either be uploaded to Apple or exported locally. The exported product will be placed at the path specified by
-exportPath.

Archives that have been uploaded to the Apple notary service can be distributed using the -exportNotarizedApp option. This spec-
ifies that xcodebuild should export a notarized app from the archive specified by -archivePath and place the exported product at
the path specified by -exportPath. If the archive has not completed processing by the notary service, or processing failed,
then xcodebuild will exit and emit informational or error messages.

When uploading an archive using the -exportArchive option, or exporting a notarized archive using the -exportNotarizedApp
option, an Apple ID account belonging to the archive's development team is required. Enter the credentials for the Apple ID
account using Xcode's Accounts preference pane before invoking xcodebuild.

Environment Variables
The following environment variables affect the execution of xcodebuild:

XCODE_XCCONFIG_FILE
Set to a path to a file, build settings in that file will be loaded and used when building all targets. These
settings will override all other settings, including settings passed individually on the command line, and those
in the file passed with the -xcconfig option.

Exit Codes
xcodebuild exits with codes defined by sysexits(3). It will exit with EX_OK on success. On failure, it will commonly exit with
EX_USAGE if any options appear malformed, EX_NOINPUT if any input files cannot be found, EX_IOERR if any files cannot be read or
written, and EX_SOFTWARE if the commands given to xcodebuild fail. It may exit with other codes in less common scenarios.

EXAMPLES
xcodebuild clean install

Cleans the build directory; then builds and installs the first target in the Xcode project in the directory from which
xcodebuild was started.

xcodebuild -project MyProject.xcodeproj -target Target1 -target Target2 -configuration Debug

Builds the targets Target1 and Target2 in the project MyProject.xcodeproj using the Debug configuration.

xcodebuild -target MyTarget OBJROOT=/Build/MyProj/Obj.root SYMROOT=/Build/MyProj/Sym.root

Builds the target MyTarget in the Xcode project in the directory from which xcodebuild was started, putting intermedi-
ate files in the directory /Build/MyProj/Obj.root and the products of the build in the directory
/Build/MyProj/Sym.root.

xcodebuild -sdk macosx10.6

Builds the Xcode project in the directory from which xcodebuild was started against the macOS 10.6 SDK. The canonical
names of all available SDKs can be viewed using the -showsdks option.

xcodebuild -workspace MyWorkspace.xcworkspace -scheme MyScheme

Builds the scheme MyScheme in the Xcode workspace MyWorkspace.xcworkspace.

xcodebuild archive -workspace MyWorkspace.xcworkspace -scheme MyScheme

Archives the scheme MyScheme in the Xcode workspace MyWorkspace.xcworkspace.

xcodebuild build-for-testing -workspace MyWorkspace.xcworkspace -scheme MyScheme -destination generic/platform=iOS

Build tests and associated targets in the scheme MyScheme in the Xcode workspace MyWorkspace.xcworkspace using the
generic iOS device destination. The command also writes test parameters from the scheme to an xctestrun file in the
built products directory.

xcodebuild test-without-building -workspace MyWorkspace.xcworkspace -scheme MyScheme -destination 'platform=iOS
Simulator,name=iPhone 5s' -destination 'platform=iOS,name=My iPad'

Tests the scheme MyScheme in the Xcode workspace MyWorkspace.xcworkspace using both the iOS Simulator and the device
named iPhone 5s for the latest version of iOS. The command assumes the test bundles are in the build root (SYMROOT).
(Note that the shell requires arguments to be quoted or otherwise escaped if they contain spaces.)

xcodebuild test-without-building -xctestrun MyTestRun.xctestrun -destination 'platform=iOS Simulator,name=iPhone 5s'
-destination 'platform=iOS,name=My iPad'

Tests using both the iOS Simulator and the device named iPhone 5s. Test bundle paths and other test parameters are
specified in MyTestRun.xctestrun. The command requires project binaries and does not require project source code.

xcodebuild test -workspace MyWorkspace.xcworkspace -scheme MyScheme -destination 'platform=macOS,arch=x86_64'

Tests the scheme MyScheme in the Xcode workspace MyWorkspace.xcworkspace using the destination described as My Mac
64-bit in Xcode.

xcodebuild test -workspace MyWorkspace.xcworkspace -scheme MyScheme -destination 'platform=macOS,arch=x86_64' -only-testing
MyTests/FooTests/testFooWithBar

Tests the scheme MyScheme in the Xcode workspace MyWorkspace.xcworkspace using the destination described as My Mac
64-bit in Xcode. Only the test testFooWithBar of the test suite FooTests, part of the MyTests testing bundle target,
will be run.

xcodebuild -exportArchive -archivePath MyMobileApp.xcarchive -exportPath ExportDestination -exportOptionsPlist 'export.plist'

Exports the archive MyMobileApp.xcarchive to the path ExportDestination using the options specified in export.plist.

xcodebuild -exportLocalizations -project MyProject.xcodeproj -localizationPath MyDirectory -exportLanguage zh-hans
-exportLanguage es-MX

Exports two XLIFF files to MyDirectory from MyProject.xcodeproj containing development language strings and transla-
tions for Simplified Chinese and Mexican Spanish.

xcodebuild -exportLocalizations -project MyProject.xcodeproj -localizationPath MyDirectory

Export a single XLIFF file to MyDirectory from MyProject.xcodeproj containing only development language strings. (In
this case, the -exportLanguage parameter has been excluded.)

xcodebuild -importLocalizations -project MyProject.xcodeproj -localizationPath MyLocalizations.xliff

Imports localizations from MyLocalizations.xliff into MyProject.xcodeproj. Translations with issues will be reported
but not imported.

SEE ALSO
ibtool(1), sysexits(3), xcode-select(1), xcrun(1), xed(1)

Xcode Builds Settings Reference <https://help.apple.com/xcode/mac/current/#/itcaec37c2a6>

macOS June 20, 2016 macOS
(END)

xcodebuild –help

1
xcodebuild --help
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
Usage: xcodebuild [-project <projectname>] [[-target <targetname>]...|-alltargets] [-configuration <configurationname>] [-arch <architecture>]... [-sdk [<sdkname>|<sdkpath>]] [-showBuildSettings [-json]] [<buildsetting>=<value>]... [<buildaction>]...
xcodebuild [-project <projectname>] -scheme <schemeName> [-destination <destinationspecifier>]... [-configuration <configurationname>] [-arch <architecture>]... [-sdk [<sdkname>|<sdkpath>]] [-showBuildSettings [-json]] [-showdestinations] [<buildsetting>=<value>]... [<buildaction>]...
xcodebuild -workspace <workspacename> -scheme <schemeName> [-destination <destinationspecifier>]... [-configuration <configurationname>] [-arch <architecture>]... [-sdk [<sdkname>|<sdkpath>]] [-showBuildSettings] [-showdestinations] [<buildsetting>=<value>]... [<buildaction>]...
xcodebuild -version [-sdk [<sdkfullpath>|<sdkname>] [-json] [<infoitem>] ]
xcodebuild -list [[-project <projectname>]|[-workspace <workspacename>]] [-json]
xcodebuild -showsdks [-json]
xcodebuild -exportArchive -archivePath <xcarchivepath> [-exportPath <destinationpath>] -exportOptionsPlist <plistpath>
xcodebuild -exportNotarizedApp -archivePath <xcarchivepath> -exportPath <destinationpath>
xcodebuild -exportLocalizations -localizationPath <path> -project <projectname> [-exportLanguage <targetlanguage>...[-includeScreenshots]]
xcodebuild -importLocalizations -localizationPath <path> -project <projectname>
xcodebuild -resolvePackageDependencies [-project <projectname>|-workspace <workspacename>] -clonedSourcePackagesDirPath <path>
xcodebuild -create-xcframework [-help] [-framework <path>] [-library <path> [-headers <path>]] -output <path>

Options:
-usage print brief usage
-help print complete usage
-verbose provide additional status output
-license show the Xcode and SDK license agreements
-checkFirstLaunchStatus Check if any First Launch tasks need to be performed
-runFirstLaunch install packages and agree to the license
-project NAME build the project NAME
-target NAME build the target NAME
-alltargets build all targets
-workspace NAME build the workspace NAME
-scheme NAME build the scheme NAME
-configuration NAME use the build configuration NAME for building each target
-xcconfig PATH apply the build settings defined in the file at PATH as overrides
-arch ARCH build each target for the architecture ARCH; this will override architectures defined in the project
-sdk SDK use SDK as the name or path of the base SDK when building the project
-toolchain NAME use the toolchain with identifier or name NAME
-destination DESTINATIONSPECIFIER use the destination described by DESTINATIONSPECIFIER (a comma-separated set of key=value pairs describing the destination to use)
-destination-timeout TIMEOUT wait for TIMEOUT seconds while searching for the destination device
-parallelizeTargets build independent targets in parallel
-jobs NUMBER specify the maximum number of concurrent build operations
-maximum-concurrent-test-device-destinations NUMBER the maximum number of device destinations to test on concurrently
-maximum-concurrent-test-simulator-destinations NUMBER the maximum number of simulator destinations to test on concurrently
-parallel-testing-enabled YES|NO overrides the per-target setting in the scheme
-parallel-testing-worker-count NUMBER the exact number of test runners that will be spawned during parallel testing
-maximum-parallel-testing-workers NUMBER the maximum number of test runners that will be spawned during parallel testing
-dry-run do everything except actually running the commands
-quiet do not print any output except for warnings and errors
-hideShellScriptEnvironment don't show shell script environment variables in build log
-showsdks display a compact list of the installed SDKs
-showdestinations display a list of destinations
-showTestPlans display a list of test plans
-showBuildSettings display a list of build settings and values
-list lists the targets and configurations in a project, or the schemes in a workspace
-find-executable NAME display the full path to executable NAME in the provided SDK and toolchain
-find-library NAME display the full path to library NAME in the provided SDK and toolchain
-version display the version of Xcode; with -sdk will display info about one or all installed SDKs
-enableAddressSanitizer YES|NO turn the address sanitizer on or off
-enableThreadSanitizer YES|NO turn the thread sanitizer on or off
-enableUndefinedBehaviorSanitizer YES|NO turn the undefined behavior sanitizer on or off
-resultBundlePath PATH specifies the directory where a result bundle describing what occurred will be placed
-resultStreamPath PATH specifies the file where a result stream will be written to (the file must already exist)
-resultBundleVersion 3 [default] specifies which result bundle version should be used
-clonedSourcePackagesDirPath PATH specifies the directory to which remote source packages are fetch or expected to be found
-derivedDataPath PATH specifies the directory where build products and other derived data will go
-archivePath PATH specifies the directory where any created archives will be placed, or the archive that should be exported
-exportArchive specifies that an archive should be exported
-exportNotarizedApp export an archive that has been notarized by Apple
-exportOptionsPlist PATH specifies a path to a plist file that configures archive exporting
-enableCodeCoverage YES|NO turn code coverage on or off when testing
-exportPath PATH specifies the destination for the product exported from an archive
-skipUnavailableActions specifies that scheme actions that cannot be performed should be skipped instead of causing a failure
-exportLocalizations exports completed and outstanding project localizations
-importLocalizations imports localizations for a project, assuming any necessary localized resources have been created in Xcode
-localizationPath specifies a path to XLIFF localization files
-exportLanguage specifies multiple optional ISO 639-1 languages included in a localization export
-xctestrun specifies a path to a test run specification
-testPlan specifies the name of the test plan associated with the scheme to use for testing
-only-testing constrains testing by specifying tests to include, and excluding other tests
-only-testing:TEST-IDENTIFIER constrains testing by specifying tests to include, and excluding other tests
-skip-testing constrains testing by specifying tests to exclude, but including other tests
-skip-testing:TEST-IDENTIFIER constrains testing by specifying tests to exclude, but including other tests
-only-test-configuration constrains testing by specifying test configurations to include, and excluding other test configurations
-skip-test-configuration constrains testing by specifying test configurations to exclude, but including other test configurations
-testLanguage constrains testing by specifying ISO 639-1 language in which to run the tests
-testRegion constrains testing by specifying ISO 3166-1 region in which to run the tests
-resolvePackageDependencies resolves any Swift package dependencies referenced by the project or workspace
-disableAutomaticPackageResolution prevents packages from automatically being resolved to versions other than those recorded in the `Package.resolved` file
-json output as JSON (note: -json implies -quiet)
-allowProvisioningUpdates Allow xcodebuild to communicate with the Apple Developer website. For automatically signed targets, xcodebuild will create and update profiles, app IDs, and certificates. For manually signed targets, xcodebuild will download missing or updated provisioning profiles. Requires a developer account to have been added in Xcode's Accounts preference pane.
-allowProvisioningDeviceRegistration Allow xcodebuild to register your destination device on the developer portal if necessary. This flag only takes effect if -allowProvisioningUpdates is also passed.
-showBuildTimingSummary display a report of the timings of all the commands invoked during the build
-create-xcframework create an xcframework from prebuilt libraries; -help for more information.

Available keys for -exportOptionsPlist:

compileBitcode : Bool

For non-App Store exports, should Xcode re-compile the app from bitcode? Defaults to YES.

destination : String

Determines whether the app is exported locally or uploaded to Apple. Options are export or upload. The available options vary based on the selected distribution method. Defaults to export.

embedOnDemandResourcesAssetPacksInBundle : Bool

For non-App Store exports, if the app uses On Demand Resources and this is YES, asset packs are embedded in the app bundle so that the app can be tested without a server to host asset packs. Defaults to YES unless onDemandResourcesAssetPacksBaseURL is specified.

generateAppStoreInformation : Bool

For App Store exports, should Xcode generate App Store Information for uploading with iTMSTransporter? Defaults to NO.

iCloudContainerEnvironment : String

If the app is using CloudKit, this configures the "com.apple.developer.icloud-container-environment" entitlement. Available options vary depending on the type of provisioning profile used, but may include: Development and Production.

installerSigningCertificate : String

For manual signing only. Provide a certificate name, SHA-1 hash, or automatic selector to use for signing. Automatic selectors allow Xcode to pick the newest installed certificate of a particular type. The available automatic selectors are "Mac Installer Distribution" and "Developer ID Installer". Defaults to an automatic certificate selector matching the current distribution method.

manifest : Dictionary

For non-App Store exports, users can download your app over the web by opening your distribution manifest file in a web browser. To generate a distribution manifest, the value of this key should be a dictionary with three sub-keys: appURL, displayImageURL, fullSizeImageURL. The additional sub-key assetPackManifestURL is required when using on-demand resources.

method : String

Describes how Xcode should export the archive. Available options: app-store, validation, ad-hoc, package, enterprise, development, developer-id, and mac-application. The list of options varies based on the type of archive. Defaults to development.

onDemandResourcesAssetPacksBaseURL : String

For non-App Store exports, if the app uses On Demand Resources and embedOnDemandResourcesAssetPacksInBundle isn't YES, this should be a base URL specifying where asset packs are going to be hosted. This configures the app to download asset packs from the specified URL.

provisioningProfiles : Dictionary

For manual signing only. Specify the provisioning profile to use for each executable in your app. Keys in this dictionary are the bundle identifiers of executables; values are the provisioning profile name or UUID to use.

signingCertificate : String

For manual signing only. Provide a certificate name, SHA-1 hash, or automatic selector to use for signing. Automatic selectors allow Xcode to pick the newest installed certificate of a particular type. The available automatic selectors are "Mac App Distribution", "iOS Developer", "iOS Distribution", "Developer ID Application", "Apple Distribution", "Mac Developer", and "Apple Development". Defaults to an automatic certificate selector matching the current distribution method.

signingStyle : String

The signing style to use when re-signing the app for distribution. Options are manual or automatic. Apps that were automatically signed when archived can be signed manually or automatically during distribution, and default to automatic. Apps that were manually signed when archived must be manually signed during distribtion, so the value of signingStyle is ignored.

stripSwiftSymbols : Bool

Should symbols be stripped from Swift libraries in your IPA? Defaults to YES.

teamID : String

The Developer Portal team to use for this export. Defaults to the team used to build the archive.

thinning : String

For non-App Store exports, should Xcode thin the package for one or more device variants? Available options: <none> (Xcode produces a non-thinned universal app), <thin-for-all-variants> (Xcode produces a universal app and all available thinned variants), or a model identifier for a specific device (e.g. "iPhone7,1"). Defaults to <none>.

uploadBitcode : Bool

For App Store exports, should the package include bitcode? Defaults to YES.

uploadSymbols : Bool

For App Store exports, should the package include symbols? Defaults to YES.

How to use Derived data in Xcode

Issue #543

Workspace

Workspace has its own DerivedData folder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
DerivedData
ModuleCache.noindex
workspace_name
Build
Products
Debug-iphonesimulator
Cat
Dog
Dog2
Index
Info.plist
Logs
Build
Debug
Install
Issues
Package
Test
LogStoreManifest.plist
Test-scheme_name-2019.12.15_21-08-32-+0100.xcresult
scm.plist
SourcePackages
TextIndex

Note that workspace always needs a scheme to work

1
xcodebuild: error: If you specify a workspace then you must also specify a scheme.  Use -list to see the schemes in this workspace.

Project

Project has its own DerivedData folder. If run a scheme within workspace, we see build folder for workspace. But if we open a project and run a scheme within project, we see build folder for that project.

The structure is the same, with project_name instead workspace_name

How to use test scheme in Xcode

Issue #541

Scheme action

A scheme, either for app or test, consists of actions

Run

Used when Cmd+R. The executable specifies which app target to run

Screenshot 2019-12-14 at 23 39 48

Test

Used when Cmd+U. The tests specifies which test target to run

Screenshot 2019-12-14 at 23 40 09

Test target recognises app targets via Test application and target dependency

Screenshot 2019-12-15 at 21 06 24 Screenshot 2019-12-14 at 23 40 48

When specify test scheme, we are specifying Test action in test scheme, which builds test target, and by dependency, builds app target, then run test action in test scheme, which is the UITest

1
xcodebuild -project TestApp.xcodeproj -scheme TestAppUITests test

Scheme build settings

Inspect build settings from test scheme does not work, need to specify app scheme

1
xcodebuild -workspace Animal.xcworkspace -scheme CatUITests -showBuildSettings

How to set language and locale with xcodebuild

Issue #540

testLanguage and testRegion

1
2
3
4
5
6
7
-testLanguage language
Specifies ISO 639-1 language during testing. This overrides the setting for the test action of a
scheme in a workspace.

-testRegion region
Specifies ISO 3166-1 region during testing. This overrides the setting for the test action of a
scheme in a workspace.
1
xcodebuild -project 'TestApp.xcodeproj' -scheme 'TestAppUITests' -configuration Debug -sdk iphonesimulator -UseModernBuildSystem=YES -destination 'OS=13.2.2,name=iPhone 11,platform=iOS Simulator' -testLanguage ja -testRegion ja_JP test

How to take screenshots for UITest in Xcodee

Issue #539

XCUIScreenshot

1
2
3
4
5
6
7
8
extension XCTestCase {
func takeScreenshot(name: String) {
let screenshot = XCUIScreen.main.screenshot()
let attach = XCTAttachment(screenshot: screenshot)
attach.lifetime = .keepAlways
add(attach)
}
}
Screenshot 2019-12-12 at 23 02 21

Gather screenshot for localization

xcresult from Xcode 11

xcresulttool

Test plan

Links for Xcode

Issue #499

Build setting

Build Library For Distribution

It turns on all the features that are necessary to build your library in such a way that it can be distributed

What does this error actually mean? Well, when the Swift compiler goes to import a module, it looks for a file called the Compiled Module for that library. If it finds one of these files, it reads off the manifest of public APIs that you can call into, and lets you use them. Now, this Compiled Module Format is a binary format that basically contains internal compiler data structures.

And since they’re just internal data structures, they’re subject to change with every version of the Swift Compiler. So what this means is that if one person tries to import a module using one version of Swift, and that module was created by another version of Swift, their compiler can’t understand it, and they won’t be able to use it.

Well, in order to solve this version lock, Xcode 11 introduces a new format for Swift Modules, called Swift Module Interfaces. And just like the Compiled Module Format, they list out all the public APIs of a module, but in a textual form that behaves more like source code. And since they behave like source code, then future versions of the Swift Compiler will be able to import module interfaces created with older versions. And when you enable Build Libraries for Distribution, you’re telling the compiler to generate one of these stable interfaces whenever it builds your framework

How to use Xcode

Issue #499

Build setting

Build Library For Distribution

It turns on all the features that are necessary to build your library in such a way that it can be distributed

What does this error actually mean? Well, when the Swift compiler goes to import a module, it looks for a file called the Compiled Module for that library. If it finds one of these files, it reads off the manifest of public APIs that you can call into, and lets you use them. Now, this Compiled Module Format is a binary format that basically contains internal compiler data structures.

And since they’re just internal data structures, they’re subject to change with every version of the Swift Compiler. So what this means is that if one person tries to import a module using one version of Swift, and that module was created by another version of Swift, their compiler can’t understand it, and they won’t be able to use it.

Well, in order to solve this version lock, Xcode 11 introduces a new format for Swift Modules, called Swift Module Interfaces. And just like the Compiled Module Format, they list out all the public APIs of a module, but in a textual form that behaves more like source code. And since they behave like source code, then future versions of the Swift Compiler will be able to import module interfaces created with older versions. And when you enable Build Libraries for Distribution, you’re telling the compiler to generate one of these stable interfaces whenever it builds your framework

How to configure test target in Xcode

Issue #478

This applies to

  • Main targets
    • App
    • Framework
  • Test targets
    • Unit tests
    • UI tests

Examples

Dependencies used

Examples

  • Cocoapods
  • Carthage

Notes

  • Make sure test target can link to all the frameworks it needs. This includes frameworks that Test targets use, and possibly frameworks that Main target uses !
  • Remember to “Clean Build Folder” and “Clear Derived Data” so that you’re sure it works. Sometimes Xcode caches.

Errors

Errors occur mostly due to linker error

  • Test target X encountered an error (Early unexpected exit, operation never finished bootstrapping - no restart will be attempted
  • Framework not found

Cocoapods

1. Pod

Test targets need to include pods that Main target uses !

or we’ll get “Framework not found”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def app_pods
pod 'Sugar', '~> 1.0'
end

def test_pods
pod 'Nimble', '~> 3.2'
pod 'Quick', '~> 0.9'
end

target 'TeaApp' do
app_pods
end

target 'TeaAppTests' do
app_pods
test_pods
end

target 'TeaAppUITests' do
app_pods
test_pods
end

Cocoapods builds a framework that contains all the frameworks the Test targets need, and configure it for us

3. Runpath Search Paths

  • Go to Test target Build Settings
  • Add $(FRAMEWORK_SEARCH_PATHS)

Carthage

1. Cartfile

We usually have

  • Cartfile for Main target
1
github "hyperoslo/Sugar" ~> 1.0
  • Cartfile.private for Test target
1
2
github "Quick/Nimble"
github "Quick/Quick"
  • Go to Test target build phase
  • Drag built frameworks from Carthage/Build
  • In rare case, we need to drag frameworks that the Main target uses
  • In rare case, we need to drag the Main target framework

3. Framework Search Paths

Configure correct path

  • Go to Test target Built Settings
  • Configure Framework Search Paths

4. Runpath Search Paths

  • Go to Test target Build Settings
  • Add $(FRAMEWORK_SEARCH_PATHS)

5. Copy Files (maybe)

From Adding frameworks to unit tests or a framework

In rare cases, you may want to also copy each dependency into the build product (e.g., to embed dependencies within the outer framework, or make sure dependencies are present in a test bundle). To do this, create a new “Copy Files” build phase with the “Frameworks” destination, then add the framework reference there as well.

Runpath Search Paths and Install name

Question

  • Why preconfigured run path “@executable_path/Frameworks” and “@loader_path/Frameworks” not work?
  • Why configuring runpath to “$(FRAMEWORK_SEARCH_PATHS)” works ?
  • Why framework has install name “@rpath/Sugar.framework/Sugar” ?

Reference

Code

How to use Apple certificate in Xcode 11

Issue #458

For push notification, we can now use just Production Certificate for 2 environments (production and sandbox) instead of Development and Production certificates.

Now for code signing, with Xcode 11 https://developer.apple.com/documentation/xcode_release_notes/xcode_11_release_notes we can just use Apple Development and Apple Distribution certificate for multiple platforms

Signing and capabilities settings are now combined within a new Signing & Capabilities tab in the Project Editor. The new tab enables using different app capabilities across multiple build configurations. The new capabilities library makes it possible to search for available capabilities

Xcode 11 supports the new Apple Development and Apple Distribution certificate types. These certificates support building, running, and distributing apps on any Apple platform. Preexisting iOS and macOS development and distribution certificates continue to work, however, new certificates you create in Xcode 11 use the new types. Previous versions of Xcode don’t support these certificates

How to run app on beta iOS devices

Issue #343

Xcode 10.3 with iOS 13

1
sudo ln -s /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/13.0 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

Xcode 10.3 with iOS 13.1 beta 2

1
sudo ln -s /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/13.0/ /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/13.1

Use DeviceSupport

1
/Applications/Xcode/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

How to convert your Xcode plugins to Xcode extensions

Issue #267

Original post https://medium.freecodecamp.org/how-to-convert-your-xcode-plugins-to-xcode-extensions-ac90f32ae0e3


Xcode is an indispensable IDE for iOS and macOS developers. From the early days, the ability to build and install custom plugins had given us a huge boost in productivity. It was not long before Apple introduced Xcode extension due to privacy concerns.

I have built a few Xcode plugins and extensions like XcodeWay, XcodeColorSense, XcodeColorSense2, and Xmas. It was a rewarding experience. I learned a lot, and the productivity I gained was considerable. In this post I walkthrough how I converted my Xcode plugins to extensions, and the experience I had in doing so.

My first Xcode plugin: XcodeWay

I choose a lazy person to do a hard job. Because a lazy person will find an easy way to do it

I really like the above quote from Bill Gates. I try to avoid repetitive and boring tasks. Whenever I find myself doing the same tasks again, I write scripts and tools to automate that. Doing this takes some time, but I will be a bit lazier in the near future.

Besides the interest in building open source frameworks and tools, I like to extend the IDE I’m using — mostly Xcode.

I first started iOS development in 2014. I wanted a quick way to navigate to many places right from Xcode with the context of the current project. There are many times we want to:

  • open the current project folder in “Finder” to change some files

  • open Terminal to run some commands

  • open the current file in GitHub to quickly give the link to a workmate

  • or to open other folders like themes, plugins, code snippets, device logs.

Every little bit of time we save each day counts.

I thought it would be cool idea to write an Xcode plugin that we can do all above things right inside Xcode. Instead of waiting for other people to do it, I pulled up my sleeve and wrote my first Xcode plugin — XcodeWay— and shared it as open source.

XcodeWay works by creating a menu under Editor with lots of options to navigate to other places right from Xcode. It looks simple but there was some hard work required.XcodeWay works by creating a menu under Editor with lots of options to navigate to other places right from Xcode. It looks simple but there was some hard work required.

What are Xcode plugins?

Xcode plugins are not officially supported by Xcode or recommended by Apple. There are no documents about them. The best places we can learn about them are via existing plugins’ source code and a few tutorials.

An Xcode plugin is just a bundle of type xcplugin and is placed at ~/Library/Application Support/Developer/Shared/Xcode/Plug-ins . Xcode, when starting, will load any Xcode plugins present in this folder. Plugins are run in the same process as Xcode, so could do anything as Xcode. A bug in any plugin can cause Xcode to crash.

To make an Xcode plugin, create a macOS Bundle with one class that extends from NSObject , and have an initialiser that accepts NSBundle , for example in Xmas:

class Xmas: NSObject {

  var bundle: NSBundle

  init(bundle: NSBundle) {
    self.bundle = bundle
    super.init()
  }
}

Inside Info.plist, we need to:

  • declare this class as the main entry class for the plugin, and

  • that this bundle has no UI, because we create UI controls and add to the Xcode interface during runtime

    NSPrincipalClass
    Xmas
    XCPluginHasUI

Another problem with Xcode plugins is that we have to continuously update DVTPluginCompatibilityUUIDs . This changes every time a new version of Xcode comes out. Without updating, Xcode will refuse to load the plugin.

What Xcode plugins can do

Many developers build Xcode plugins because they miss specific features found in other IDEs like Sublime Text, AppCode, or Atom.

Since Xcode plugins are loaded in the same process as Xcode, they can do everything that Xcode can. The only limit is our imagination. We can leverage Objective C Runtime to discover private frameworks and functions. Then LLDB and Symbolic breakpoint can be used further to inspect running code and alter their behaviors. We can also use swizzling to change implementation of any running code. Writing Xcode plugins is hard — lots of guessing, and sometimes a good knowledge of assembly is required.

In the golden age of plugins, there was a popular plugin manager, which itself was a plugin, called Alcatraz. It could install other plugins, which basically just downloads the xcplugin file and moves this to the Plug Ins folder.

To get a sense of what plugins can do, let’s take a look at some popular plugins.

Xvim

First in the list is Xvim, which adds Vim keybindings right inside Xcode. It supports mostly all of the keybindings that we used to have in Terminal.

SCXcodeMiniMap

If you miss MiniMap mode in Sublime Text, you can use SCXcodeMiniMap to add a right map panel inside Xcode editor.

FuzzyAutocompletePlugin

Before version 9, Xcode didn’t have proper auto completion — it was just based on prefix. That was where FuzzyAutocompletePlugin shone. It performs fuzzy auto completion based on the hidden IDEOpenQuicklyPattern feature in Xcode.

KSImageNamed-Xcode

To display a bundle image inside UIImageView, we often use the imageNamed method. But remembering exactly the name of the image file is hard. KSImageNamed-Xcode is here to help. You will get a list of auto-suggested image names when you begin to type.

ColorSense-for-Xcode

Another itch during development is to work with UIColor , which uses RGBA color space. We don’t get a visual indicator of the color that we specify, and manually performing checking can be time consuming. Luckily there is ColorSense-for-Xcode which shows the color being used and the color picker panel to easily select the right color.

LinkedConsole

In AppCode, we can jump to a specific line in the file that is logged inside the console. If you miss this feature in Xcode, you can use LinkedConsole. This enables clickable links inside Xcode console so we can jump to that file instantly.

The hard work behind Xcode plugins

Making an Xcode plugin is not easy. Not only do we need to know macOS programming, but we also need to dive deep into Xcode view hierarchy. We need to explore private frameworks and APIs in order to inject the feature we want.

There are very few tutorials on how to make plugins but, luckily, most plugins are open source so we can understand how they work. Since I have made a few plugins, I can give some technical details about them.

Xcode plugins are done usually with two private frameworks: DVTKit and IDEKit . System frameworks are at /System/Library/PrivateFrameworks but the frameworks that Xcode uses exclusively are under /Applications/Xcode.app/Contents/ , there you can find Frameworks , OtherFrameworks and SharedFrameworks.

There is a tool class-dump that can generate headers from the Xcode app bundle. With the class names and methods, you can call NSClassFromString to get the class from the name.

Swizzling DVTBezelAlertPanel framework in Xmas

Christmas has always given me a special feeling, so I decided to make Xmas, which shows a random Christmas picture instead of the default alert view. The class used to render that view is DVTBezelAlertPanel inside the DVTKit framework. My article on building that plugin is here.

With Objective C Runtime, there is a technique called swizzling, which can change and switch implementation and method signature of any running classes and methods.

Here, in order to change the content of that alert view, we need to swap the initialiser initWithIcon:message:parentWindow:duration: with our own method. We do that early by listening to NSApplicationDidFinishLaunchingNotification which is notified when a macOS plugin, in this case Xcode, launches.

class func swizzleMethods() {
    guard let originalClass = NSClassFromString("DVTBezelAlertPanel") as? NSObject.Type else {
        return
    }

do {
        try originalClass.jr_swizzleMethod("initWithIcon:message:parentWindow:duration:",
            withMethod: "xmas_initWithIcon:message:parentWindow:duration:")
    }
    catch {
        Swift.print("Swizzling failed")
    }
}

I initially liked to do everything in Swift. But it’s tricky to use the swizzle init method in Swift, so the quickest way is to do that in Objective C. Then we simply traverse the view hierarchy to find the NSVisualEffectView inside NSPanel to update the image.

Interacting with DVTSourceTextView in XcodeColorSense

I work mostly with hex colors and I want a quick way to see the color. So I built XcodeColorSense — it supports hex color, RGBA, and named color.

The idea is simple. Parse the string to see if the user is typing something related to UIColor, and show a small overlay view with that color as background. The text view that Xcode uses is of type DVTSourceTextView in DVTKit framework. We also need to listen to NSTextViewDidChangeSelectionNotification which is triggered whenever any NSTextView content is changed.

func listenNotification() {
  NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(handleSelectionChange(_:)), name: NSTextViewDidChangeSelectionNotification, object: nil)
}

func handleSelectionChange(note: NSNotification) {
  guard let DVTSourceTextView = NSClassFromString("DVTSourceTextView") as? NSObject.Type,
    object = note.object where object.isKindOfClass(DVTSourceTextView.self),
    let textView = object as? NSTextView
  else { return }

self.textView = textView
}

I had a Matcher architecture so we can detect different kinds of UIColor constructions — for example HexMatcher .

public struct HexMatcher: Matcher {

func check(line: String, selectedText: String) -> (color: NSColor, range: NSRange)? {
    let pattern1 = "\"#?[A-Fa-f0-9]{6}\""
    let pattern2 = "0x[A-Fa-f0-9]{6}"

let ranges = [pattern1, pattern2].flatMap {
      return Regex.check(line, pattern: $0)
    }

guard let range = ranges.first
      else { return nil }

let text = (line as NSString).substringWithRange(range).replace("0x", with: "").replace("\"", with: "")
    let color = NSColor.hex(text)

return (color: color, range: range)
  }
}

To render the overlay, we use NSColorWell which is good for showing a view with background. The position is determined by calling firstRectForCharacterRange and some point conversions with convertRectFromScreen and convertRect .

Using NSTask and IDEWorkspaceWindowController in XcodeWay

Finally, my beloved XcodeWay.

I found myself needing to go to different places from Xcode with the context of the current project. So I built XcodeWay as a plugin that adds lots of handy menu options under Window.

Since the plugin runs in the same Xcode process, it has access to the main menu NSApp.mainMenu?.itemWithTitle(“Window”) . There we can alter the menu. XcodeWay is designed to easily extend functionalities through its Navigator protocol.

[@objc](http://twitter.com/objc) protocol Navigator: NSObjectProtocol {
  func navigate()
  var title: String { get }
}

For folders with a static path like Provisioning Profile ~/Library/MobileDevice/Provisioning Profiles or User data Developer/Xcode/UserData , we can just construct the URL and call NSWorkspace.sharedWorkspace().openURL . For dynamic folders that vary depending on the current project, more work needs to be done.

How do we open the folder for the current project in Finder? The information for the current project path is kept inside IDEWorkspaceWindowController . This is a class that manages workspace windows in Xcode. Take a look at EnvironmentManager where we use objc_getClass to get the class definition from a string.

self.IDEWorkspaceWindowControllerClass = objc_getClass("IDEWorkspaceWindowController");

NSArray *workspaceWindowControllers = [self.IDEWorkspaceWindowControllerClass valueForKey:@"workspaceWindowControllers"];

id workSpace = nil;

for (id controller in workspaceWindowControllers) {
  if ([[controller valueForKey:@"window"] isEqual:[NSApp keyWindow]]) {
    workSpace = [controller valueForKey:@"_workspace"];
  }
}

NSString * path = [[workSpace valueForKey:@"representingFilePath"] valueForKey:@"_pathString"];

Finally, we can utilise valueForKey to get the value for any property that we think exists. This way not only do we get the project path, we also get the path to the opening file. So we can call activateFileViewerSelectingURLs on NSWorkspace to open Finder with that file selected. This is handy as users don’t need to look for that file in Finder.

Many times we want to execute some Terminal commands on the current project folder. To achieve that, we can use NSTask with launch pad /usr/bin/open and arguments [@”-a”, @”Terminal”, projectFolderPath] . iTerm, if configured probably, will open this in a new tab.

The documents for iOS 7 apps are placed in the fixed location iPhone Simulator inside Application Support. But, from iOS 8, every app has a unique UUID and their document folders are hard to predict.

~/Library/Developer/CoreSimulator/Devices/1A2FF360-B0A6-8127-95F3-68A6AB0BCC78/data/Container/Data/Application/

We can build a map and perform tracking to find the generated ID for the current project, or to check the plist inside each folder to compare the bundle identifier.

The quick solution that I came up with was to search for the most recent updated folder. Every time we build the project, or make changes inside the app, their document folder is updated. That is where we can make use of NSFileModificationDate to find the folder for the current project.

There are many hacks when working with Xcode plugins, but the results are rewarding. Every few minutes we save each day end up saving a lot of time overall.

Security and freedom

With great power comes great responsibility. The fact that plugins can do whatever they want rings an alert to security. In late 2015, there was a malware attack by distributing a modified version of Xcode, called XcodeGhost, which injects malicious code into any apps built with Xcode Ghost. The malware is believed to use the plugin mechanism among other things.

Like the iOS apps we download from the Appstore, macOS apps like Xcode are signed by Apple when we download them from the Mac Appstore or through official Apple download links.

Code signing your app assures users that it is from a known source and the app hasn’t been modified since it was last signed. Before your app can integrate app services, be installed on a device, or be submitted to the App Store, it must be signed with a certificate issued by Apple

To avoid potential malware like this, at WWDC 2016 Apple announced the Xcode Source Editor Extension as the only way to load third party extensions into Xcode. This means that, from Xcode 8, plugins can’t be loaded.

Source Editor Extension

Extension is the recommended approach to safely add functionalities in restricted ways.

App extensions give users access to your app’s functionality and content throughout iOS and macOS. For example, your app can now appear as a widget on the Today screen, add new buttons in the Action sheet, offer photo filters within the Photos app, or display a new system-wide custom keyboard.

For now, the only extension to Xcode is Source Editor, which allows us to read and modify contents of a source file, as well as read and modify the current text selection within the editor.

Extension is a new target and runs in a different process than Xcode. This is good in that it can’t alter Xcode in any ways other than conforming to XCSourceEditorCommand to modify the current document content.

protocol XCSourceEditorCommand {

  func perform(with invocation: [XCSourceEditorCommandInvocation](https://developer.apple.com/documentation/xcodekit/xcsourceeditorcommandinvocation), 
completionHandler: @escaping ([Error](https://developer.apple.com/documentation/swift/error)?) -> [Void](https://developer.apple.com/documentation/swift/void))
}

Xcode 8 has lots of improvements like the new code completion features, Swift image and color literals, and snippets. This led to the deprecation of many Xcode plugins. For some indispensable plugins like XVim, this is unbearable for some people. Some old plugin features can’t be achieved with the current Source Editor Extension system.

Unless you resign Xcode

A workaround to bypass the restriction from Xcode 8 for plugins, is to replace the existing Xcode signature by a technique called resign. Resigning is very easy — we just need to create a self-signed certificate and call the codesign command. After this, Xcode should be able to load plugins.

codesign -f -s MySelfSignedCertificate /Applications/Xcode.app

It is, however, not possible to submit apps built with resigned Xcode as the signature does not match the official version of Xcode. One way is to use two Xcodes: one official for distribution and one resigned for development.

Moving to Xcode extension

Xcode extension is the way to go, so I started moving my plugins to extension. For Xmas, since it modifies view hierarchy, it can’t become an extension.

Color literal in XcodeColorSense2

For the color sense, I rewrote the extension from scratch, and called it XcodeColorSense2. This, of course, can’t show an overlay over the current editor view. So I chose to utilize the new Color literal found in Xcode 8+.

The color is shown in a small box. It may be hard to distinguish similar colors, so that’s why I also include the name. The code is simply about inspecting selections and parsing to find the color declaration.

func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: [@escaping](http://twitter.com/escaping) (Error?) -> Void ) -> Void {
    guard let selection = invocation.buffer.selections.firstObject as? XCSourceTextRange else {
      completionHandler(nil)
      return
    }

let lineNumber = selection.start.line

guard lineNumber < invocation.buffer.lines.count,
      let line = invocation.buffer.lines[lineNumber] as? String else {
      completionHandler(nil)
      return
    }

guard let hex = findHex(string: line) else {
      completionHandler(nil)
      return
    }

let newLine = process(line: line, hex: hex)

invocation.buffer.lines.replaceObject(at: lineNumber, with: newLine)

completionHandler(nil)
  }
}

Most of the functionality is embedded inside my framework Farge, but I can’t find a way to use the framework inside Xcode extension.

Since the extension feature is only accessible through the Editor menu, we can customise a key binding to invoke this menu item. For example I choose Cmd+Ctrl+S to show and hide color information.

This is, of course, not intuitive compared to the original plugin, but it’s better than nothing.

How to debug Xcode extensions

Working and debugging extensions is straightforward. We can use Xcode to debug Xcode. The debugged version of Xcode has a gray icon.

How to install Xcode extensions

The extension must have an accompanying macOS app. This can be distributed to Mac Appstore or self-signed. I’ve written an article on how to do this.

All extensions for an app need to be explicitly enabled through “System Preferences”.

The Xcode extension only works with editor for now, so we must open a source file for the Editor menu to have effect.

AppleScript in XcodeWay

In Xcode extensions, NSWorkspace, NSTask and private class construction don’t work anymore. Since I have used Finder Sync Extension in FinderGo, I thought I could try the same AppleScript scripting for Xcode extension.

AppleScript is a scripting language created by Apple. It allows users to directly control scriptable Macintosh applications, as well as parts of macOS itself. You can create scripts — sets of written instructions — to automate repetitive tasks, combine features from multiple scriptable applications, and create complex workflows.

To try AppleScript, you can use the app Script Editor built inside macOS to write prototype functions. Function declaration starts with on and ends with end . To avoid potential conflicts with system functions, I usually use my as a prefix. Here is how I rely on System Events to get the home directory.

User interface scripting terminology is found in the “Processes Suite” of the “System Events” scripting dictionary. This suite includes terminology for interacting with most types of user interface elements, including:

  • windows

  • buttons

  • checkboxes

  • menus

  • radio buttons

  • text fields.

In System Events, the process class represents a running app.

Many good citizen apps support AppleScript by exposing some of their functionalities, so these can be used by other apps. Here is how I get the current song from Spotify in Lyrics.

tell application "Spotify"
  set trackId to id of current track as string
  set trackName to name of current track as string
  set artworkUrl to artwork url of current track as string
  set artistName to artist of current track as string
  set albumName to album of current track as string
  return trackId & "---" & trackName & "---" & artworkUrl & "---" & artistName & "---" & albumName
end tell

To get all the possible commands of a certain app, we can open the dictionary in Script Editor. There we can learn about which functions and parameters are supported.

If you think Objective C is hard, AppleScript is much harder. The syntax is verbose and error-prone. For your reference, here is the whole script file that powers XcodeWay.

To open a certain folder, tell Finder using POSIX file. I refactor every functionality into function for better code reuse.

on myOpenFolder(myPath)
tell application "Finder"
activate
open myPath as POSIX file
end tell
end myOpenFolder

Then, to run AppleScript inside a macOS app or extension, we need to construct an AppleScript descriptor with the correct process serial number and event identifiers.

func eventDescriptior(functionName: String) -> NSAppleEventDescriptor {
  var psn = ProcessSerialNumber(highLongOfPSN: 0, lowLongOfPSN: UInt32(kCurrentProcess))
  let target = NSAppleEventDescriptor(
    descriptorType: typeProcessSerialNumber,
    bytes: &psn,
    length: MemoryLayout<ProcessSerialNumber>.size
  )

let event = NSAppleEventDescriptor(
    eventClass: UInt32(kASAppleScriptSuite),
    eventID: UInt32(kASSubroutineEvent),
    targetDescriptor: target,
    returnID: Int16(kAutoGenerateReturnID),
    transactionID: Int32(kAnyTransactionID)
  )

let function = NSAppleEventDescriptor(string: functionName)
  event.setParam(function, forKeyword: AEKeyword(keyASSubroutineName))

return event
}

Other tasks, like checking the current Git remote, are a bit trickier. Many times I want to share the link of the file I’m debugging to my remote teammate, so they know what file I’m referencing. This is doable by using shell script inside AppleScript .

on myGitHubURL()
set myPath to myProjectPath()
set myConsoleOutput to (do shell script "cd " & quoted form of myPath & "; git remote -v")
set myRemote to myGetRemote(myConsoleOutput)
set myUrl to (do shell script "cd " & quoted form of myPath & "; git config --get remote." & quoted form of myRemote & ".url")
set myUrlWithOutDotGit to myRemoveSubString(myUrl, ".git")
end myGitHubURL

We can use quoted and string concatenation to form strings. Luckily we can expose Foundation framework and certain classes. Here is how I expose NSString to take advantage of all existing functionalities. Writing string manipulation from scratch using plain AppleScript will take lots of time.

use scripting additions
use framework "Foundation"
property NSString : a reference to current application's NSString

With this we can build our other functions for string handling.

on myRemoveLastPath(myPath)
set myString to NSString's stringWithString:myPath
set removedLastPathString to myString's stringByDeletingLastPathComponent
removedLastPathString as text
end myRemoveLastPath

One cool feature that XcodeWay supports is the ability to go to the document directory for the current app in the simulator. This is handy when we need to inspect a document to check saved or cached data. The directory is dynamic so it’s hard to detect. We can, however, sort the directory for the most recently updated. Below is how we chain multiple shell scripts commands to find the folder.

on myOpenDocument()
set command1 to "cd ~/Library/Developer/CoreSimulator/Devices/;"
set command2 to "cd `ls -t | head -n 1`/data/Containers/Data/Application;"
set command3 to "cd `ls -t | head -n 1`/Documents;"
set command4 to "open ."
do shell script command1 & command2 & command3 & command4
end myOpenDocument

This feature helped me a lot when developing Gallery to check whether videos and downloaded images are saved in the correct place.

However, none of the scripts seem to work. Scripting has always been part of macOS since 1993. But, with the advent of the Mac Appstore and security concerns, AppleScript finally got restricted in mid 2012. That was when App Sandbox was enforced.

App Sandbox

App Sandbox is an access control technology provided in macOS, enforced at the kernel level. It is designed to contain damage to the system and the user’s data if an app becomes compromised. Apps distributed through the Mac App Store must adopt App Sandbox.

For an Xcode extension to be loaded by Xcode, it must also support App Sandbox.

At the beginning of App Sandbox enforcement, we could use App Sandbox Temporary Exception to temporarily grant our app access to Apple Script.

This is now not possible.

The only way for AppleScript to run is if it resides inside ~/Library/Application Scripts folder.

How to install custom scripts

macOS apps or extensions can’t just install scripts into the Application Scripts by themselves. They need user consent.

One possible way to do that is to enable Read/Write and show a dialog using NSOpenPanel to ask user to select the folder to install our scripts.

For XcodeWay, I choose to provide an install shell script so the user has a quick way to install scripts.

#!/bin/bash

set -euo pipefail

DOWNLOAD_URL=[https://raw.githubusercontent.com/onmyway133/XcodeWay/master/XcodeWayExtensions/Script/XcodeWayScript.scpt](https://raw.githubusercontent.com/onmyway133/XcodeWay/master/XcodeWayExtensions/Script/XcodeWayScript.scpt)
SCRIPT_DIR="${HOME}/Library/Application Scripts/com.fantageek.XcodeWayApp.XcodeWayExtensions"

mkdir -p "${SCRIPT_DIR}"
curl $DOWNLOAD_URL -o "${SCRIPT_DIR}/XcodeWayScript.scpt"

AppleScript is very powerful. All of this is made explicit so the user has complete control over which things can be done.

Like an extension, a script is done asynchronously in a different process using XPC for inter process communication. This enhances security as a script has no access to the address space to our app or extension.

More security in macOS Mojave

This year, at WWDC 2018, Apple introduced macOS Mojave which focuses on lots of security enhancements. In the Your Apps and the Future of macOS Security we can learn more about new security requirement for macOS apps. One of them is the usage description for AppleEvents.

unable to load info.plist exceptions (egpu overrides)

We used to declare usage description for many permissions in iOS, like photo library, camera, and push notifications. Now we need to declare the usage description for AppleEvents.

Source: [https://www.felix-schwarz.org/blog/2018/08/new-apple-event-apis-in-macos-mojave](https://www.felix-schwarz.org/blog/2018/08/new-apple-event-apis-in-macos-mojave)Source: https://www.felix-schwarz.org/blog/2018/08/new-apple-event-apis-in-macos-mojave

The first time our extension tries to execute some AppleScript commands, the above dialog is shown to ask for user consent. User can grant or deny permission, but for Xcode please say yes 🙏

The fix for us is to declare NSAppleEventsUsageDescription in our app target. We only need to declare in the app target, not in the extension target.

<key>NSAppleEventsUsageDescription</key>
<string>Use AppleScript to open folders</string>

Where to go from here

Huff huff, whew! Thanks for following such a long journey. Making frameworks and tools take lots of time, especially plugins and extensions — we have to continuously change to adapt them to new operating systems and security requirements. But it is a rewarding process, as we’ve learned more and have some tools to save our precious time.

For your reference, here are my extensions which are fully open source.

I hope you find something useful in the post. Here are some resources to help explore Xcode extensions further:

How to fix mismatched deployment between app and test target in Xcode

Issue #204

  • My macOS app target has deployment target 10.12, but when running test, I get
1
Compiling for OS X 10.11, but module 'MyApp' has a minimum deployment target of OS X 10.12: /Users/khoa/MyApp/DerivedData/MyApp/Build/Products/Debug/MyApp.framework/Modules/MyApp.swiftmodule/x86_64.swiftmodule
  • The fix is go to test target -> Build Settings -> Deployment
    Ensure deployments match
build

How to use shared AppGroup UserDefaults in macOS and Xcode extension

Issue #201

  • Go to both app and extension target, under Capabilities, enable AppGroup

  • Specify $(TeamIdentifierPrefix)group.com.onmyway133.MyApp

  • $(TeamIdentifierPrefix) will expand to something like T78DK947F3., with .

  • Then using is like a normal UserDefaults

1
2
3
4
let defaults = UserDefaults(suiteName: "T78DK947F3 .group.com.onmyway133.MyApp")

defaults?.set(true, forKey: "showOptions")
defaults?.synchronize()

Using CircleCI 2.0

Issue #158

We ‘ve been using CircleCI for many of our open source projects. Since the end of last year 2017, version 2.0 began to come out, and we think it’s good time to try it now together with Swift 4.1 and Xcode 9.3

The problem with version 2.0 is it’s so powerful and has lots of cool new features like jobs and workflows, but that requires going to documentation for how to migrate configuration file, especially Search and Replace Deprecated 2.0 Keys

Creating config.yml

The first thing is to create a new config.yml inside folder .circleci

Copy your existing circle.yml file into a new directory called .circleci at the root of your project repository.

Next is to declare version and jobs

Add version: 2 to the top of the .circleci/config.yml file.

Checking xcodebuild

For simple cases, we just use xcodebuild to build and test the project, so it’s good to try it locally to avoid lots of trial commits to trigger CircleCI. You can take a look at this PR https://github.com/hyperoslo/Cheers/pull/20

Before our configuration file for version 1.0 looks like this

1
- set -o pipefail && xcodebuild -project Cheers.xcodeproj -scheme "Cheers-iOS" -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 8,OS=11.0' -enableCodeCoverage YES test

Now we should put pipefail inside shell, follow https://github.com/CircleCI-Public/circleci-demo-ios/blob/master/.circleci/config.yml

shell: /bin/bash –login -o pipefail

Now is the actual trying xcodebuild, after many failures due to destination param

1
2
3
4
5
6
xcodebuild: error: Unable to find a destination matching the provided destination specifier:
{ platform:iOS Simulator, OS:11.3 }

Missing required device specifier option.
The device type “iOS Simulator” requires that either “name” or “id” be specified.
Please supply either “name” or “id”.
1
xcodebuild: error: option 'Destination' requires at least one parameter of the form 'key=value'

I found this to work, run this in the same folder as your xcodeproj

1
xcodebuild -project Cheers.xcodeproj -scheme "Cheers-iOS" -sdk iphonesimulator -destination "platform=iOS Simulator,OS=11.3,name=iPhone X" -enableCodeCoverage YES test

Adding workflow

Version 2.0 introduces workflow which helps organising jobs

A workflow is a set of rules for defining a collection of jobs and their run order. Workflows support complex job orchestration using a simple set of configuration keys to help you resolve failures sooner.

For our simple use cases, we add this workflow

1
2
3
4
5
workflows:
version: 2
build-and-test:
jobs:
- build-and-test

Collecting Test Metadata

CircleCI collects test metadata from XML files and uses it to provide insights into your job

Final

Use below as template

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: 2.1
jobs:
build_test:
macos:
xcode: "11.0"
shell: /bin/bash --login -o pipefail
steps:
- checkout
- run:
command: |
curl https://cocoapods-specs.circleci.com/fetch-cocoapods-repo-from-s3.sh | bash -s cf
pod install
- run:
command: xcodebuild -workspace MyApp.xcworkspace -scheme "MyApp" -sdk iphonesimulator -destination "platform=iOS Simulator,name=iPhone X,OS=12.2" -enableCodeCoverage YES test
- store_test_results:
path: test-results

workflows:
version: 2.1
primary:
jobs:
- build_test

Read more