nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
fork

Configure Feed

Select the types of activity you want to include in your feed.

at release-20.03 229 lines 8.1 kB view raw view rendered
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```