Chapter 3. Automating iOS Builds

One of the constants of the Enterprise universe is that, almost before you have your first line of code written, someone will be asking you to set up automated nightly builds with regression testing. And I’m not disagreeing with the practice, because nothing will get a project in trouble faster than the “it worked on my desktop” syndrome. Automated builds are a good way to keep developers honest, and they also can provide a single place for your testing team to get builds to bang on.

And the good news is, with a little bit of finesse, you can get your iOS builds automated, and never have to worry about it again. Apple doesn’t make it easy to do, not so much because the tools aren’t there, but that it can be a scavenger hunt through forums, sparse documentation, and third-party web-sites to find out exactly how to make it tick. What we’ll do in this chapter is to go through the entire process from start to end, so that hopefully you can do it without having to dive into all the research.

Introducing Hudson

There are no lack of build automation systems available these days, and any attempt to cover them all would be far outside the scope of this book. Instead, we’ll look at one popular, open-source build system, called Hudson. Java developers are probably familiar with Hudson, since it is one of the leading tools for build automation in that space. But Hudson can be used for just about any type of build, and if you haven’t already chosen a system, I’d make a strong recommendation for Hudson. But regardless of what build system you plan to use, the tips about how to execute builds from the command line (which is the heart of automating an iOS build) should be valid.

Hudson was pioneered at Sun, and was acquired by Oracle as part of their purchase of Sun. Due to some political turmoil between Oracle and the Hudson developer community, a forked version of Hudson called Jenkins was created, which is (for the moment) entirely compatible with Hudson. In the summer of 2011, Oracle donated Hudson to the Eclipse Foundation—whether this will allow a reconciliation with the Jenkins crowd is yet to be seen.

Hudson is written in Java, and although it isn’t required, prefers to use the Ant build tool as the method to execute builds. Since Ant can do just about anything, including running command line scripts, it is a totally reasonable choice for automating iOS builds.

Breaking the News to Your IT Department

Maybe you’re one of the lucky few, and your company has fully embraced the Apple work, with Mac Pros and Macbooks as far as the eye can see. More likely, you’re living in la vida Microsoft, with a purchasing department used to buying low-priced Wintel boxes whenever anyone needs a development machine, and perhaps a Dell or HP server when you need a heavy-duty build machine.

If you’ve started doing iOS development inside your company, and you’re not using personal equipment, you’ve probably already had to break the news to them that you can only really develop iOS applications on Apple hardware (we’ll ignore the world of the Hackintosh, as that’s even less likely to meet with approval from IT than true Apple gear).

Well, now you get to go back to them and explain that if they want automated builds, they’re going to have to go back to their piggy-bank and pony up the funds for another Mac of some variety, because you can’t build iOS applications on anything but a Mac either. Unless you’re doing an absurdly large amount of builds, you don’t need much of one though. At my day job, we do just fine with a mid-range iMac, reserving the heavy-duty Mac Pros for developers. In fact, this one machine is now running not only our iOS builds (for about 10 different code branches), but also our Android, Blackberry and J2ME feature phone builds!

There are rumblings that there may be ways soon to run Mac OS X Server in a virtual environment on non-Apple hardware, so that’s something to keep an eye out for, but at the moment, you should start getting the hardware for a dedicated build machine in the purchasing pipeline if you expect to do automated builds. For the same reason that having developers produce builds is a bad idea, running automated builds on a machine that is also used for development is a bad idea.

Provisioning Your Build Machine

Before we get into the nuts and bolts of setting up Hudson, we need to make sure that the basics for iOS development are available on your new server. Primarily, this means installing the latest production version of Xcode. You can either copy the disk image that you used to install Xcode on your development machine, or download a fresh copy from the iOS Developer Site. You can now also buy a copy of XCode via the Mac App store.

A quick note about version compatibility of Xcode is worth mentioning here. At one point, Apple had Xcode 3.2, Xcode 4.0 and a beta of Xcode 4.1 all available for download at the same time from the developer site. It is easy to imagine that you could end up with situations where developers were using one version of Xcode, while the build machine was running a different version.

By and large, this is not an issue. While you never want to have your build machine running a beta version of Xcode (you can’t upload apps built with it to the App Store, for one thing), I’ve generally found that Xcode has been fairly forgiving of mix and match Xcode versions dealing with the same project files. The big (and nasty) exception is that if you use features that are only available in the beta, and then try to open the project in an older version, anything could happen. But, for example, at the moment I am developing at home using the latest Xcode beta, checking in my files and having them work without a hitch in Xcode 4.1 on our build machine. The one big gotcha is that you may want to start building using the GM version a week or so before the new version of iOS is released, so you can have a version in the store at launch time. If you bought your copy of XCode via the Mac App store, rather than downloading it from the developer portal, you won’t be able to update it until the new version of XCode is formally released.

The other (and unpleasant) things you’ll need to keep in sync between development and build machines are the provisioning profiles and certificates. There are a number of reasons that these can go out of sync. For one, every time you add someone to your Ad Hoc profile (which will be discussed in more detail in Chapter 7), you end up with a new profile, which you need to reference in your project file. If your build machine doesn’t have a copy of this profile (or the backing certificate) in the keychain, the build will fail. We’ll discuss this later in this chapter in more detail. If you’re doing both an Enterprise and Ad Hoc/App Store build, things can get very, very complicated, because of keychain conflicts. This is also discussed in Chapter 7.

Installing Hudson

Once you have Xcode installed and running (a good test is to check out your project as a logged in user on the build machine, and make sure that you can build and run the app), it’s time to install the build automation tool (in this case, Hudson).

Although I haven’t said it explicitly, the requirement that you must build iOS apps on Mac hardware means that your build automation tool must be able to deal with Mac OS X. In the case of Hudson, this isn’t an issue, since it’s a pure Java tool. Other proprietary tools may work with Macs, or may have client plug-ins that let your remotely run a build on a Mac. If your tool can’t communicate with a Mac in any way, you’re kinda out of luck, and may have to sell your build automation group on letting you use a tool such as Hudson instead.

All the tools in this section require Java. Java used to be installed as part of the Mac OS X install, but starting with Lion, it needs to be installed explicitly, you can download the latest version of Java for Lion from Apple.

Begin by downloading Hudson from http://hudson-ci.org/. They have native packages for Linux systems but not, alas, MacOS. What they have is a WAR file, which is a Java Web Application Archive, meant to be dropped into a Java web server such as Tomcat. Tomcat doesn’t have an installer for Mac OS X either, so you need to download the “core” Tomcat zip file from http://tomcat.apache.org/. You can probably download the most recent shipping version safely, but if in doubt, the Hudson site should list the compatible versions of Tomcat.

Once you’ve unzipped the Tomcat archive, you should end up with a directory hierarchy that looks something like this:

tomcat
     --> bin
     --> conf
     --> lib
     --> logs
     --> temp
     --> webapps
     --> work

Place the Hudson WAR file in the Tomcat webapps directory, and then change directories to the Tomcat bin directory, and run startup.sh. You should see terminal output that looks like this:

~Tom Tom$ cd ./tomcat/bin
bin Tom$ ./startup.sh 
Using CATALINA_BASE:   /Volumes/Homes/Tom/tomcat
Using CATALINA_HOME:   /Volumes/Homes/Tom/tomcat
Using CATALINA_TMPDIR: /Volumes/Homes/Tom/tomcat/temp
Using JRE_HOME:   /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
Using CLASSPATH:       /Volumes/Homes/Tom/tomcat/bin/bootstrap.jar

Give Tomcat and Hudson a few minutes to start up, and then you should be able to browse to http://localhost:8080/hudson, and get a screen resembling the one in Figure 3-1.

The Hudson screen on first time startup
Figure 3-1. The Hudson screen on first time startup

Again, an entire book could be written about the many ways you can customize Hudson, so it won’t be covered in any detail here. For example, you can set up users and permissions, have Tomcat (and thus Hudson) start automatically when the Mac boots, and much more. For the scope of this book, we’re going to focus on creating a Hudson job to build our application automatically.

Creating the Build Job

For the remainder of this chapter, we’re going to assume that you have an Xcode project checked into a source control system, as outlined in the last chapter. Since the entire point of automating your builds is to take the most recent version of your project under source control and create a build of the app from it, it is obviously a prerequisite.

I’ve set up a repository on github that has all the examples in this book, as well as the tools and utilities mentioned. You can check a read-only copy out of git by using the repository URL:

git://github.com/blackbear/enterprise-ios-applications.git

With Hudson up and running, we can start implementing our automated build. Helpfully, Hudson places a link to what we want to do right at the upper left hand corner, New Job. If you click on that link, you’re brought to an intermediate page that asks you to name your job, and select what type of build it is (see Figure 3-2). For the purposes of this walk-through, we won’t look into these options in detail, just give the build a name (BuggyWhipBuild) and set it up as a freestyle project.

Creating a new job in Hudson
Figure 3-2. Creating a new job in Hudson

The Main Configuration Screen

Once that page is submitted, you’re brought to a longer page where you will configure the build (Figure 3-3). Especially when you are first starting out with Hudson, it is a good idea to take things step by step, rather than try to get it all working at once, so that’s the approach we’ll take. The first section of the configuration has four checkboxes, which we can discuss briefly.

The main build configuration screen
Figure 3-3. The main build configuration screen

Discard old builds

If you leave this box unchecked, Hudson will keep every build ever made until you run out of disk space. Usually, you only want a few builds available (perhaps as many as a month’s worth, but probably not more). By checking this box, you will be given the option to select the number of days back or number of builds to keep. You can also choose (using the advanced checkbox) to select a different number of days to keep artifacts (the finished output products) of builds, which in the case of an iOS build would be things such as test results and IPA files.

This build is parameterized

This is an option you will almost never use with automated builds, because it will cause the build to prompt the user for parameters that will be passed into the build process. Obviously, this isn’t practical for builds designed to run unattended.

Disable build

This item is self-explanatory. If it is checked, scheduled builds will not occur.

Execute concurrent builds

Again, not an option you are likely to need—it allows Hudson to run multiple builds simultaneously, if the resources have been configured to allow for it. If you wish to do it, there shouldn’t be an issue doing this with Xcode builds.

Advanced options

In general, a stand-alone iOS build project should not need to set these options. They deal with cross-build dependencies, how often to retry failed builds, and what directory to perform the build in. You can ignore them for the moment.

Source Code Management with Hudson

The next section of the configuration screen deals with source code management. Specifically, it deals with how to check out the project so that a build can be performed on it. On the Hudson website, there is a long list of SCM systems that can be integrated into Hudson using plug-ins, including git, Mercurial, Visual SourceSafe, MKS, and many others. For the purposes of this example, we’ll stick with our existing CVS project that we used in the previous chapter. If you click on the CVS radio button, a new section expands out (Figure 3-4).

Configuring CVS in Hudson
Figure 3-4. Configuring CVS in Hudson

To make this work, all we need to do is set the CVSROOT to the appropriate directory, the module to the module name of our project (BuggyWhipChat), and optionally decide which branch we wish to check out (if none is provided, the main trunk is checked out for CVS).

Obviously, depending on which source control system you use, you will end up providing different parameters to this section, but the idea remains the same: you will end up with a copy of your Xcode project checked out and ready to be built.

Before we go any further, let’s make sure that the piece we’ve done so far is working correctly. With the SCM section filled out, you have enough done to try running the project. At the bottom of the page, press the Save button, which will return you to a view of your build (Figure 3-5).

The initially configured iOS build
Figure 3-5. The initially configured iOS build

Trying Your First Build

To try out the build, all you need to do is click on the Build Now link in the left-hand side list of links, A progress bar will appear under the Build History heading, and a few seconds later, the build will be complete and a link to the finished build will appear in the history. If you click on the link, and then click on Console Output link on the next page, you can see what happened under the covers.

Started by user anonymous
[BuggyWhipBuild] $ cvs -Q -z0 -d /usr/local/CVS co -P 
    -d workspace -D "Monday, July 11, 2011 12:40:39 AM UTC" buggywhipchat
$ no changes detected
Finished: SUCCESS

Since all the job did was to check the sources out of CVS, there wasn’t much excitement to be seen. If you look in your home directory, you will see a hidden directory called .hudson. Walking down the directories to .hudson/jobs/BuggyWhipBuild/workspace, you’ll see a copy of your project checked out and waiting for you to build it. So now we’re set to actually start playing with Xcode and making some apps!

Creating an Ant Build File

As has been previously mentioned, Hudson prefers to use Ant as the build tool to build projects. That’s not to say that this is your only choice: you could almost as easily use GnuMake or any other tool that can be executed from the command line. But really, there’s no reason not to use Ant, unless you’re violently opposed to it for some reason. As opposed to gmake, which tends to be finicky on random characters in the file and can be a bit arcane to understand, Ant uses XML files that can be edited and validated in any standard XML editor. It will also make all your Java friends happy, because Ant is the build tool of choice for Java.

Ant build files can get quite complex, but they don’t need to. All you really need is a single file called build.xml, and that’s the file we’re about to create. Example 3-1 shows a very simple build.xml file that does absolutely nothing.

Example 3-1. A simple build file
<?xml version="1.0" encoding="utf-8"?>
<project name="Buggy Whip Builder" default="debugbuild" basedir=".">
   <target name="debugbuild">
      <echo message="Debug Build Will Go Here"/>
   </target>
</project>

Let’s break the file down line by line. The first line is a standard XML header. The next line, which uses the project tag, defines the name of the project that is associated with this build file, the default target (debugbuild) that the file builds if given no arguments, and the base directory that all commands will be executed relative to.

With this file placed in the root of the CVS project (which, you may remember, has the BuggyWhipChat and ChatAPI directories as subdirectories), we can run Ant from the command line and see the build script work:

tom Tom:buggywhipchat$ ant
Buildfile: /Volumes/Homes/Tom/buggwhipchat/build.xml

debugbuild:
     [echo] Debug Build Will Go Here

BUILD SUCCESSFUL
Total time: 0 seconds

Testing xcodebuild

I know it seems like we’ve spent a lot of time discussing non-Xcode stuff, but now that we’ve assured ourselves that the basic Ant script is working, we can start to actually wire up Xcode to the build. Making command-line builds work comes down to understanding a few basic commands that are included in the developer SDK. The star of the show is xcodebuild, which you can find in the /Developer/usr/bin directory. The basic format of the command is:

xcodebuild [-project projectname] [-target targetname] ...
[-configuration configurationname] [buildaction] ...

There is an alternate format that is used if you are dealing with workspaces:

xcodebuild [-workspace workspacename] [-scheme schemename] ...
[-configuration configurationname] [buildaction] ...

The major difference is that the workspace version replaces the project and target specifications with the more “modern” workspace and scheme ones.

Since we’re working with a workspace-based project, we’ll be using the second form of the command. Before trying to integrate it into our build system, we should make sure that we can run the command correctly, directly from the command line:

buggywhipchat Diane$ /Developer/usr/bin/xcodebuild -workspace 
  BuggyWhipChat.xcworkspace -scheme BuggyWhipChat build
=== BUILD NATIVE TARGET ChatAPI OF PROJECT ChatAPI WITH CONFIGURATION Debug ===
Check dependencies   
.
.
.
=== BUILD NATIVE TARGET BuggyWhipChat OF PROJECT BuggyWhipChat WITH CONFIGURATION Debug ===
Check dependencies
.
.
.
/usr/bin/codesign --force --sign "iPhone Developer: Diane Coder (UU7RPZZZZZ)" 
** BUILD SUCCEEDED **

So, the first good news is that the build worked. But what exactly happened? We can start by looking at the command we executed. We specified the workspace we wanted to use (which is in the current directory, the same one that has the build.xml file in it. The scheme we asked for is the BuggyWhipChat scheme, which is the standard scheme that builds a debug build. Finally, we asked for a build action of build (which, by the way, is the default). We’ll look at some of the other build actions later on—there are also a number of other arguments that you can pass to xcodebuild that will allow you to tweak the build settings that you normally set via the Xcode project inspector. If you’re interested, running man xcodebuild from the command line will give you the information in detail.

Integrating xcodebuild into an Ant Script

The next step is to take the xcodebuild command that worked so well on the command line, and make it work from inside Ant. The key to this is the exec task of Ant, which lets you fire off any command line you desire from inside Ant. In our case, we’re going to modify our build.xml to look like Example 3-2.

Example 3-2. build.xml with the xcodebuild
<?xml version="1.0" encoding="utf-8"?>
<project name="Buggy Whip Builder" default="debugbuild" basedir=".">
   <target name="debugbuild">
      <echo message="Building debug build of BuggyWhipChat"/>
      <exec executable="/Developer/usr/bin/xcodebuild" os="Mac OS X">
         <arg value="-workspace"/>
         <arg value="BuggyWhipChat.xcworkspace"/>
         <arg value="-scheme"/>
         <arg value="BuggyWhipChat"/>
         <arg value="build"/>
      </exec>
  </target>
</project>

This is fairly straightforward: we’ve added an exec task that runs the xcodebuild command, passing in the arguments that we’ve already determined will work. The os parameter of the exec task ensures that we don’t try to run this script on a non-Mac, but to be thorough, we should really use an if task and print an error message if the we’re not on a Mac. With this in place, we can try running Ant from the command line, and see what we get:

buggywhipchat Diane$ ant
Buildfile: /Volumes/Homes/James/Dropbox/Dianescvs/buggywhipchat/build.xml

debugbuild:
     [echo] Building debug build of BuggyWhipChat
  [exec] === BUILD NATIVE TARGET ChatAPI OF PROJECT ChatAPI WITH CONFIGURATION Debug ===
.
.
.
     [exec]
     [exec] ** BUILD SUCCEEDED **
     [exec]

Houston, we have a build! But we’re not quite done yet.

Calling the Ant Script from Hudson

The whole purpose of this exercise was to get our builds hooked up into Hudson. Now that we have a good Ant script, we can tell Hudson to use it. But before we forget, we need to add the build script to our CVS repository.

buggywhipchat Diane$ cvs add build.xml
cvs add: scheduling file `build.xml' for addition
cvs add: use `cvs commit' to add this file permanently
buggywhipchat Diane$ cvs commit

Now we can go back to our Hudson configuration, and make a few changes. To begin, let’s make sure that we start with an empty directory before we check our project out from CVS, you do this by making sure that the “Use Update” option in the advanced portion of the Source Control Management section of the configuration is turned off, as shown in Figure 3-6. This will cause Hudson to start with a clean slate every time, which can be especially important if you end up with work products in your build directory. This also saves you the hassle of having to run an xcodebuild clean action before doing your build.

Turning off the Use Update flag
Figure 3-6. Turning off the Use Update flag

The other step required is to add a build step, which is done by going down to the Build section of the configuration, and clicking on the Add Build Step pulldown (Figure 3-7). From this menu, we want to use Invoke Ant.

Adding an Ant task to Hudson
Figure 3-7. Adding an Ant task to Hudson

Selecting this choice gives use a single parameter to fill out: the targets to build. In this case, we want to use the debugbuild target, so we fill that in (Figure 3-8) and save the configuration. Now we’re ready to rumble!

Setting up the Ant target
Figure 3-8. Setting up the Ant target

If we go back to the main Hudson window and hit the play button for the build, which tells Hudson to start running the build, we should (if everything went according to plan) end up with a good build. Going into the new build, we can look at the console output, and see everything worked as expected:

Started by user anonymous
[BuggyWhipBuild] $ cvs -Q -z0 -d /usr/local/CVS co -P 
  -d workspace -D "Friday, July 15, 2011 3:41:38 PM UTC" buggywhipchat
$ computing changelog
[workspace] $ ant debugbuild
Buildfile: /Volumes/Homes/James/.hudson/jobs/BuggyWhipBuild/workspace/build.xml
debugbuild:
     [echo] Building debug build of BuggyWhipChat
     [exec] === BUILD NATIVE TARGET ChatAPI OF PROJECT ChatAPI WITH CONFIGURATION Debug ===
.
.
.
     [exec] ** BUILD SUCCEEDED **
     [exec] BUILD SUCCESSFUL
Total time: 12 seconds
Finished: SUCCESS

Getting Fancy with Hudson

Now that we have the basic build running, there are a few things we can do within Hudson and our project to make life easier for us later on.

Running a Nightly Build

The first one is fairly simple—we can set the build to run automatically every night, to make sure that we have a good nightly build. To do this, go back into the configuration screen for the build in Hudson, and scroll down to the section entitled Build Triggers. In there, you’ll see a checkbox called “Build periodically,” and if you check it, you’ll get an empty Schedule field you can type in (Figure 3-9). This is essentially the build’s personal cron file, and follows pretty much the same format. If you’ve never used cron, you can click on the ? icon, and a tutorial will appear below the field. So to run a build every night at 2:05 AM, you’d enter:

5 2 * * *
Configuring a build to run nightly
Figure 3-9. Configuring a build to run nightly

Now (assuming that Hudson is up and running at the time), you’ll get a nightly build. If you’re feeling ambitious, you can configure the build to send you status messages via email (and even set it not to bother you unless the build fails!).

In Chapter 7, we’ll go one step further, and actually use TestFlight to send new builds directly to our testers.

Include the Build Number Directly into the Application Version

Eventually, you’re going to get a bug report, and after spending hours trying to reproduce it, you may learn that the user was running an old build. Grrrrr! Wouldn’t it be great if we could automatically bump up the minor version number of the application every time we did a build? Well, Bunky, you’re in luck! It turns out that with a few magic steps, you can do just that.

The first step is the simplest of all, you just need to put a string in your version number (and short version number) in your applicationname-info.plist file, something unlikely to occur anywhere else in the file. I like to use BUILDNUM in all caps. So, if your version number for your application is 1.0, you’d use 1.0.BUILDNUM as the version number for the two properties in the plist (see Figure 3-10).

Editing the plist version number
Figure 3-10. Editing the plist version number

There’s only one more step we need to take here, which is to tell Hudson to run a small shell script, which will replace the BUILDNUM string with the actual build number (which, helpfully, Hudson exposes as an environment variable to shell scripts it runs).

Go back into the configuration for our build, and create a new build step (in the same way that we created the Ant build step earlier). But, this time, rather than selecting Invoke Ant, select Execute Shell. You’ll end up with a text box directly beneath the existing Ant target text box. Before we do anything else, grab the step by the little grey box “handle” on the left, and drag it above the Ant step, because we want to edit the plist entries before the build runs.

The script itself is trivial, and is shown in Example 3-3.

Example 3-3. A perl script to set the build number in the version string
cd BuggyWhipChat/BuggyWhipChat
/usr/bin/perl -p -i -e "s/BUILDNUM/$BUILD_NUMBER/g" BuggyWhipChat-Info.plist

So what’s going on here? First, we move ourselves to the right directory with cd, in this case the subdirectory that contains the plist file we want to modify. Then we use a perl “in-place” edit to substitute the string BUILDNUM for the BUILD_NUMBER environment variable globally in the file. Since this step occurs before xcodebuild is run, the version number in the binary will reflect the build number we set.

If we run the build again (after checking the modified plist file into CVS, of course), we can verify that the step ran by looking at the build console output, which will now contain this snippet:

$ computing changelog[workspace] 
$ /bin/sh -xe /Volumes/Homes/Diane/tomcat/temp/hudson3475590830804804920.sh
+ cd BuggyWhipChat/BuggyWhipChat
+ /usr/bin/perl -p -i -e s/BUILDNUM/6/g BuggyWhipChat-Info.plist

In this case, BUILDNUM is being replaced by 6, the current build number. If we take a peek at the plist in the finished build workspace directory (which hides in ~/.hudson/jobs/buildname/workspace/), we can also see that the strings were appropriately modified in the actual file:

        <key>CFBundleShortVersionString</key>
        <string>1.0.6</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
        <string>1.0.6</string>

Parameterize the Build Script

As you go along, you’re going to end up running a number of different Xcode builds as part of your automated build process. You’ll be running unit-test-only builds, debug builds, Ad Hoc builds, and maybe even App Store builds. They all are the same, except for the scheme and action you specify to xcodebuild—so why not make a parameterized custom Ant task, and save some copy-and-paste scripting?

Go back into your build.xml file, and change it to look like Example 3-4.

Example 3-4. A parameterized build.xml file
<?xml version="1.0" encoding="utf-8"?>
<project name="Buggy Whip Builder" default="debugbuild" basedir=".">
   <macrodef name="xcodebuild">
      <attribute name="workspace"/>
      <attribute name="scheme"/>
      <attribute name="action" default="build"/>
      <sequential>         <echo message="Running xcodebuild using workspace '@{workspace}',
         scheme '@{scheme}', action '@{action}'"/>
         <exec executable="/Developer/usr/bin/xcodebuild" os="Mac OS X">
             <arg value="-workspace"/>
             <arg value="@{workspace}"/>
             <arg value="-scheme"/>
             <arg value="@{scheme}"/>
             <arg value="@{action}"/>
          </exec>
      </sequential>
   </macrodef>
   <target name="debugbuild">
      <xcodebuild workspace="BuggyWhipChat.xcworkspace" scheme="BuggyWhipChat"/>
   </target>
</project>

What we’ve done here is to create a macro called xcodebuild that takes three parameters, one of them with a default value if not supplied. Now, in the rest of our code, we can invoke an Xcode build using a single command, which supplies values for those parameters. We’ll be using this handy macro through the rest of the book, and you’ll see how much copy-and-paste it saves.

With our project building automatically and inserting build numbers into the version strings, it’s time to actually do some coding. In the next chapter, we’ll see how to get your iPhone application talking to a number of popular web service formats.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset