1 of 1
I recently read another blog post about OTA (Over the Air) distribution of Ad-Hoc builds of iPhone applications and thought I’d share my own thoughts on this.
I’m doing a lot of client work and try to maintain very short feedback cycles. Sometimes this means that I may send out multiple Ad-Hoc builds for one application a week to get constant feedback from my clients. My “traditional” approach was to build the Ad-Hoc build, put it in an email and send it to the client. The client then had to sync his device with iTunes to get the latest build. As many of you know, this becomes frustrating very quickly.
Not so long ago Apple enabled OTA distribution of Ad-Hoc builds, which means you can export the Ad-Hoc build from Xcode, put it on a webserver and have the client install it over the air right from Safari. (For a detailed instruction on how to do this, check out this article by John Muchow who has written a great detailed instruction on how to do this). So because it seemed so much easier for my clients I did that for a while and basically had a list with all the URLs to enter which i could just use by copy/pasting them into Xcode while saving the .ipa file.
But if you do this manually a couple of times, you notice that it is really annoying and time consuming. Something that needs to be automated. So that’s what I did. I built a small application for exactly that purpose and it’s called IPA Publisher. If you want to check it out, visit the Mac App Store and get it for just $4.99.Note: Unfortunately, IPA Publisher is still in review so you won’t find on the App Store yet. But since I have a short talk at NSConference 2011 about it, I wanted to publish this post anyway so people could come back to it. If you want to know how it works, keep on reading:
The basic idea
The basic idea behind IPA Publisher is to relieve you of the tasks of entering the location information over and over again. You enter details about one (or more) locations where you publish Ad-Hoc builds once (e.g. a public Dropbox folder, your webserver, …), and then every distribution of a new build comes down to:
- Build and Archive an Ad-Hoc build
- Save the .ipa file (no Distribute for Enterprise and entering all the location details, but instead just choosing Save to Disk)
- Hand the .ipa to IPA Publisher
- Choose the location where you want to publish it
- Have all the necessary files generated (.plist, website and provisioning profile).
Start IPA Publisher
In the screenshot below you see the main window of IPA Publisher. You basically have only two options: 1) Configure your publish locations and 2) Give IPA Publisher a .ipa file. This can be done by dropping the file on the marked area in the main window, dragging the file on the dock icon (no matter if IPA Publisher is running or not) or for example by writing an Automator action or Finder service.

Configure a publish location
For the example, the first thing we want to do is configure a publish location. So just click on Manage Publish Locations and you get a simple dialog to configure your different publish locations. Click on + to add a new location and enter a name and the URL to access files in your Dropbox Public Folder. To get this URL go to the Dropbox website, select Get shareable link on your public folder and look in your browser’s address bar. The URL looks something like https://www.dropbox.com/s/’some token’. What you need is the ‘some token’ part of the URL. Shareable links to a Dropbox folder or file are of the form https://dl.dropbox.com/s/’some token’/'file’. So enter the URL https://dl.dropbox.com/s/’some token’ in the URL field in IPA Publisher and replace ‘some token’ with the token of your Dropbox Public Folder. You can leave the Base Directory and Custom HTML fields empty for now (I will explain later what they’re for).

Once you’ve entered all the information as in the screenshot above, close the Manage Locations dialog by clicking Done.
Build And Archive
Use Xcode Build and Archive to create a new Ad-Hoc build of your application and switch to the Organizer when the build is done. Select the application and choose Share… and then Save to Disk… to save the .ipa file somewhere, e.g. your Documents folder as in the screenshots below.



Publish with IPA Publisher
Open your folder where you saved your .ipa file in the Finder and Drag and Drop the .ipa file to the designated area in the main window or to the application icon of IPA Publisher in your dock as shown in the next screenshot:

If you have multiple publish locations configured, IPA Publisher will ask you to which location you want to publish the .ipa file as shown in the next screenshot:

If you have only one publish location, IPA Publisher will automatically use this one location and not bother to ask you. And that’s it. As you can immediately see in the Finder window (and the screenshot below), IPA Publisher has created a .html, .plist, .mobileprovision and two .png files with the same name as your .ipa file.

Now just put those files in your Dropbox Public Folder and navigate to the following website on your iOS device: https://dl.dropbox.com/s/’some token’/'the name of the .html file’.html and you should see a web site as in the screenshot below:

By tapping on the two rows on the website you can now install the provisioning profile and the application over the air.
What just happened
IPA Publisher took the .ipa file you dropped on it’s application icon, extracted the Provisioning Profile, Icons and metadata from the Info.plist file and created all the necessary files to enable an OTA distribution of the Ad-Hoc build. Since you have only one publish location configured in IPA Publisher it uses this one as the default publish location and doesn’t bother to ask you for any additional information. If you have multiple publish locations defined, IPA Publisher opens a small popup when you drop an .ipa file on it’s icon and lets you choose the publish location you want to publish to.
Making the website fancier
As you probably see when you opened the generated website on your iOS device, the generated HTML is functional but very simple. If you want to provide your testers with a fancier website you can use the custom HTML field in the Manage Publish Locations window. To keep everything working with a custom HTML you need to make sure your custom HTML meets two mandatory (and three optional) requirement:
- Provide a link element for the provisioning profile in the form: <a href=”$profilelink”>Install Provisioning File</a>. IPA Publisher replaces the $profilelink placeholder with the correct link upon generation.
- Provide a link element for the application archive in the form: <a href=”itms-services://?action=download-manifest&url=$plistlink”>Install Application</a>. IPA Publisher replace the $plistlink placeholder with the correct link to the .plist file (which the devices uses to find and install the application) upon generation.
- (Optional) Place a placeholder named $title for the application name in the HTML. IPA Publisher replaces this with the value of the CFBundleDisplayName key in your application’s Info.plist.
- (Optional) Place a placeholder named $artworklink for the big application artwork in the HTML. IPA Publisher replaces this with a link to the iTunesArtwork file in the application bundle.
- (Optional) Place a placeholder named $iconlink for the small application icon in the HTML. IPA Publisher resizes the iTunesArtwork file to 57×57 pixels and replaces this placeholder with a link to the resized image.
Understand the Base Directory field
As you probably saw in the Manage Publish Locations window, you can also set a Base Directory for every Publish Location. To understand how the Base Directory works, suppose you want to organize your Ad-Hoc Builds in the following way in your Dropbox Public Folder:

If you want to make a publish location with the URL for the parent folder (in the example the Dropbox Public Folder), the links in all the generated files in the subfolders would need to have the form https://dl.dropbox.com/s/’some token’/app1/app1.html. But if you try this, you will see that, even though the files are in subfolders, IPA Publisher will generate the URL https://dl.dropbox.com/s/’some token’/app1.html which is clearly not right.
That’s where the Base Directory comes into play. You set the base directory of the publish location to the folder the URL points to. So if https://dl.dropbox.com/s/’some token’ points to your Dropbox Public Folder which is located at /Users/me/Dropbox/Public you would put /Users/me/Dropbox/Public in the Base Directory field as in the screenshot below:

Then when you publish an .ipa file in a subfolder of that (e.g. /Users/me/Dropbox/Public/app1/app1.ipa), IPA Publisher compares the Base Directory with the path to the file. If the path to the file starts with the Base Directory, IPA Publisher removes the Base Directory from the path of the file and appends the remaining relative path to the URL upon generation. So in this example, IPA Publisher removes /Users/me/Dropbox/Public from the path to the .ipa, which leaves us with /app1/app1.ipa and leads to /app1 being appended to all generated URLs and everything working as excepted.
Alternatives
There are some great alternatives like Hockey (which I wrote about in a previous post), which works very well and the guys at Testflight, who have also done an amazing job. But I found that both are not quick and easy enough for me – Hockey needs you to include some code in your app Update: Sorry for the mistake, but Hockey does not need you to include code in your client app. The client part is optional if you want to have the automatic update notifications in the app. But you have to make sure that you do not ship the Hockey client framework with the App Store build of your app. And Testflight requires your users to register with them before they can install the test build.
Instead I switched to just using my Dropbox for sharing Ad-Hoc builds. One option is to use your Dropbox Public Folder, but another option is to switch to Dropbox’s new sharing site (which is described here) with which you can get a shareable link to any folder or file. The great thing about the second option is that you get a link with a unique, pretty much unguessable token for every file and folder you share.
So what I do is I have a folder in my Dropbox where I put all my Ad-Hoc builds, have subfolders for my different clients/projects and in those subfolders for every app of that client. I create Publish Locations for each of the client folders and set the path to that subfolder as the base directory of the publish location. Then I can just put a new app in a subfolder, publish the .ipa with IPA Publisher and send the slightly modified link to my client. (So the client gets a link https://dl.dropbox.com/s/theclientspecifictoken and then appends the app name to that link – e.g. https://dl.dropbox.com/s/theclientspecifictoken/app1/app1.html). Or you make a start page for the client in the base directory and then just link to the subpages in that file.
Let me know what you think
If you like what you read, head over to the Mac App Store and get IPA Publisher. And if you have any comments or suggestions how to make IPA Publisher better or more usable for iOS developers just drop me a comment, send me an email to martin (at) martinreichart (dot) com or just sent me a reply on twitter to martinr_vienna.
- Add the Hockey source code to your project
- Tell Hockey where to find your Ad-Hoc builds on your PHP5-enabled webserver
- Use Build and Archive in Xcode to build your Ad-Hoc Build
- Use Xcode’s ‘Distribute for Enterprise’ feature to export the application build
- Copy the application build to your webserver
- Done
Step 1: Getting Hockey
You can get all the necessary parts you need for this right here on Github. The repository contains the necessary parts you need on the server as well as very simple client code and a small demo. Plus there are README files for the different parts.
Step 2: Setting up your webserver
The first step you need to do is set up your webserver. This is as easy as enabling PHP5 and copying the files in the server directory somewhere on your server.
Step 3: Adding Hockey to your project
The next thing you need to do is add Hockey to your project. Basically you can take all the code in the client directory (except the Beta Automatisation directory) and copy it into your project.
One thing that’s important is that the Hockey code is not included in your Builds for the App Store. To do this, open the build settings of your target and select ‘All Configurations’. Then add the following to the setting ‘Preprocessor Macros Not Used In Precompiled Headers’: CONFIGURATION_$(CONFIGURATION)
This will add preprocessor macros so you can do the following in your code (assuming for example that your Ad-Hoc configuration is called AdHoc):
#ifdef CONFIGURATION_AdHoc
or
NSLog("This will only be logged in Ad-Hoc builds");
#endif
#if defined(CONFIGURATION_AdHoc)
You also might want to exclude the source files from Hockey in your App Store distribution build. To do this, switch to your App Store configuration in the build settings of your target and add a User-Defined Setting called
NSLog("This will only be logged in Ad-Hoc builds");
#endifEXCLUDED_SOURCE_FILE_NAMES. Then set it’s value so that all Hockey files are excluded (I renamed all hockey source files so they start with BWHockey and set the value of this setting to BWHockey*).
Step 4: Activating Hockey in your code:
Then just add the following to application:didFinishLaunchingWithOptions: in your AppDelegate:
Of course you need to change the URL string accordingly. You also need to add a conditional header include:
#if defined(CONFIGURATION_AdHoc)
[[BWHockeyController sharedHockeyController] setBetaURL: @"YourUrlPointToThePathWhereTheIndexPHPFileIsLocated"];
#endif
In my example, I only add the code in my Ad-Hoc builds by using the preprocessor macros we defined earlier.
#if defined(CONFIGURATION_AdHoc)
#import "BWHockeyController.h"
#endif
Step 5: Building and distributing your application
Next, switch to your Ad-Hoc build configuration and use Xcode’s ‘Build and Archive‘ to create a build of your application. Then open the Organizer, go to the Archived Applications and select the application and build you just created. Click on ‘Share Application…’ and select ‘Distribute for Enterprise…’. In the following dialog enter ‘__URL__‘ in the URL field, type in a Title and fill out the rest if you want to. When you’re done, click ok and save the build to some location on your hard disk.
Connect to your webserver and go to the folder where you copied index.php in Step 2. In there create a subfolder named just like your application’s Bundle Identifier and copy the 2 files just Xcode exported for you (a .ipa and .plist file). That’s it.
Step 6: Accessing the application
Now your beta testers just need to navigate to the website and they see a list of all the applications that are found there (actually the index.php file searched for all .ipa and .plist files it can find). Then they just need to tap on an entry and can install the application right from Safari.
Step 7: Distributing updates
When you have an update for your beta app, change the bundle version in your Info.plist and repeat Step 5. The included index.php file can only handle one version of an app at a time, so you need to delete the old files before copying the new version. The next time your users start the application, they get a notification that there is a new version of the app available and they can install it right on the spot. Or they install it again via Safari.
Conclusion
The main advantage i see in using Hockey (or just wireless app distribution) is that it eliminates the need for beta testers to sync their devices with iTunes to get a new version of an app. No matter where they are, they can get the latest version of your app and start testing immediately.
Oh and although you ‘Distribute for Enterprise’ you don’t need to be a member of the iOS Enterprise Developer Program.
Links
As software developers we pretty much spend about 90% of our workday sitting in front of a computer or laptop – The remaining 10% are usually spent in short activities like going to the bathroom, getting water, a coffee or maybe a few steps during a phone call. Now, I’m not staying that every workday is like that but there are certainly many days in our life that look like that for 8-10 hours a day.
So what’s the problem with that? The problem starts when your lack of physical activity over such a long period of time causes your body and health to suffer. I personally experienced this about 4 1/2 years ago when I started feeling pain in my lower back after sitting for a long time or after doing some exhausting sport (basically anything that strained my back). At first I didn’t pay too much attention to this and dismissed it as nothing serious – nothing a relaxing massage couldn’t fix.
But then 3 months after that I woke up one morning and simply couldn’t get up because of the blinding pain in my back during even the slightest movement. After having an MRI I was diagnosed with a herniated vertebral disc. Instead of having surgery (which is nowadays done very rarely with such an injury) my doctors suggested going with “conservative therapy” – meaning pain medicine, physical therapy, and patience and after about 4 months I was able to walk again rather painless.
Now 4 years after that I started feeling a certain tension in my back again and all the memories came screaming back to me (i think becoming sort of a hypochondriac comes naturally with such an injury). What’s even worse is that I don’t really have back pain, but I feel that something is not quite alright and in addition I occasionally have a weird feeling (sort of like a tingling) in my left foot. My doctors say that it’s nothing like what I had 4 years ago but there is definitely some kind of irritation of the nerves. My therapy advice so far: Try to sit less!
As a developer your first thought may be “Good one”, but there are definitely a lot of things we can do to take care of our back during a busy workday, so here’s a few things I recommend and will try to personally stick to:
- Make breaks: Try to make short breaks at least every 25 minutes to get up, walk around a bit and straighten and stretch your back and legs. If you’re anything like me, you tend to forget to do this regularly. That’s why I use a Mac application called Time Out by Dejal which let’s you set timers to remind you and covers your screen with a reminder to take a break. In conjunction I sometimes work according to the Pomodoro Technique which recommends working in 25 minute increments (called pomodori) and making a 5 minute break between two pomodori to relax and refocus
-
Get a really good chair: I currently have a really basic leather office chair, which I thought was pretty decent. But when my back problems started again I went to a shop which is specialized in ergonomically great chairs and tried a couple of them. And thanks to a recommendation from a friend I tried a chair by Varièr (former Stokke) and after sitting on it for a few minutes I noticed how much difference there actually is in chairs.
And do yourself a favor and don’t care about the price at first – a good chair which supports your back is more important than thinking about 200 bucks difference for a chair you’re probably going to have 10 years. - Drink enough during the day: This is important because your spinal discs are basically filled with water to help absorb pressure. Staying well hydrated helps your spinal discs properly refill during your sleep.
- Get some regular exercise: Try to regularly do some kind of sport for your back and abdominal muscles. Those two regions are especially important because they help stabilize the whole spine. Personally I have found Pilates to be very helpful. There are different forms of Pilates – some more Aerobic-style and some very relaxed. I would absolutely recommend the second type, but depending on where you live it might be quite hard to find an appropriate instructor (and you should really do this with a professional instructor and not some kind of book or video, because only an instructor can give you advice on your individual needs)
- Listen to your body: If you’re feeling pain, your body tries to tell you something; too much stress, too little exercise, bad posture, … Listen to these signs and make changes, because sooner or later this is gonna fall on your head and you’re just gonna pay with your health.
Oh and one more thing: With a lot of health-related problems we usually tend to think that certain things won’t happen to us, because we’re young. But believe me: Back problems do not fall into this category!
So take care of yourself before you even get problems with your back!















