The Deployment Process
One of the first things I noticed when I first started getting involved in the development of an iOS application is just how insanely complex the deployment process is to a newcomer. Even regardless of me having to get my head around new programming languages (Objective C and Swift) and new APIs, the bigger hurdle was Xcode itself.
At first I was the liaison with the outsourced mobile app development agency. Every few weeks the agency would do a ‘Testflight’ build for us to try out. We’d give feedback and that would be rolled into their development as they went along. Speaking to them, the actual process of testing, building and deploying a release would take one of their developers most of an afternoon to do. Trying to get the releases more frequent would just tie up a valuable developer for longer.
Eventually we moved the development of the app in-house. We recruited a developer to work on the project. I was now more involved in the actual day-to-day management of the development process. And this was when I started to realised just how complex the deployment can be. The developer was fantastic and helped me to understand things a great deal, but the process of actually deploying the app was cumbersome.
I tried to do a build myself from Xcode. This required me to have the right certificates, keys, and provisioning profiles to work. Several times Xcode would come up with some error about the provisioning profile and just ask me if I wanted it to ‘fix it’. If I hit the button to fix it, it just went away and did it’s magic. I had no idea what it was actually doing. I just pressed an hoped. Sometimes it worked, sometimes it didn’t. In talking to other iOS developers this seemed like ‘normal’ behaviour. Most of them didn’t really know what was going on. They just hit the button in Xcode and hopes for the best. Kudos to Apple for hiding all the details and letting people get on with the task at hand, developing software, but when things went wrong it is hard to work out.
One of the main issues was that often a build would work on our developer’s machine, but not on mine. Or it would work on my desktop, but not my laptop. They should work the same. They had the same code checked out from Github, but alas one would work and one would not.
The time came for us to start hiring more developers, and soon we had a team of four developers working on the app, plus myself, a UX person, and a graphic designer. How would be handle the deployment process? In order to build the app we had to ensure that they keys and certificates required were on the machine the develop building it was using. Not only that, but we were developing in Swift, which takes forever to compile. A build could take up to half an hour to build on a modern machine. That is time that a developer is sat there with their machine ground to a halt compiling.
What we needed
We needed a deployment mechanism. We needed an automated way for the builds to happen independent of any one developer. We needed to ensure we didn’t need to distribute our company distribution key to everyone involved. It would be great if the process could happen automatically and frequently so that anyone could test out a build. This is not like the world of web development, where you can simply allow anyone with a browser to your dev/staging server. In order for someone to test a build they need to be able to access a properly signed app with their device’s UDID encoded in the provisioning profile.
The previous incarnation of the app had very little in the way of unit tests, and this was something I wanted to change too. All the developers we hired had a very strong interest in testing, and I needed to make it as easy as possible for their tests to be run.
We bought a small Mac Mini to sit in the office and act as our build server. In order to build iOS apps you need to be on a physical Mac. Alas you can’t use a VM or similar. We needed a way to automate the build process and so ended up assembling a number of tools to do so.
Tools we used
This is where all out code it stored. It is a number of private Github repos. At one point we were evaluating Github Enterprise, which was one of the reasons I wanted to have more control over the build server, rather than use one of the nascent cloud-based iOS build services.
Fastlane is a set of tools to interact with Apple’s developer services via the command line. I first heard about it from a talk by the author of the tools, Felix Krause, at NSConf 7 in Leicester, UK. He has done a remarkable job of making sane ways to interact with the App store process in a automatable way.
Jenkins is an Continuos Integration (CI) tool. I was familiar with it from previous projects I’d worked on, such as Plone. Jenkins can monitor Github and when code is pushed to github it can check it out and run automated tests on the code. In our case we wanted to take it further, and not just run the tests, but actually build and deploy the app.
Hockey and TestFlight are two services that allow you to do deployments of apps to testers. Hockey (derived from the term ‘adhoc’ as one of the three types of provisioning profile Apple allow) is a 3rd party service. It also allows you to capture crash reports from devices. If the app crashes on a user’s phone then the next time they start the app it sends the crash report to Hockey. Hockey allows you to then browse the stack trace and other crash debugging information.
TestFlight is a similar service to Hockey, but now owned by Apple themselves. Rather then using an ‘adhoc’ provisioning profile, you actually use a ‘store’ profile and upload the app to iTunes Connect in a similar way to if you were submitting a final app to Apple for the App Store. By marking the app as ‘beta’ in the upload process it allows you to distribute the pre-release app to testers.
Slack is our internal communications tool. When a build happens on Jenkins the status of the tests and build and the link to the download are posted to Slack for the team to see.
In the next post I’ll go into more detail about Fastlane.Go Top