iPhone Tutorial: Better way to check capabilities of iOS devices

The iPhone OS started off with a single device, the original iPhone, ala, iPhone 1,1. In the last three years, Apple has been innovating hard and introduced multiple devices running the same operating system with different capabilities. For example, the original iPod touch, iPod 1,1 wasn’t able to record audio input, and till date iPod Touch cannot vibrate as a result of an alert. There are many such subtle differences between different iOS devices and it’s the developer’s effort to make sure that the code runs properly on all devices.

Problems using the device model

Most developers have resorted to reading the hw.machine parameter to check if the device is an iPhone or iPod touch. Another lousy way is to read the [UIDevice currentDevice].model. The problem with these methods are that, you are essentially comparing the device name with a hard-coded value. As such, code like

Today, this code will work perfectly, but with next release of the iPod Touch or the iPad that might probably have a front facing camera, your app (or the video conferencing feature) will no longer work on the new device though it’s (might be) capable of video conferencing.

There are Apple defined ways to check the hardware capabilities rather than assuming features based on the model string. In this tutorial, we will walk you through the various pitfalls that any iOS developer may encounter and provide solutions on how to combat them. Also provided is a complete source code and an elegant, drop dead simple to use device capabilities helper class.

Gonna Vibrate the device to alert the user? Read this first

Apple has documented two functions that would vibrate the iPhone. But vibration hardware is present only on iPhones (at least currently). So how will you alert your user who uses the app on iPad or iPod touches? Clearly, checking the model is not the way to go. Apple has provided an elegant solution to this. There are two seemingly similar functions that take a parameter kSystemSoundID_Vibrate

Both the functions vibrate the iPhone. But when you use the first function on devices that don’t support vibration, it plays a beep sound. The second function on the other hand does nothing on unsupported devices. So if you are going to vibrate the device continuously, as a alert, common sense says, use function 2.

Phone Call Capable?

Checking if a device is capable of making a phone call is as easy as making a function call to check if the device can handle URLs of type “tel://”

Again, in future if there is a 7″ iProduct that sits somewhere in between the iPad and iPhone and has call capabilities, this method will work on that device as well.

Sorry, you are not running on iPhone, This feature requires an iPhone.

if your app uses this feature to detect a phone from an iPod. In most cases, you show a telphone number and have a call button to make a phone call. On iPod Touch or other devices, just hide that button. That gives a better user experience than a error message. The user already knows that he doesn’t have an iPhone and his device cannot make a phone call. You don’t have to repeat that.

Email capability

Email is a bit tricky thing. You cannot always assume the all devices will support in-app email. If you read my previous tutorial on in-app email, I would have mandated to check the email capability using

[MFMailComposeViewController canSendMail]

[MFMailComposeViewController canSendMail]

This class is available from iOS 3.0. You might think that, because I always set the iPhone OS Deployment target to 3.0, I don’t have to check this and can directly present the modal email sheet. But the code will crash when the user has no email configuration setup in the Mail app. As such, you should always check for this capability before you show the in-app email sheet.

SMS capability

For SMS support, you can either use [MFMessageComposeViewController canSendText] or better check if the device can handle URLs of type “sms://”

The reason I would suggest using the latter is, MFMessageComposeViewController isn’t available on iPhone OS 3.2 and below. You app might crash if you try to send a non-existant message to a non-existant class.

Camera/Flash/Video support

Most of the camera related availability support is exposed through the UIImagePickerController. The UIImagePickerController has class methods that can be used to check if there is a camera hardware present in the device. Do note that, it’s important to check even for the availability of the Photo Library before you ask the user to pick photos. For example, if the user’s iPhone is new and he doesn’t have any photos in his Photo Library, it’s better to show an error rather than crash the application. As such, the method below returns NO when there is no photos in the user’s library.

Gyroscope support

With iPhone 4, Apple added yet another hardware to the iPhone, namely the Gyroscope. Using Gyroscope. The Gyroscope related functions are grouped together under the CoreMotion framework. The CMMotionManager has a property called gyroAvailable to check if the device has gyroscope. Good news here is that, even if you make calls to CMMotionManager related to Gyroscope, the SDK converts them no-op on unsupported devices.

Multitasking support

Not all devices support multitasking even on iOS 4. The iPhone 3G, and the iPod touch 2nd generation can be upgraded to iOS 4, but still will not get any of the multitasking or fast app switching benefits. I’m just re-writing Apple’s own code here

Source Code

To make life easier, I’ve put together a sample application and a helper class that demonstrates most of these capabilities. You can download it from here or go to github. Again, it’s a singleton class based on my previous xcode singleton template

MKDeviceHelper.zip

Using this Class

Just drag the two files MKDeviceHelper.h and it’s counterpart. Add the frameworks, AVFoundation, MessageUI, AudioToolbox, CoreLocation, MobileCoreServices and CoreMotion frameworks. Build your app and you are good to go. If you can’t find any of the XCode. The current version works fine on XCode 3.2.3

Note that these frameworks are dynamically linked. They will in no way bloat your app.

Licensing

My only request is don’t pass of this code as your own. Fork it or do whatever you want, commercial/non-commercial but retain a reference to this blog post in the code and don’t remove the URL in the source code files.