fork
Configure Feed
Select the types of activity you want to include in your feed.
nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
fork
Configure Feed
Select the types of activity you want to include in your feed.
1---
2title: iOS
3author: Sander van der Burg
4date: 2019-11-10
5---
6# iOS
7
8This component is basically a wrapper/workaround that makes it possible to
9expose an Xcode installation as a Nix package by means of symlinking to the
10relevant executables on the host system.
11
12Since Xcode can't be packaged with Nix, nor we can publish it as a Nix package
13(because of its license) this is basically the only integration strategy
14making it possible to do iOS application builds that integrate with other
15components of the Nix ecosystem
16
17The primary objective of this project is to use the Nix expression language to
18specify how iOS apps can be built from source code, and to automatically spawn
19iOS simulator instances for testing.
20
21This component also makes it possible to use [Hydra](https://nixos.org/hydra),
22the Nix-based continuous integration server to regularly build iOS apps and to
23do wireless ad-hoc installations of enterprise IPAs on iOS devices through
24Hydra.
25
26The Xcode build environment implements a number of features.
27
28Deploying a proxy component wrapper exposing Xcode
29--------------------------------------------------
30The first use case is deploying a Nix package that provides symlinks to the Xcode
31installation on the host system. This package can be used as a build input to
32any build function implemented in the Nix expression language that requires
33Xcode.
34
35```nix
36let
37 pkgs = import <nixpkgs> {};
38
39 xcodeenv = import ./xcodeenv {
40 inherit (pkgs) stdenv;
41 };
42in
43xcodeenv.composeXcodeWrapper {
44 version = "9.2";
45 xcodeBaseDir = "/Applications/Xcode.app";
46}
47```
48
49By deploying the above expression with `nix-build` and inspecting its content
50you will notice that several Xcode-related executables are exposed as a Nix
51package:
52
53```bash
54$ ls result/bin
55lrwxr-xr-x 1 sander staff 94 1 jan 1970 Simulator -> /Applications/Xcode.app/Contents/Developer/Applications/Simulator.app/Contents/MacOS/Simulator
56lrwxr-xr-x 1 sander staff 17 1 jan 1970 codesign -> /usr/bin/codesign
57lrwxr-xr-x 1 sander staff 17 1 jan 1970 security -> /usr/bin/security
58lrwxr-xr-x 1 sander staff 21 1 jan 1970 xcode-select -> /usr/bin/xcode-select
59lrwxr-xr-x 1 sander staff 61 1 jan 1970 xcodebuild -> /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild
60lrwxr-xr-x 1 sander staff 14 1 jan 1970 xcrun -> /usr/bin/xcrun
61```
62
63Building an iOS application
64---------------------------
65We can build an iOS app executable for the simulator, or an IPA/xcarchive file
66for release purposes, e.g. ad-hoc, enterprise or store installations, by
67executing the `xcodeenv.buildApp {}` function:
68
69```nix
70let
71 pkgs = import <nixpkgs> {};
72
73 xcodeenv = import ./xcodeenv {
74 inherit (pkgs) stdenv;
75 };
76in
77xcodeenv.buildApp {
78 name = "MyApp";
79 src = ./myappsources;
80 sdkVersion = "11.2";
81
82 target = null; # Corresponds to the name of the app by default
83 configuration = null; # Release for release builds, Debug for debug builds
84 scheme = null; # -scheme will correspond to the app name by default
85 sdk = null; # null will set it to 'iphonesimulator` for simulator builds or `iphoneos` to real builds
86 xcodeFlags = "";
87
88 release = true;
89 certificateFile = ./mycertificate.p12;
90 certificatePassword = "secret";
91 provisioningProfile = ./myprovisioning.profile;
92 signMethod = "ad-hoc"; # 'enterprise' or 'store'
93 generateIPA = true;
94 generateXCArchive = false;
95
96 enableWirelessDistribution = true;
97 installURL = "/installipa.php";
98 bundleId = "mycompany.myapp";
99 appVersion = "1.0";
100
101 # Supports all xcodewrapper parameters as well
102 xcodeBaseDir = "/Applications/Xcode.app";
103}
104```
105
106The above function takes a variety of parameters:
107* The `name` and `src` parameters are mandatory and specify the name of the app
108 and the location where the source code resides
109* `sdkVersion` specifies which version of the iOS SDK to use.
110
111It also possile to adjust the `xcodebuild` parameters. This is only needed in
112rare circumstances. In most cases the default values should suffice:
113
114* Specifies which `xcodebuild` target to build. By default it takes the target
115 that has the same name as the app.
116* The `configuration` parameter can be overridden if desired. By default, it
117 will do a debug build for the simulator and a release build for real devices.
118* The `scheme` parameter specifies which `-scheme` parameter to propagate to
119 `xcodebuild`. By default, it corresponds to the app name.
120* The `sdk` parameter specifies which SDK to use. By default, it picks
121 `iphonesimulator` for simulator builds and `iphoneos` for release builds.
122* The `xcodeFlags` parameter specifies arbitrary command line parameters that
123 should be propagated to `xcodebuild`.
124
125By default, builds are carried out for the iOS simulator. To do release builds
126(builds for real iOS devices), you must set the `release` parameter to `true`.
127In addition, you need to set the following parameters:
128
129* `certificateFile` refers to a P12 certificate file.
130* `certificatePassword` specifies the password of the P12 certificate.
131* `provisioningProfile` refers to the provision profile needed to sign the app
132* `signMethod` should refer to `ad-hoc` for signing the app with an ad-hoc
133 certificate, `enterprise` for enterprise certificates and `app-store` for App
134 store certificates.
135* `generateIPA` specifies that we want to produce an IPA file (this is probably
136 what you want)
137* `generateXCArchive` specifies thet we want to produce an xcarchive file.
138
139When building IPA files on Hydra and when it is desired to allow iOS devices to
140install IPAs by browsing to the Hydra build products page, you can enable the
141`enableWirelessDistribution` parameter.
142
143When enabled, you need to configure the following options:
144
145* The `installURL` parameter refers to the URL of a PHP script that composes the
146 `itms-services://` URL allowing iOS devices to install the IPA file.
147* `bundleId` refers to the bundle ID value of the app
148* `appVersion` refers to the app's version number
149
150To use wireless adhoc distributions, you must also install the corresponding
151PHP script on a web server (see section: 'Installing the PHP script for wireless
152ad hoc installations from Hydra' for more information).
153
154In addition to the build parameters, you can also specify any parameters that
155the `xcodeenv.composeXcodeWrapper {}` function takes. For example, the
156`xcodeBaseDir` parameter can be overridden to refer to a different Xcode
157version.
158
159Spawning simulator instances
160----------------------------
161In addition to building iOS apps, we can also automatically spawn simulator
162instances:
163
164```nix
165let
166 pkgs = import <nixpkgs> {};
167
168 xcodeenv = import ./xcodeenv {
169 inherit (pkgs) stdenv;
170 };
171in
172xcode.simulateApp {
173 name = "simulate";
174
175 # Supports all xcodewrapper parameters as well
176 xcodeBaseDir = "/Applications/Xcode.app";
177}
178```
179
180The above expression produces a script that starts the simulator from the
181provided Xcode installation. The script can be started as follows:
182
183```bash
184./result/bin/run-test-simulator
185```
186
187By default, the script will show an overview of UDID for all available simulator
188instances and asks you to pick one. You can also provide a UDID as a
189command-line parameter to launch an instance automatically:
190
191```bash
192./result/bin/run-test-simulator 5C93129D-CF39-4B1A-955F-15180C3BD4B8
193```
194
195You can also extend the simulator script to automatically deploy and launch an
196app in the requested simulator instance:
197
198```nix
199let
200 pkgs = import <nixpkgs> {};
201
202 xcodeenv = import ./xcodeenv {
203 inherit (pkgs) stdenv;
204 };
205in
206xcode.simulateApp {
207 name = "simulate";
208 bundleId = "mycompany.myapp";
209 app = xcode.buildApp {
210 # ...
211 };
212
213 # Supports all xcodewrapper parameters as well
214 xcodeBaseDir = "/Applications/Xcode.app";
215}
216```
217
218By providing the result of an `xcode.buildApp {}` function and configuring the
219app bundle id, the app gets deployed automatically and started.
220
221Troubleshooting
222---------------
223In some rare cases, it may happen that after a failure, changes are not picked
224up. Most likely, this is caused by a derived data cache that Xcode maintains.
225To wipe it you can run:
226
227```bash
228$ rm -rf ~/Library/Developer/Xcode/DerivedData
229```