Developing apps compatible with all iOS devices
As you might already know, iOS is the operating system that runs on iPhones, iPod Touches and iPads. The first iOS device was the iPhone and was released in January, 2007. Back then the operating system was called “iPhone OS”. Since that time more devices were released running iPhone OS than just the iPhone. This is why a while ago Apple announced that the operating system would from that point on be called “iOS” instead.
When you’re developing an app for iOS you most probably are focusing on just one specific device with a specific version of the operating system. For example you’re developing for iPhones running iOS 4.2. If your only target audience is iPhone users then this is good enough. But you could make you’re app support other devices and iOS versions as well. This would extend the target audience for your app. As it turns out, it isn’t much of a hassle to do so!
Here’s the current list of iOS devices your app could support.
- iPod Touch
- iPod Touch 4th generation
- iPad
- iPhone running iOS 3.x
- iPhone running iOS 4.x
- iPhone 4
Let’s say you’ve developed an iPhone app. In this blog post I will discuss the different kinds of iOS devices and versions to explain how to make that iPhone app support those devices as well.
iPad
The iPad is the odd one out compared to other iOS devices. First of all it has a larger display. But more importantly, it supports a few interesting different new ways to design your user interfaces. At first glance you would expect that you have to write an all new application if you would want to support the iPad. You don’t have to do this. You can modify your existing iPhone app to what is called a “universal app” which can run on both iPads and iPhones.
In the app store, universal apps are marked with a “+” sign.
This basically tells you that if you download this app for iPhone or iPod Touch, you can run the same application on your iPad too. As a user you have the advantage that you don’t need to buy the same app twice. And as a developer you only have to maintain one application instead of two, so it’s a win-win situation!
How to create a universal app?
The user interface of the iPhone and iPad version of an app are often quite different. Take a look at Dropbox for example:
Dropbox on iPad
Dropbox on iPhone
The general idea is to redesign the user interface of the iPhone app for iPad while reusing as much code as you can. In case of something like the Dropbox app, you could probably completely reuse the controllers and the UI components for both the list and the detail view. The difference is that on iPad both can be displayed at the same time using the UISplitViewController while on iPhone either the list or detail view is shown at a time.
To make your current app universal, configure two separate XIB files in the Info.plist of your app instead of the single one you currently have configured. One of course is meant for iPhone and the other for iPad.
You app already contains an XIB file for the iPhone user interface. So what’s left is to create an XIB file and an UIApplicationDelegate implementation for iPad. The easist way is probably to generate those files by creating a new iPad application using XCode. Copy the generated files into your iPhone project and set up the MyCoolApp-Info.plist file like illustrated above.
Finally, what you need to do is let the XCode compiler know that it should compile a universal binary instead of an iPhone binary. Go to the Project Info screen and in the “Build” tab, find the option “Targeted Device Family” and set it to “iPhone/iPad”.
What’s next is up to you. From the newly created XIB files and app delegate you can set up two separate user interfaces and you can reuse classes wherever suited. Try to avoid duplicating any code. This will maximize the maintainability of your app, since you won’t have to make the same change twice.
iPhone 4 and the iPod Touch 4th generation
The new iPhone 4 (and latest iPod touch) have the so called retina display built in. This retina display has a resolution of 960×640 which is four times the amount of pixels as before (480×320). Even though the resolution has increased, all existing iPhone and iPod Touch apps will look the same, but look much sharper. This is because iOS does everything it can to make use of the higher resolution. Text will automatically upscale properly as well as all built in UI components (buttons, sliders, navigation bars, tool bars, etc). So basically most of the work to support the higher resolution is automatically done for you!
One of the things it can’t upscale properly without help are images and graphics. So you can imagine that regular apps require a lot less work than games. But regular apps often still make use of some images and graphics.
Upscaling images
In an example application I wrote, I used the JTeam logo using the UIImageView component. This is the logo before and after upscaling on an iPhone 4:
Before upscaling
After upscaling
As you can see all text and the button and bar are upscaled nicely without any effort on your part (left image). The only thing that was not upscaled is the image. The image has a resolution of 45×70. To support the bigger screen, all I needed to do is create a high resolution version of the JTeam logo. The hi-res version should be exactly twice the resolution as the original image, in this case 90×140. Copy it into your XCode project and give it the special “@2x” suffix.
The “@2x” suffix basically tells iOS that this version of the image should be used whenever the device is using a double resolution (retina) display. On non-retina devices (iPhone 3GS, iPad, etc), the original image is used instead (the one without the prefix).
Upscaling graphics
Sometimes you don’t take an existing image to display in your app, but you dynamically draw an image from scratch. You usually start drawing by calling this method:
<br> UIGraphicsBeginImageContext(CGSizeMake(width, height));<br>
When you do this running on an iPhone 4, you will draw an image using pixels. The effect of using the above method to draw, is that anything you draw will be stretched to the double amount of pixels using anti-aliasing on an iPhone 4. Instead use a function which is introduced in iOS 4.0 which allows you to define the size of the image in a different way.
<br> UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, height), YES, 0.0);<br>
The first argument is the size of the image in points. A point is basically a device independent pixel. The iPhone 4 screen is made of 480×320 points (as any other iPhone), so each point on an iPhone 4 spans a total of 4 pixels since the resolution is 960×640 pixels. On any previous iPhone each point spans just one pixel. The second argument specifies whether the bitmap you’re going to draw is opaque or not. The third argument defines at what scale the given points are translated to pixels. The scale argument has a value of 2.0 on iPhone 4 and 1.0 on iPhone 3G(S) for example. By passing 0.0 as the scale, the default scale will be used depending on the device the code is running on. As a result, any graphics you draw using the new function will no longer look fuzzy.
iPhone running on iOS 3.x
Some iOS users don’t even know how (or can’t be bothered) to update their device to the new version or are running a jailbreaked version of their OS preventing them to update without losing that jailbreak. So as a result, a very small percentage of iOS users will probably still run iOS 4.0 or even iOS 3.x. Older iOS versions than 3.0 are not even supported anymore by the app store itself so you don’t have to worry about those. By default an iOS app is compiled against the latest version of iOS which doesn’t even allow a iOS 3.0 user to download your app. If you want to make your app available to those users as well this is what you have to do.
First of all, to make an app support iOS 3.x you will have to set the deployment target to “iOS 3.0” in the build tab of the Info screen of your project in XCode:
This will allow iOS 3.0 users to run the app. But wait, we’re not done yet! The fact is your app might still be using iOS 4.x specific features even though you now configured it to run on iOS 3.0 and above. So the next thing you will have to do when running on iOS 3.x, is avoid calling methods or functions that were not yet available in iOS 3.x. If you’re not depending on specific frameworks that were not available in iOS 3.0 you can probably find alternative ways to accomplish the same thing. If you are depending on such frameworks (like Event Kit for calendar support for example) then there is no way around it. The only thing you can do is to in this case inform the user that calendar support is not available until he or she updates the device to the latest version. But hey, the app won’t crash, which is what will happen when trying to access a non-existing framework on iOS 3.x.
So when you want to call methods which are only available in iOS4.x and were not in iOS 3.0 you will have to check for availability like this:
<br> if ([tableView respondsToSelector:@selector(setBackgroundView:)]) {<br> [tableView setBackgroundView:myBackgroundView];<br> }<br>
Or maybe you want to call global functions that were not available in iOS 3.0. This is how to check for their availability:
<br> if (UIGraphicsBeginImageContextWithOptions != NULL) {<br> UIGraphicsBeginImageContextWithOptions(CGSizeMake(30, 30), YES, 0.0);<br> } else {<br> UIGraphicsBeginImageContext(CGSizeMake(30, 30));<br> }<br>
But in some cases, the app just behaves differently in iOS 4.x compared to iOS 3.0. For example a button is not rendered properly or some other kind of bug is triggered. In this case you will have to check the device version to make a decision to be able to provide a work around.
<br> [[UIDevice currentDevice] systemVersion]<br>
This returns a version string of the device’s version, for example “4.0.1” or “3.0″. Only check for specific device versions to make a decision if you couldn’t solve it using one of the first two options I described.
iPod Touch
The iPod Touch is basically an iPhone you can’t make phone calls with. So it is similar enough to the iPhone to run most of the apps in the app store. Therefore you don’t have to do anything on your part to make your app support it. The only thing is you can’t use features an iPod Touch doesn’t have (like a camera for example on older generations). See the previous section for an explanation of how to avoid calling methods, functions and frameworks that are not available on the iPod Touch.
Conclusion
It’s relatively easy to make your app support iPod touch, the retina display (high resolution) of the iPhone 4 and even provide backwards compatibility with iOS 3.x. So why not always take this approach for creating all your apps? It certainly extends your audience and makes it easier to maintain.
To make it support iPad as well it’s more work because you have to build a new user interface, but it will all be inside a single application! Having a single application to maintain saves some trouble making adjustments in the future.
My intention of this blog post was to explain the basics you need to know when you want your app to support multiple iOS devices. Since all this stuff isn’t documented in one place I thought it might be useful to do so. If something still isn’t clear, please leave a comment below!