Getting your app in front of real users as soon as possible is very important. They will use the app in ways you hadn’t even thought of, and uncover hidden bugs and gotchas. My current beta distribution platform of choice is Testflight. I keep meaning to try HockeyApp, but everyone else here at M&S uses Testflight making it the path of least resistance. Again this is very important as you want it to be as easy as possible for testers to install your app. This is the tale of getting new betas out to testers as painlessly as possible.
The most basic way of uploading builds to Testflight is by creating an archive using Xcode (Product > Archive) then uploading it using the web uploader. This is a tedious manual process involving a whole lot of clicking. We can do better.
For a while I used Testflight’s Mac menubar app, which intelligently watches for any archives you make using Xcode and then offers to upload them. The app then steps you through the process of selecting a provisioning profile, writing release notes, and finally uploading. This removes some friction from the process, but again involves a lot of clicking and hassle. Again, we can do better.
In steps the prolific Matt Thompson who has written an excellent collection of command line tools for automating various aspects of iOS development and distribution called Nomad. The specific tool we want is called Shenzhen, and allows you to build archives on the command line and distribute them to Testflight (and HockeyApp and FTP). After a quick gem install shenzhen
, we can simply
(Or we could do ipa distribute:testflight
, but distribute
defaults to Testflight)
As someone who loves the command line this fills me with delight, no more dicking around filling out forms and clicking on boxes, just straight terminal goodness. But wait! You guessed it, we can do better.
Rather than typing (well, copypasting) in our Testflight API token and team token each time, we can feed them to ipa
using the --team-token
and --API-token
flags. To do so we’ll wrap up ipa
in our own little bash script that contains our Testflight credentials, like so1
You can find your API token and your team token here and here respectively. Note we could use the flags -a
and -T
for the API and team tokens respectively, but I prefer to use the full versions in scripts for readability purposes.
Frequently when I come to write releases notes for new build I forget a lot of the new things in that particular build. To help this I like to write release notes as I go, popping them in a releasenotes.txt
file. Conveniently ipa
includes a --notes
option, which you can pass release notes into. Lets update our script, taking care to deal with the case where we don’t have any release notes.
Another pain point for me is accidentally distributing a build with the wrong provisioning profile. We can get our script to help us with this, the simplest way being bailing if the right provisioning profile isn’t set in our project.pbxproj
file.
Its quick, its dirty, but it works and thats the most important thing. I’d quite like the script to automatically set the correct provisioning profile for me, but thats a challenge for future me.
Finally, we can add a bit of messaging to indicate the script’s progress (with added ticks and crosses and colours) and use the ipa
flags --lists
and --notify
to set permissions for the build and notify testers. The final script in all its glory looks like this
Hope this helps you get betas of your app out there quicker and I’d love to hear any suggestions for improvements. Find me at @neilkimmett or email me at neil@kimmett.me.
Update
It turns out theres a much nicer way of specifying a provisioning profile to use. xcodebuild
(which ipa
uses under the hood) uses a PROVISIONING_PROFILE
environment variable, which we can add to the top of our script and get rid of that messy grep
business. Much nicer:
Update 2
So it turns out that the wrong provisioning profile was sometimes still sneaking its way into the build. Fear not, I have a new tactic to stop this: a bit of sed
magic. sed
is a standard Unix tool for doing find-and-replace in a file. What we need to find is a line like PROVISIONING_PROFILE = "stuff";
in our project.pbxproj
file, and replace it with PROVISIONING_PROFILE = "our actual provisioning profile";
. We can do this with this incantation:
This uses regular expressions. The -E
flag tells OS X’s sed
to use the extended regular expression syntax. The bit after the first /
is what we’re looking for, and the bit after the second /
is what to replace it with. The .
in our pattern means “match any character” (except a line break). The *
means “match the previous character zero or more times”. Combined .*
matches our provisioning profile hash. We can slot this sed
wizardry into the rest of our script, and we should finally have the One True Release script: