Acorn Heroes

Setting up an Automated Build in an iOS environment – part 3

by on Sep.03, 2010, under Coding, Project Management

In my previous articles, we’ve looked at how we can set up an automatic build, with a focus on catching issues with bad check-ins immediately.  Another useful aspect of an automated build is that it can remove the chance of human error whenever we have a task that consists of a lot of manual steps.

One such example is generating a build for ad-hoc distribution to beta testers.  We could create a build by hand, but if we forget to increment the version number in our project, then our testers won’t be able to update from a previous build unless they delete the old build by hand off their devices and iTunes – definitely a pain for people you don’t want to inconvenience.

 

Also, imagine the scenario in a couple of weeks when a tester notifies you of a serious bug they’ve found.  Chances are the code you have now is quite different to the build they have.  Can you get back to that point in the code easily?

Fortunately Apple provide us with a handy tool called agvtool that can handle these situations for us.  It’s a command line tool, so it integrates nicely into Hudson.  But first let’s look at agvtool on its own, and see what we can do with it.

agvtool

In order for agvtool to do its magic, we have a few things to set up in our project first.  Most of the steps here are described in detail by Jamie Montgomerie on his blog.  Briefly though, we will use two different version numbers – a release version and a build number.  The release version is our “marketing” number – what our clients see (“Now updated to version 1.2!”).  Our build number is for internal use, and will connect a given instance of our App to a specific tagged version of our code in source control. To test this, I created a simple OpenGL project in Xcode and added it to SVN as a starting point.  The only modification I’ve made to it is to add a label on top of the GL view.  We will use this later to display our build number for testers.  Note that SVN is not necessary for using agvtool, but it will give us a few nice options down the track.

 

So, following Jamie’s instructions, we:

  1. Open our project’s PROJECT_NAME-Info.plist file and set the Bundle version to 1.  This represents our build number.
  2. Ctrl (or right) click on the plist and choose Add Row.  From the options presented, select Bundle versions string, short and set its initial value to (say) 0.1.  This is our release version.
  3. Ctrl (or right) click on the project in the Groups & Files window, and select Get Info.  Make sure you’ve selected All Configurations and find the Versioning section, near the bottom.  Set the Current Project Version to match you build number – 1 in our case.  Set the Versioning system to apple-generic.

OK, not too painful and we’ll never need to touch these bits again!  Let’s test our a few things.  Open up a terminal window and cd to your project directory.  We can use agvtool to tell us both the current build and release version numbers (agvtool calls them version and marketing version respectively):

 

WhatVersions.png

You should see the build number (agvtool what-version) and release version (agvtool what-marketing-version) that you entered into the project settings.  Now, using agvtool we can also update our build and release version numbers.  Note that doing this modifies your project, so ensure it’s either not open in XCode or everything has been saved – otherwise you may lose changes to your project such as settings or newly added files. So, to increment our build number we use:

agvtool bump -all

Bump.png

On the slightly rarer occasion that we want to adjust our release version, this can be done as follows:

agvtool new-marketing-version 0.21b

ReleaseBump.png

 

You can use the agvtool what- command to verify what’s going on here.  Note that our build number is automatically incremented by one using the bump command.  Our release version is in fact a string, and we can supply whatever we want there, in this case 0.21b.

Assuming you’re paranoid like me, now is a good time to check this into source control as we have all the basics covered.

Open the project in XCode and build it.  XCode will now automatically generate a .c file as part of the build.  In my case, these were found at:

build/AutoVersionTest.build/Debug-iphonesimulator/AutoVersionTest.build/DerivedSources/AutoVersionTest_vers.c

You don’t need to even open this file, or include them in your project (that happens automatically).  This file declares two variables, a version string and number that correspond to our build number.  We can put them to good use.  In my sample project, I’ve declared the build number as an external variable in my App delegate:

extern const double AutoVersionTestVersionNumber;

And then in my application: didFinishLaunchingWithOptions method I’ve used the build number on the label I added earlier:

versionLabel.text = [NSString stringWithFormat:@"Build: %1.0f",AutoVersionTestVersionNumber, nil];

Now when testers run my App they’ll see something like this:

BuildId.png

Now, a tester can easily identify the build they’re running when giving me feedback.  By the way – if anyone know an easy way to get at our release version number in code, please let me know!  What we need now is a simple way to tie that back to a specific version of our code…

 

Tagging in SVN

Note, this also works with CVS as well, however while there are good arguments for not moving to a more modern system like Git or Mercurial, there’s no good argument for sticking with CVS.

 

agvtool has the ability to update our version information and then commit the changes, simply by adding the usesvn tag like so:

agvtool -usesvn bump -all

Commit.png

Nice.  But it gets better.  We can then tag these changes to make getting back to them simple:

agvtool -usesvn tag -baseurlfortag http://URL/to/svn/AutoVersionTest/tags

Tagged.png

The -baseurlfortag option specifies where the tag should go.  After this operation, you’re SVN repository should look something like this:

svn.png

Now, when you receive feedback from a tester it’s a simple matter to check out the tagged code and you can track down issues with the same code base your tester was using.  Note that the folder specified by the -baseurlfortag option must already exist – agvtool will not create it for you.

 

And Hudson?

Hopefully it’s not too much of a stretch from here to see how we can use this in Hudson (or any other automated build system).  First off, we should create a project in Hudson that will check out our code and build it.  If you already have an existing Hudson project that builds periodically or with each new check-in you can simply clone it (Hudson is good that way).  Configure the project to only build manually by unchecking all the build triggers:

 

NoTriggers.png

And add in new build step(s), calling agvtool to bump our build number and (if using SVN) tag the resulting build.  Note that if this project were set up to trigger a new build when check-ins are detected we have a potential race condition, with agvtool checking in changes which would trigger a new build which would make agvtool check in changes….

So, with these changes in place we can now reliably build a version of our code for testers, tag it and know that we can come back to the code for that build at any time.  And it’s all done automatically.  Also our version numbers will always increase, insuring that our testers don’t have trouble updating to a newer build.

 

And Another Thing

OK, I haven’t played with this one extensively yet, but will add it here for your consideration.  Hudson allows us to add parameters to a build.  When we start a build, it will ask us to supply parameters that affect the build.  As an example we can add a BuildNumber parameter that will decide which tagged version of our code we want.  Configuring it in Hudson will look something like this:

 

Parameter.png

So what’s the use of this?  Well the parameter becomes an environment variable when Hudson is building the project.  So we can slip the environment variable into our source control link.  This way, when we kick off a build we can specify the tag to use, making it easy to recreate our App as it was at any stage in its development.

Well that’s it for this week.  If you have any questions or feedback please leave a comment below.

This post is part of iDevBlogADay, a group of indie iPhone development blogs featuring two posts per day. You can keep up with iDevBlogADay through the web siteRSS feed, or Twitter.

Share with friends:
  • Print
  • email
  • RSS
  • Facebook
  • Twitter
  • Google Bookmarks
  • Digg
  • Reddit
  • StumbleUpon
  • del.icio.us

Related posts:

  1. Setting up an Automated Build in an iOS environment – part 4
  2. Setting up an Automated Build in an iOS environment – part 2
  3. Setting up an Automated Build in an iOS environment
  4. Setting up an Automated Build in an iOS environment – part 5
:, , ,

3 Comments for this entry

  • Brandon

    Nice article. I’ve been using agvtool for awhile, but mostly doing it manually to bump build numbers. I really should add it to my automated build process for when preparing a beta.

    You asked if there is a way to access the version number in code. You can access your info.plist’s dictionary with [[NSBundle mainBundle] infoDictionary], then the keys you are looking for are:

    Release version: CFBundleShortVersionString
    Build #: CFBundleVersion

  • George

    Glad you like the article. And thanks for the tip about bundle settings – now I can generate “proper” build ids :)

  • Ken Carpenter

    Further to Brandon’s comment above, I use the following line to update a label with my version number:

    // Set the version label
    [versionLabel setText:[NSString stringWithFormat:@"V%@",[[NSBundle mainBundle] objectForInfoDictionaryKey:@”CFBundleShortVersionString”]]];

Leave a Reply