Thursday, April 7, 2011

Swap It Don't Stop It iPhone app

My recent handy work is out in the wild in the form of the Swap It Don't Stop It iPhone app for a new Australian Government health campaign.


The Swap It Don't Stop It campaign is all about educating and encouraging people to swap unhealthy food and unproductive activities for those that can improve your overall health & fitness.


The iPhone app provides a tool for tracking your "swaps", gaining achievements, receiving alerts to be reminded when to swap, tracking food swaps (with an integrated shopping list) and finding healthy activities near you.


Technically, the app required:

  • Custom views to match the attractive design;
  • Core animation for some custom transitions and UI elements;
  • Server side REST API integration;
  • MapKit and Location Services along with SOAP API integration for finding activities by location;
  • Core Data for local data management;
  • Push notifications for alerts;
  • Retina display optimisation.

The app looks really great and is free on the Australian App Store. I was very happy with how it turned out. I developed the app on behalf of the great guys at Millipede Creative Development and JWT Melbourne.


Monday, April 4, 2011

iOS Dev, Beta & Production builds installed side-by-side

A development and testing pattern I adopted early on for my iOS projects was to configure projects such that development, ad hoc test and release builds could all be installed on my device at the same time. This allows for side-by-side testing and easy comparison of the builds, each being at different states of completion at any point in time.


For example, this iPhone screen snapshot demonstrates dev, beta & release builds of my hobby project River Level installed side-by-side.


Dev, beta & release builds of River Level installed side-by-side
iOS differentiates apps by their Bundle Identifiers (CFBundleIdentifier) which are defined in the Project-Info.plist.  A Bundle Identifier looks like a reverse DNS address, e.g. "com.apple.safari". What I like to do is to set the Bundle Identifier to different values for each build configuration, thus allowing each to be installed separately. I don't do this manually, though, as I'll explain below.


Note that some iOS features – like Push Notifications, Game Center and In-App Purchase – require the Bundle Identifier to match the value configured in iTunes Connect so you can test these features. In those cases this technique won't be effective, unless you set up multiple app instances in iTunes Connect for each build configuration.


The other parameter I customise per build configuration is the Bundle Display Name (CFBundleDisplayName). This is the app name as displayed on the home screen. iOS doesn't require these names to be unique, so if you changed the Bundle Identifiers without changing the Display Names you would end up with multiple instances of your app all with the same name and icon, making it difficult to work out which build is which.


My convention is to append "∆" to dev builds and "ß" to ad hoc builds.


To customise the Bundle Identifier and Bundle Display Name per build the process is:

  • Append ${BUNDLE_ID_SUFFIX} to the "Bundle identifier" in Project-Info.plist.
  • Append ${BUNDLE_DISPLAY_NAME_SUFFIX} to the "Bundle display name" in Project-Info.plist.
Custom variables appended to Bundle Display Name and Bundle Identifier values



Note that with no other changes these variables will be expanded to empty strings and so will have no effect. This is how I handle Release builds, so they are submitted to the App Store with standard values.


The next step is to define the custom values for each build configuration.  My convention is:


Development (Debug) builds:
  BUNDLE_DISPLAY_NAME_SUFFIX=∆
  BUNDLE_ID_SUFFIX=.dev


Ad Hoc builds:
  BUNDLE_DISPLAY_NAME_SUFFIX=ß
  BUNDLE_ID_SUFFIX=.adhoc

Release builds:
  Neither of these settings is defined.


The place to put these settings is in each relevant Build Configuration of the Project. Note: some people edit the build configuration for their Target, but I recommend only doing this if you need a setting specifically for a build target.  If you only have one target, edit the build settings for the whole Project.  That way, if you add Targets later they will inherit the Project build settings.


To add custom settings to build configurations, in Xcode 3:

  • Select menu "Project" / "Edit Project Settings"
  • Select "Build" tab
  • Select a build configuration in the Configuration list (e.g. "Debug")
  • Select "Add User-Defined Setting" from the command list (bottom left corner pulldown)
  • Add a user-defined setting for each of "BUNDLE_DISPLAY_NAME_SUFFIX" and "BUNDLE_ID_SUFFIX" with the values you choose.
  • Repeat this for each build configuration that you want to install separately to the others.

User-defined settings for a Debug build configuration
In Xcode 4, the process is similar, although the UI has changed.  Select your project; select the "Build Settings" tab, then select "Add Build Setting"/"Add User-Defined Setting". You can set the values for Debug and Ad Hoc at the same time with the new UI.


To see any user-defined settings, scroll the build settings table to the bottom; or use the "Show" list to filter only "User-Defined Settings" (Xcode 3).


To delete a user-defined setting, highlight the setting and hit the delete key.


That's it. Now re-build and install and the app should appear separately to the other builds. Feel free to install as many different builds as you feel like.