Chapter 16: Running on Multiple iPlatforms and iDevices

The iOS SDK was announced to the public in February 2008. At that time, there were only two devices using it: iPhone and iPod touch. Apple has since been innovating vigorously, and in 2010 it introduced another bigger brother to the family, the iPad. In 2010, another new device running iOS was introduced: the Apple TV. Who knows what the future might hold—Apple might even announce an SDK for Apple TV development and may even enable running games from Apple TV controlled by your iPhone on iPod touch.

Every year, a new version of the SDK comes out along with at least two or three new device updates, and these new devices often come with additional sensors. The GPS sensor debuted with iPhone 3G, the magnetometer—a sensor used to show the direction of magnetic north (more commonly known as a compass)—debuted in iPhone 3GS, and the gyroscope (for life-like gameplay) in iPhone 4. The iPad was introduced later with a whole new UI, a far bigger screen than the iPhone, but without a camera. iPad added a couple of cameras (including a front-facing camera) in the second iteration, iPad 2. The iPad 2 was superceded by the new iPad, which has a better camera and features like face detection and video stabilization. Recently, Apple announced the iPhone 5, which has a larger screen than its predecessors. iPhone 5 poses another challenge in designing your user interfaces. I show you how to support iPhone 5 in your app later in this chapter.

Similarly, every version of the SDK comes with powerful new features: In App Purchases, Push Notification Service, Core Data, and MapKit support in iOS 3; multitasking, blocks, and Grand Central Dispatch in iOS 4; iCloud, Twitter integration, and Storyboards in iOS 5; and, PassKit in iOS 6, to name a few. When you use one of these features, you might be interested in providing backward compatibility to users running an older version of the operating system. Keep in mind, however, that if you’re using a feature available in a newer version of the SDK, you must either forget about old users (not a good idea) or write code that adapts to both users (either by supporting an equivalent feature for older users or by prompting them that additional features are available if they run a newer version).

As a developer, you need to know how to write code that easily adapts to any device (known or unknown) and platform. For that purpose, it’s easier to depend on Cocoa framework APIs to detect capabilities than writing code assuming that a certain sensor will be present on a given hardware. In short, developers need to avoid making assumptions about hardware capabilities based on device model strings.

This chapter looks at some strategies that can help you write code that adapts easily to multiple platforms and devices using the various APIs provided by Cocoa framework. You also learn how to adapt your code to support the new, taller, iPhone 5 In the course of this chapter, you write a category extension on the UIDevice class and add methods that check for features that aren’t readily exposed by the framework.

Developing for Multiple Platforms

The iOS debuted with a public SDK in version 2.0, and version 6.0 is the fifth iteration that is available for developers. One important advantage of iOS over competing platforms is that users don’t have to wait for carriers to “approve” their OS updates, and because the updates are free of charge, most users (more than 75 percent) get the latest available OS within a month. It’s usually fine for iOS developers to support just the two latest iterations of the SDK. That is, in late 2011 and early 2012, it was enough to support iOS 4 and iOS 5; now, in late 2012 to early 2013, it should be enough to support iOS 5 and iOS 6, all of which makes life easier for developers.

Configurable Target Settings: Base SDK Versus Deployment Target

To customize the features your app can use and the devices and OS versions your app can run, Xcode provides two configurable settings for the target you build. The first is your base SDK setting and the second is the iOS Deployment Target.

Configuring the Base SDK Setting

The first configurable setting is called Base SDK. You can configure this setting by editing your target. To do so, follow these steps:

1. Open your project and select the project file on the project navigator.

2. On the editor pane, select the target and select the Build Settings tab. The Base SDK setting is usually the third option here, but the easiest way to look for a setting in this pane is to search for it in the search bar.

You can change the value to “Latest iOS SDK” or any version of SDK installed on your development machine. The Base SDK setting instructs the compiler to use that version of SDK to compile and build your app, and this means it directly controls which APIs are available for your app. By default, new projects created with Xcode always use the latest-available SDK, and Apple handles API deprecation. Unless you have very specific reasons not to, stick to this default value.

Configuring the Deployment Target Setting

The second setting is the Deployment Target, which governs the minimum required OS version necessary for using your app. If you set this to a particular version, say 5.0, the AppStore app automatically prevents users running previous operating systems from downloading or installing your app. To cater to a wider audience, I recommend providing backward compatibility for at least one previous version of the OS. For example, if iOS 6 is the latest version, you should also support at least iOS 5. You can set the Deployment Target on the same Build Settings tab as the Base SDK setting.

When you’re using a feature available in iOS 6 SDK, but still want to support older versions, set your Base SDK setting to the latest SDK (or iOS 6) and your Deployment Target to at least iOS 5. However, when your app is running on iOS 5 devices, some frameworks and features may not be available. It’s your responsibility as a developer to adapt your app to work properly without crashing.

Considerations for Multiple SDK Support: Frameworks, Classes, and Methods

You need to handle three cases when you support multiple SDKs: frameworks, classes, and methods. In the following sections, you find out about the ways to make this possible.

Framework Availability

Sometimes a new SDK may add a whole new framework, which means that a complete framework is not available on older operating systems. An example from iOS 5 is the Twitter.framework. This framework is available only to users running iOS 5 and above. You have two choices here. Either set the deployment target to iOS 5 and build your app only for customers running iOS 5 and above or check whether the given framework is present on the user’s operating system and hide necessary UI elements that invoke a call to this framework. Clearly, the second choice is the optimal one.

When you use a symbol that’s defined in a framework that is not available on older versions, your app will not load. To avoid this and to selectively load a framework, you must weak-link it. To weak-link a framework, open the target settings page from the project settings editor. Then open the Build Phases tab and expand the fourth section (Link Binary With Libraries). You will see a list of frameworks that are currently linked to your target. If you haven’t yet changed a setting here, all the frameworks are set to Required by default. Click the Required combo box and change it to Optional. This will weak-link the said framework.

When you weak-link a framework, missing symbols automatically become null pointers, and you can use this null check to enable or disable UI elements.

An example on iOS 6 is the PassKit.Framework. When you use the built-in PassKit framework for storing user’s coupons, weak-link it and do a runtime check to see if it is available. If not, you have to implement your own methods to mimic that functionality.

When you link a framework that is present only on a newer version of the SDK, but you still specify the iOS Deployment target to a SDK older than that, your application will fail to launch and crash almost immediately. This will cause your app to be rejected. When you receive a crash report from the Apple review team stating that the app crashes immediately on launch (mostly without any useful crash dumps), this is what you have to look for. The fix for this crash is to “weak link” the framework. To learn more about debugging, read Chapter 19 in this book.

Class Availability

Sometimes a new SDK might add new classes to an existing framework. This means that even if the framework gets linked, not all symbols will be available to you on older operating systems. An example from iOS 4 is the UILocalNotification class defined in UIKit.Framework. This framework is linked with every iOS app, so when you’re using this class, you need to check for its presence by instantiating an object using the NSClassFromString method. If it returns nil, that class is not present on the target device. An example from iOS 5 is the UIStepper control. If you’re using this class, check for its existence.

Another method to check for class availability is to use the class method instead of NSClassFromString, as shown in the following code.

Checking for Availability of the UIStepper Control

if ([UIStepper class])  {

   // Create an instance and add it to the subview

} else {

   // create instance of a equivalent control and add it to subview

}

To use the class method, use the LLVM Clang compiler, and the deployment target should be 3.1 or later.

Method Availability

In some cases, new methods are added to an existing class in the new SDK. A classic example from iOS 4 is multitasking support. The class UIDevice has a method called isMultitaskingSupported. The following code checks for this class.

Code for Checking Whether a Method Is Available in a Class

if ([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)])  {

if([UIDevice currentDevice].isMultitaskingSupported)  {

    // Code to support multitasking goes here

  }

}

To check whether a method is available in a given class, use the respondsToSelector: method. If it returns YES, you can use the method you checked for.

If the method you’re checking is a global C function, equate it to NULL instead, as shown in the following code.

Checking Availability of a C Function

if (CFunction != NULL) {

  CFunction(a);

}

You have to equate the function name explicitly to NULL. Implicitly assuming pointers as nil or NULL will not work. Do note that it is not CFunction(). It’s just CFunction without the parenthesis. Checking the condition will not invoke the method.

Checking the Availability of Frameworks, Classes, and Methods

Although it’s quite easy to remember framework availability, it can be challenging to remember the availability of every single class and method. Equally difficult is reading through the complete iOS documentation to find out which method is available and which method is not. I recommend two different ways to check the availability of a framework, class, or method.

Developer Documentation

The straightforward way to check the availability of symbols or frameworks is to search in the Availability section of the developer documentation. Figure 16-1 is a screenshot from the developer documentation showing how to look for multitasking availability.

9781118449974-fg1601.tif

Figure 16-1 Multitasking availability in developer documentation

Macros in iOS Header Files

The other method for checking the availability of a method or class is to read through the header files. I find this easier than fiddling through the documentation. Just Cmd-click the symbol from your source code, and Xcode opens the header file where it’s defined. Most newly added methods have either one of the macro decorations shown in Figure 16-2.

Availability Macros

UIKIT_CLASS_AVAILABLE

__OSX_AVAILABLE_STARTING

__OSX_AVAILABLE_BUT_DEPRECATED

9781118449974-fg1602.tif

Figure 16-2 Multitasking availability in header file

It’s usually easier and faster to check availability of a class or method for a given SDK version from the header file. But not all methods will have this macro decoration. If it doesn’t, you have to look at the developer documentation.

If a method doesn’t have a macro decoration, it probably means that the method was added ages ago to the SDK, and you normally don’t have to worry if you’re targeting the two most recent SDKs.

Now that you know how to support multiple SDK versions, it’s time to focus on the meat of the chapter: supporting multiple devices. In the next section, you discover the subtle differences between the devices and learn the correct way to check for availability of a particular feature. In parallel, you also write a category extension class on UIDevice that adds methods and properties for checking features not exposed by the framework.

Detecting Device Capabilities

The first and most common mistake that developers made in the past, when there were only two devices (iPod touch and iPhone), was to detect the model name and check whether it was an “iPhone,” thereby assuming capabilities. This worked well for a year or so. But soon, when new devices with new hardware sensors became available, the method became highly prone to error. For example, the initial version of the iPod touch didn’t have a microphone; however, after the iPhone OS 2.2 software update, users could add one by connecting an external microphone/headset. If your code assumes device capabilities based on model name, it will still work, but it’s not correct and not the right thing to do.

Detecting Devices and Assuming Capabilities

Consider the following code fragment, which assumes the capabilities of the iPhone.

Detecting a Microphone the Wrong Way

if(![[UIDevice currentDevice].model isEqualToString:@”iPhone”])  {

        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@”Error”

message:@”Microphone not present”

delegate:self

       cancelButtonTitle:@”Dismiss”

otherButtonTitles: nil];

        [alertView show];

    }

The problem with the preceding code is that the developer has made a broad assumption that only iPhones will ever have microphones. This code worked well initially. But with the iOS software 2.2 update, when Apple added external microphone capability to iPod touch, the preceding code prevents users from using the app. Another problem is that this code shows an error for any new device introduced later—for example, iPad.

You should use some other method for detecting hardware or sensor availability rather than assume devices’ capabilities. Fortunately or unfortunately, these methods are scattered around on various frameworks.

Now, it’s time to start looking at various methods for checking device capabilities the right way and grouping them under a UIDevice category class.

Detecting Hardware and Sensors

The first thing to understand is that instead of assuming capabilities, you need to check for the presence of the exact hardware or sensor you need. For example, instead of assuming that only iPhones have a microphone, use APIs to check for the presence of a microphone. The first advantage of the following code is that it automatically works for new devices to be introduced in the future and for externally connected microphones.

What’s the second advantage? The code is a one-liner.

Correct Way to Check for Microphone Availability

- (BOOL) microphoneAvailable  {

AVAudioSession *session = [AVAudioSession sharedInstance];

return session.inputIsAvailable;

}

In the case of a microphone, you also need to consider detecting input device change notifications. That is, enable your Record button on the UI when the user plugs in a microphone, in addition to viewDidAppear. Sounds cool, right? Here’s how to do that.

Detecting Whether a Microphone Is Being Plugged In

void audioInputPropertyListener(void* inClientData,

AudioSessionPropertyID inID, UInt32 inDataSize, const void *inData)  {

    UInt32 isAvailable = *(UInt32*)inData;    

    BOOL micAvailable = (isAvailable > 0);

    // update your UI here

}

- (void)viewDidLoad  {

    [super viewDidLoad];    

AudioSessionAddPropertyListener(

kAudioSessionProperty_AudioInputAvailable,

audioInputPropertyListener, nil);

}

All you need to do here is to add a property listener for kAudioSessionProperty_AudioInputAvailable and on the callback check for the value.

With just few extra lines of code, you’re able to write the correct version of device detection code. Next, you extend this for other hardware and sensors.

AudioSessionPropertyListeners behave much like observing NSNotification events. When you add a property listener to a class, it’s your responsibility to remove it at the right time. In the preceding example, because you added the property listener in viewDidLoad, you need to remove it in the didReceiveMemoryWarning method.

Detecting Camera Types

The iPhone shipped with a single camera originally and added a front-facing camera later in iPhone 4. The iPod touch had no camera until the fourth generation. While the iPhone 4 has a front-facing camera, the iPad 1 (its bigger brother) doesn’t have one, whereas the newer iPad 2 has both a front-facing and a back-facing camera. All this means that you should not write code with device-based assumptions. It’s actually far easier to use the API.

The UIImagePickerController class has class methods to detect source type availability.

Checking for Camera Presence

- (BOOL) cameraAvailable  {

  return [UIImagePickerController isSourceTypeAvailable:

UIImagePickerControllerSourceTypeCamera];

}

Checking for a Front-Facing Camera

- (BOOL) frontCameraAvailable

{

#ifdef __IPHONE_4_0

  return [UIImagePickerController isCameraDeviceAvailable:

UIImagePickerControllerCameraDeviceFront];

#else

  return NO;

#endif

}

For detecting a front-facing camera, you need to be running on iOS 4 and above. The enumeration UIImagePickerControllerCameraDeviceFront is available only on iOS 4 and above because any device that has a front-facing camera (iPhone 4 and iPad 2) always runs iOS 4 and above. So you use a macro and return NO if the device runs iOS 3 or below.

Similarly, you can check whether the camera attached has video-recording capabilities. Cameras on iPhone 3GS and above can record videos. You can check that using the following code.

Checking for a Video-Recording Capable Camera

- (BOOL) videoCameraAvailable  {

  UIImagePickerController *picker =

[[UIImagePickerController alloc] init];

// First call our previous method to check for camera presence.

if(![self cameraAvailable])  return NO;

NSArray *sourceTypes = [UIImagePickerController availableMediaTypesForSourceType:

UIImagePickerControllerSourceTypeCamera];

  

  if (![sourceTypes containsObject:(NSString *)kUTTypeMovie]){

    return NO;

  }

  return YES;

}

This enumerates the available media types for a given camera and determines whether it contains kUTTypeMovie.

Detecting Whether a Photo Library Is Empty

If you’re using a camera, you will almost always use the user’s photo library. Before calling UIImagePicker to show the user’s photo album, ensure that there are photos in it. You can check this the same way you check for camera presence. Just pass UIImagePickerControllerSourceTypePhotoLibrary or UIImagePickerControllerSourceTypeSavedPhotosAlbum for the source type.

Detecting the Presence of a Camera Flash

So far, the only device to have a camera flash is the iPhone 4. In coming years, more and more devices will have a camera flash. It’s easy to check for camera flash presence using UIImagePickerController’s class method.

Checking for a Camera Flash

- (BOOL) cameraFlashAvailable  {

#ifdef __IPHONE_4_0

  return [UIImagePickerController isFlashAvailableForCameraDevice:

UIImagePickerControllerCameraDeviceRear];

#else

  return NO;

#endif

}

Detecting a Gyroscope

The gyroscope is an interesting addition to the iPhone 4. Devices introduced after iPhone 4, including the new iPad and iPhone 5, also have a gyroscope. It allows developers to measure relative changes to the physical position of the device. By comparison, an accelerometer can measure only force. Twisting movements cannot be measured by an accelerometer. Using a gyroscope, it’s possible for game developers to implement 6-axis control like that found in Sony’s PlayStation 3 controller or Nintendo’s Wii controller. You can detect the presence of a gyroscope using an API provided in the CoreMotion.framework.

Code to Detect the Presence of a Gyroscope

- (BOOL) gyroscopeAvailable  {

#ifdef __IPHONE_4_0

  CMMotionManager *motionManager = [[CMMotionManager alloc] init];

  BOOL gyroAvailable = motionManager.gyroAvailable;

  return gyroAvailable;

#else

  return NO;

#endif

}

If a gyroscope is a core feature of your app but your target device doesn’t have a gyroscope, you have to design your app with alternative input methods, or you can specify them in the UIRequiredDeviceCapablities key in your app’s info.plist, preventing devices without a gyroscope from installing the app. You learn more about this key later in the chapter.

Detecting a Compass or Magnetometer

Compass availability can be checked using the CoreLocation.framework class CLLocationManager. Call the method headingAvailable in CLLocationManager, and if it returns true, you can use a compass in your app. A compass is more useful in a location-based application and augmented reality-based applications.

Detecting a Retina Display

As an iOS developer, you already know that catering to a retina display is as easy as adding an @2x image file for every resource you use in the app. But in cases where you download the image from a remote server, you need to download images at twice the resolution on devices with retina display.

A good example of this is a photo browser app like, say, a Flickr viewer or Instagram. When your user launches the app in iPhone 4 or the new iPad or iPhone 5, you should be downloading images of double the resolution you do for non-retina display devices. Some developers choose to ignore this and download higher resolution images for all devices, but that is a waste of bandwidth and might even be slower to download over EDGE. Instead, download higher-resolution files after determining that the device has a retina display. Checking for this is easy.

Retina Display Capable

- (BOOL) retinaDisplayCapable  {

int scale = 1.0;

UIScreen *screen = [UIScreen mainScreen];

if([screen respondsToSelector:@selector(scale)])

  scale = screen.scale;

if(scale == 2.0f) return YES;

else return NO;

}

With this code, you look for the mainScreen of the device and check whether the device is capable of showing high-resolution retina display-capable graphics. This way, if Apple introduces an external retina display (maybe the newer Apple Cinema Displays) and allows the current generation iPads to project to it in retina mode, your app will still work without changes.

Detecting Alert Vibration Capability

As of this writing, only iPhones are capable of vibrating to alert the user. Unfortunately, there is no public API for checking whether a device is vibration-capable. However, the AudioToolbox.framework has two methods to selectively vibrate only iPhones:

AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);

AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);

The first method vibrates the iPhone and plays a beep sound on iPod touch/iPad. The second method just vibrates the iPhone. On devices not capable of vibrating, it does’t do anything. If you’re developing a game that vibrates the device to signify danger or a Labyrinth game where you want to vibrate whenever the player hits the wall, use the second method. The first method is for alerting the user, which includes vibration plus beeps, whereas the second is just for vibrations.

Detecting Remote Control Capability

iOS apps can handle remote control events generated by buttons pressed on the external headset. To handle these events, use the following method to start receiving notifications:

[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

Implement the following method in your firstResponder:

remoteControlReceivedWithEvent:

Be sure to turn this off when you no longer need the events by calling

[[UIApplication sharedApplication] endReceivingRemoteControlEvents];

Detecting Phone Call Capability

You can check whether a device can make phone calls by checking if it can open URLs of type tel:. The UIApplication class’s canOpenURL: method is handy for checking whether a device has an app that can handle URLs of a specific type. tel: URLs are handled by the phone app on iPhone. The same method can also be used to check whether a specific app that can handle a given URL is installed on a device.

Phone Call Capabilities

- (BOOL) canMakePhoneCalls  {

  return [[UIApplication sharedApplication]

canOpenURL:[NSURL URLWithString:@”tel://”]];

}

A word about usability: Developers should completely hide features specific to phones on iPod touch devices. For example, if you’re developing a Yellow Pages app that lists phone numbers from the Internet, show the button to place a call only on devices that are capable of making phone calls. Do not simply disable it (because nothing can be done by the user to enable it) or show an error alert. There have been cases where showing a “Not an iPhone” error on an iPod touch leads to rejection of the app by the app review team.

In App Email and SMS

Although In App email and In App SMS are technically not sensors or hardware, not every device can send e-mails or SMSs. This includes iPhones as well—even those that run iOS 4 and above. Although MFMessageViewController and MFMailComposeViewController are available from iOS 4, and even if your app’s minimum deployment target is set to iOS 4, you still need to know and understand the common pitfalls when using these classes.

A common case is an iOS device that has no configured e-mail accounts and therefore cannot send e-mail, even when it’s technically capable of sending one. The same applies to SMS/MMS. An iPhone that doesn’t have a SIM card cannot send text messages. You need to be aware of this and always check for capabilities before attempting to use this feature.

Checking for this capability is easy. Both MFMessageComposeViewController (for In app SMS) and MFMailComposeViewController (for In App email) have class methods canSendText and canSendMail, respectively, that can be used.

Checking Multitasking Awareness

Checking whether a device can multitask is straightforward. As you saw earlier in this chapter, you have to check whether the method isMultitaskingSupported is available, as shown in the following code. If it returns YES, you can write multitasking-related code. Otherwise, remember your app’s state and continue when the app is launched again.

Is Multitasking Available?

if ([[UIDevice currentDevice] respondsToSelector:

@selector(isMultitaskingSupported)])  {

  if([UIDevice currentDevice].isMultitaskingSupported)  {

    // Code to support multitasking goes here

  }

}

But there is something more. On devices that don’t support multitasking, your application delegate will not receive the following callbacks:

– applicationDidEnterBackground:

– applicationWillEnterForeground:

This means that any part of your startup code and initialization sequence you write in applicationWillEnterForeground: should be written in applicationDidFinishLaunchingWithOptions: as well as for nonmultitasking capable devices.

Similarly, the teardown code (including your Core Data-managed context save methods) that you write in applicationDidEnterBackground: needs to be written in applicationWillTerminate: as well.

Obtaining the UIDevice+Additions Category

The code fragments you’ve seen so far in this chapter are available as a UIDevice category addition. You can download them from the book’s website.

It has just two files: UIDevice+Additions.h and UIDevice+Additions.m. You have to link necessary frameworks to avoid those pesky linker errors because this class links to various Apple library frameworks. But don’t worry; they are dynamically loaded, so they don’t bloat your app.

Supporting the iPhone 5

iPhone 5 was announced in September 2012, and it poses a new challenge to developers: a bigger screen. iOS developers have never been required to support multiple device resolutions in the past. Fret not, Apple has made things easy for us. The first step is to add a launch image ([email protected]). As shown in Figure 16-3, when you build your project with Xcode 4.5, you will see a warning: “Missing Retina 4 launch image.” Click Add to add a default launch image to your project.

9781118449974-fg1603.tif

Figure 16-3 Xcode 4.5 prompting for addition of a launch image for iPhone 5

The app will then launch in full screen without letter boxing. However, most of your nib files will still not scale properly. The next step is to check the auto resizing mask of every nib file and ensure that the view inside the nib file automatically sizes based on the super view’s height. Figure 16-4 illustrates this.

9781118449974-fg1604.tif

Figure 16.4 Changing the autoresizing mask property using Interface Builder

The properties to use are UIViewAutoresizingFlexibleTopMargin, UIViewAutoresizingFlexibleBottomMargin, and UIViewAutoresizingFlexibleHeight.

You use the UIViewAutoresizingFlexibleHeight for the top-most view so that it autosizes with the main window. You use the UIViewAutoresizingFlexibleTopMargin and/or UIViewAutoresizingFlexibleBottomMargin for subviews. Use UIViewAutoresizingFlexibleTopMargin property when you want the subview to be “pinned” to the bottom (the top margin is flexible). Use the UIViewAutoresizingFlexibleBottomMargin when you want the subview to be “pinned” to the top (the bottom margin is flexible).

Remember, a flexible bottom margin pins the UI element to the top and a flexible top margin pins the UI element to the bottom. Note too that when you use Cocoa Auto Layout, you don’t have to deal with auto resize masks.

If you have hard-coded the height of a view to 460 or 480, you might have to change this using bounds. For example, you use

  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

instead of

  self.window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];

Finally, any CALayer that you added to the view will have to be manually resized. The following code shows how to do this. This code assumes you have a “patternLayer” for your all your view controllers.

Resizing a CALayer for iPhone 5 compatiblity

       -(void)viewWillLayoutSubviews {

  self.patternLayer.frame = self.view.bounds;

  [super viewWillLayoutSubviews];

}

iPhone 5 requires a new instruction set—the armv7s. Only the latest version of Xcode (4.5 as of this writing) supports generating an armv7s instruction set. Note that Xcode 4.5 no longer supports armv6 and deprecates iPhone 3G and older devices.

UIRequiredDeviceCapabilities

So far, you’ve found out how to conditionally check a device for specific capabilities and use them if they are present. In some cases, your app depends solely on the presence of particular hardware, and without that hardware your app will be unusable. Examples include a camera app like Instagram or Camera+. The core functionality of the app doesn’t work without a camera. In this case, you need something more than just checking for device capabilities and hiding specific parts of your app. You normally won’t need devices without a camera to use or download your app.

Apple provides a way to ensure this using the UIRequiredDeviceCapabilities key in the Info plist file. The following values are supported for this key:

telephony wifi sms, still-camera

auto-focus-camera front-facing-camera camera-flash

video-camera accelerometer gyroscope

location-services gps magnetometer

gamekit opengles-1 opengles-2

armv6 armv7 peer-peer

accelerometer Bluetooth-le microphone.

You can explicitly require particular device capabilities or prohibit installation of your app on devices without a specific capability. For example, you can prevent your apps from running on devices with video-camera by setting the video-camera key to NO. Alternatively, you can mandate the presence of video-camera by setting the video-camera key to YES.

Apple doesn’t allow you to submit an update to an existing app and prevent it from running on a specific device that was supported before the update. For example, if your app supported both iPhone and iPod touch in version 1.0, you cannot submit an update that prevents it from running on either device. Put another way, you cannot introduce a mandate for the presence of particular hardware later in your app’s product life cycle. The submission process on iTunes Connect will fail and show you an error. The opposite is allowed, however. That is, if you have been excluding a device previously, you can allow installations on it in a subsequent version. In other words, if version 1 of your app supported only iPhones, you can submit a version 2 to support all devices.

There is one exception to this rule. If you have been supporting armv6 in your current application, you can submit a new app that removes support for armv6 and hence the original iPhone and iPhone 3G. In fact, Xcode 4.5 doesn’t allow you to build for armv6 devices (iPhone 3G, iPod touch 2nd generation, the original iPhone) and versions below Xcode 4.5 don’t allow you to build for armv7s devices (iPhone 5). So if you support iPhone 5, you have to forego support for iPhone 3G.

Adding values to the UIRequiredDeviceCapablities key will prohibit your app from being installed on devices without the capabilities you requested. If you specify that telephony is needed, users cannot even download the app on their iPod touch or iPad. You must be certain that this is your expected behavior before using this key.

Summary

This chapter discussed various techniques and tricks to help run your app on multiple platforms. It also looked at the various hardware and sensors available for iOS developers and how to detect their presence the right way. You incrementally wrote a category extension on UIDevice that could be used for detecting most device capabilities. You also learned about supporting the new iPhone 5’s screen size. Finally, you learned about the UIRequiredDeviceCapablities key and how to completely exclude devices without a required capability. My recommendation is to depend on the methods explained in this chapter and use the UIRequiredDeviceCapablities key sparingly.

Further Reading

Apple Documentation

The following documents are available in the iOS Developer Library at developer.apple.com or through the Xcode Documentation and API Reference.

Understanding the UIRequiredDeviceCapablities Key

iOS Build Time Configuration Details

Other Resources

MK blog. (Mugunth Kumar) “iPhone Tutorial: Better way to check capabilities of iOS devices”http://blog.mugunthkumar.com/coding/iphone-tutorial-better-way-to-check-capabilities-of-ios-devices/

Github. “MugunthKumar/DeviceHelper”https://github.com/MugunthKumar/DeviceHelper

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.70.88