Thursday, April 8, 2010

From iPhone to iPad: Creating a Universal Application

I’ve recently had the pleasure of porting an iPhone app to the iPad. The process was remarkably easy. This brief article covers the technical issues as well as the relatively minor UI design issues that came up when doing the port.

Apple’s iPhone OS SDK is capable of producing ‘Universal Applications’ which run on multiple devices, including the iPad and iPhone. The recommended approach for existing iPhone app projects is to run an upgrade wizard, which worked beautifully for me. After running the wizard I was initially concerned that nothing happened, because the wizard simply exited with no indication of what occurred — but after comparing project files against the version in my VCS there were obviously some minor changes to the project files, and one new file, the iPad’s main view MainWindow-iPad.xib.

Immediately after running the upgrade wizard I was able to run the app in the iPad simulator. Very impressive. Having implemented the app with relative layouts, the whole UI scaled very nicely to the larger screen. Running through some basic workflows in the app, I expected some things to break — but no, everything worked perfectly!

There were two places in the code where visually things needed adjusting based on the size of the screen. Initially I tried Apple’s recommended approach of conditional coding based on (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad), however I quickly discovered that it doesn’t work for iPhone 3.1.x apps because UIUserInterfaceIdiomPad is not defined. Clearly Apple missed something here. After thinking through some creative ways to make this work (see Jeff LaMarche’s blog for an approach that works) I realized that instead of trying to detect the platform, using the screen size was a better approach. An easy way to do that is as follows:

[[UIScreen mainScreen] bounds]

The iPad has some new UI paradigms which are well-described in the iPad HIG. Most apps will benefit from following these guidelines, however I was surprised at how good the app looked in its current form on the iPad.

The moment of truth of course came when I deployed the app to an iPad. Apart from having to download a new provisioning profile from Apple, the process was easy. Within a few minutes it was up and running flawlessly on the device. Kudos go to Apple for making it so easy to port apps from the iPhone to iPad. It’s hard to imagine it being any easier.

7 comments:

eddy said...

#ifdef UI_USER_INTERFACE_IDIOM()
// SDK 3.2 or later
#if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define IsiPad 1
#else
#define IsiPad 0
#endif
#else
#define IsiPad 0
#endif

David Green said...

@eddy thanks for the snippet! I agree that it works (credit). What I don't like about it is it doesn't adapt well to changing layouts or reorganizing the UI. Making layout decisions based on available space (ie: based on a container's frame bounds) makes for more robust code.

gorkem said...

I am not sure if running on iPhone and IPad qualifies an application as "universal application". JavaME midlets have been running on devices with different form factors and mobile OSes for a long time. Qt applications can do both desktop and mobile (Skype is a good example for that).

klang said...

"Universal" as in "runs on all Apple approved touch screen devices"

RoLY said...

I have found that code provided by Apple works fine!

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
// iPad
}
else
{
// iPhone/iPod
}

The problem we are running into is that this cannot be tested on the simulator for the iPhone device, only for the iPad. To test non-iPad, you MUST test it on the device. Also, you MUST test at base SDK of 3.2 because that is where the UI_USER_INTERFACE_IDIOM() is defined. Of course, this doesn't do any good for a user who doesn't have an iPhone and can take long for installs just to test some small code (been there), but then again, it must always be tested on a real device as the simulator is not meant to be duplicate real device.

David Green said...

@RoLY the main problem is that iPhone OS 3.2 has not yet been released for iPhone. If you want to target real iPhone devices in the field you'll need to use a 3.1 SDK for iPhone. See iPhone OS (wikipedia) for an SDK release history.

William said...

How about:

#ifdef UI_USER_INTERFACE_IDIOM()
#define IS_IPAD() (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#else
#define IS_IPAD() (false)
#endif

usage:
if (IS_IPAD())
{
// foo
}

Cheers,
Will (author of http://GPSLogApp.com )