9. The Last Mile

This chapter covers all the tasks needed to polish our application and get it ready for sale in the App Store. We’ll look at the details that go into a finished app, from icons and startup screens to localization and build settings. Finally, we’ll examine the process of building the app for distribution—both for ad hoc distribution and for sale in the iTunes App Store.

The Final Touches

This is a grab bag of additional features and settings. Some are required before we can submit our application, others are strongly recommended, and a few merely add a touch of convenience to our apps.

Application Artwork

Our application expects a number of icons and other images. These are not functional parts of the application itself. Rather, they are used by the system to represent our application in a variety of circumstances.

Icons

The system will use both application icons and search icons to represent our application. The application icon appears on the phone’s home screen. The search icon appears in search results. Different devices require images of different sizes. We can use whatever names we wish, but the images must be PNG files. See Table 9.1 for the details.

Table 9.1 Icon Sizes

image

There’s an easy way and a hard way to add these icons. The easy way is to simply open the target’s summary settings. Scroll down until you find the icon settings, and drag the icons into place. Unfortunately, this only lets us set the application icons.

The search icons are optional. They will be generated automatically using our application icon. However, for the best appearance, we really should create custom icons at the correct resolution. To add these, we need to modify the Info.plist file directly.

Let’s add icons to Health Beat. You can create your own icons or copy them from the source code at www.freelancemadscience.com/source. Start by adding all the icons to our project. Then, open Health Beat-Info.plist and add a new key. Select Icon files (iOS 5) from the drop-down list. This will automatically generate a dictionary with Primary Icon and Newsstand Icon entries.

The Primary Icon entry is also a dictionary. Expand it. It should contain two elements: an “Icon files” array and an “Icon already includes gloss effect” Boolean value. Expand the array and add new items to it. We will need four items.

Set the string values of these items to the names of our icon files without the extensions. If our Retina display icons follow the @2x naming convention, we don’t need to add them to this list. Simply add the name of the lower-resolution file, and the system will choose the Retina display version when appropriate.

If you’re using the Health Beat icons, the final settings should match Figure 9.1.

Figure 9.1 Icon settings

image
Launch Images

The system displays our application’s launch image as the application is initialized. Many developers use this as an opportunity to display a splash screen or advertisement, but this is actually discouraged.

Apple strongly recommends that we use a streamlined version of the application’s main interface as the launch image. We want to strip out anything that might change. Obviously, this includes date fields and table view contents, but it also includes button titles and other labels that need to be localized.

Displaying only a partial user interface has a psychological advantage. The user won’t accidentally try to use it until all the details are filled in. Furthermore, displaying a partial user interface creates the illusion that our application is launching faster. Our app seems snappier, and the users appreciate being able to get to work immediately.


The settings shown in this chapter only work for iOS 5 and later. For earlier versions, use the Icon files setting (not to be confused with the Icon file setting). This is exactly the same as the iOS 5 version’s inner Icon files key. And like the inner key, it should hold an array of filenames.

Devices running iOS 3.1.3 or earlier do not even recognize the Icon files key. Instead, they search through the app’s main bundle, looking for files with specific filenames. To support these devices, your icons must use the following names:

• iPhone Application

Icon.png

• iPad Application

Icon-72.png

• iPhone Search

Icon-Small.png

• iPad Search

Icon-Small-50.png

To support the broadest range of devices, you should use the fixed name convention, and add both the Icon files and the Icon files (iOS 5) keys. This will give us the best performance and the broadest range of features, while still supporting all our devices.


iOS uses filename conventions to distinguish the different launch screens. However, we usually don’t need to worry about these details, unlike with the icons. Most of the time, we can simply drag our launch screens into the proper locations on the target summary settings screen.

The iPhone only supports portrait launch screens. We must include a 320 × 480 PNG file for normal display, and a 640 × 960 PNG for Retina display.

The iPad supports both portrait and landscape. These must be a 768 × 1004 PNG file and a 1024 × 748 PNG file, respectively.


Note

image

The iPad also allows us to specify different images for landscape left, landscape right, and portrait upside down. We can also specify a separate launch image for all devices if the app is launched using a custom URL scheme. For more information on these cases, check out the “App-Related Resources” section of the iOS App Programming Guide.


iTunes Artwork

We also need an image to represent the app in iTunes. Create a 512 × 512 PNG file, and name it iTunesArtwork. Notice that the name does not have an extension. We need to include this file in our application’s main bundle for ad hoc distributions. Simply add it to the project. We will also use the file when we submit the application to iTunes Connect.

Required Capabilities

We must declare any special capabilities that our application requires (or explicitly prohibits). Most of the defined capabilities are hardware-based, but some (like Game Center or Location Services) have a software component.

The iOS system will not launch the application if the device does not meet its required capabilities. Furthermore, the iTunes App Store will use this information to generate its device requirements—preventing users from downloading applications that they cannot run.

To set the required capabilities, add a UIRequiredDeviceCapabilities key to the application’s Info.plist file. Set this key to either an array or a dictionary. If we use an array, then simply adding a feature’s key to the array means that the feature is required. If it’s not listed, the app can manage without it.


Note

image

Your app may be rejected from the App Store if it needs a capability but does not properly declare that requirement in the Info.plist.


If you use a dictionary, you should give each feature in the dictionary a true or false Boolean value. If it’s true, the app requires the capability. If it’s false, the app explicitly prohibits the capability. If the feature is not included in the dictionary, it’s optional.

All the capability keys are listed here. For more information about these keys, refer to the “App-Related Resources” section of the iOS App Programming Guide.

accelerometer

armv6

armv7

auto-focus-camera

bluetooth-le

camera-flash

front-facing-camera

gamekit

gps

gyroscope

location-services

magnetometer

microphone

opengles-1

opengles-2

peer-peer

sms

still-camera

telephony

video-camera

wifi

Deployment Target

There are two build settings that determine which SDK our application uses to compile, and which version of the OS it supports: the base SDK and the iOS deployment target.

The base SDK should always be set to the latest version of iOS. In fact, the default setting is Latest iOS—which will automatically select the latest version available. We should never need to touch this setting.

The deployment target, on the other hand, lets us specify the earliest version of the OS that can still run our app. We can set the deployment target either directly in the target’s build settings or at the top of the target’s summary page. Xcode 4.2 lets us select any major and minor build number, starting with iOS 3.0.

Just to be clear, the application is compiled using the latest SDK, but it may still run on earlier devices. This works through the magic of weak linking.

The compiler will compare the symbols in the frameworks of the base SDK and the deployment target SDK. Anything that’s available in the base SDK but not available in the deployment target will be weak linked. This means that when the process is running, the symbol does not need to be present. As long as a missing symbol isn’t actually called, the application will continue to run normally. Of course, calling a missing symbol will cause a crash.

This means we can include iOS 5-only features in an app targeting iOS 3 and above. We just need to perform runtime checks before calling any iOS 5-only code, and degrade gracefully if those features are not available.

To check if a class is available, we simply call [<class name> class]. If this returns nil, the class is not available. To see if a method is available, we simply call the object’s respondsToSelector: method. To see if a function is available, check to see if the function’s name evaluates to NULL.

if ([UIDocument class]) {
    // We can use UIDocument.
} else {
    // We must use old-school file I/O.
}
if ([self respondsToSelector:
     @selector(childViewControllers)]) {
    // We can create a custom UIViewController container.
}
if (UIAccessibilityIsClosedCaptioningEnabled != NULL) {
    // The function is safe to use.
}

Unfortunately, the [<class name> class] test is only available if the base SDK is 4.2 or greater, and if the deployment target is 3.1 or greater. So if you’re supporting iOS 3.0, you need to use a more verbose test.

Class cls = NSClassFromString(@"UIDocument");
If (cls) {
    // We can use the document.
} else {
    // We still have to use old-school file I/O.
}

Additionally, if you’re going to be developing for earlier devices, you will need to download the debugging support. Select Xcode > Preferences from the main menu. Switch to the Downloads tab and download the required components.

On the surface, this is amazing. It means we can have our cake and eat it too. We can support old iOS 3.0 phones while also on newer devices enabling the newest iOS 5 features, like iCloud storage and Core Location regions. However, there is one huge problem here. There is no way to check the code at compile time and verify that we aren’t accidentally calling something above the deployment target in a generally reachable branch.

Things aren’t so bad when you’re just adding a new feature to an existing app. You know that the code you’re adding is above the deployment target, and you can take care to isolate it properly. The real problem comes in when you’re doing general coding or debugging. It’s so easy to unknowingly use parts of the SDK that are above the deployment target—especially when using autocomplete.

Unfortunately, there’s only one way to catch these errors: testing. Sure, I like testing. I’m a huge fan of testing, but testing alone is not a sufficient solution for this problem. Here’s the hard, cold truth: It’s very hard (I would say impractical if not impossible) to make sure that we actually execute every possible branch of our code during our test cycles. And if we don’t test every branch, we don’t really know if we’re safe. Above-deployment API calls may be scattered throughout any part of our code, lying in wait like little land mines, just waiting to kill our apps.

So, if you go down this route, test your code. Test it hard and test it often. If possible, find a bunch of beta testers who still run older versions of iOS. Otherwise, you’re just asking for a bunch of bad reviews when your app starts crashing on older devices.

Finally, there are also some important limitations that weak linking just cannot work around. Storyboards, for example, are only available on iOS 5 and later. ARC is available for iOS 4.0 and above, but weak references are not supported before iOS 5. Therefore, if you want to support earlier devices, you must use nibs and manual memory management.

Localization

Localization involves adapting our application to two or more culturally distinct markets. People often think about localization in terms of translating written text—and it can involve a lot of translation. However, it also involves a wide range of other cultural aspects that have nothing to do with language. For example, we’ve already used NSNumberFormatter to create locally formatted numbers. There, it’s not about language—we’re not translating the number; we’re simply choosing the best representation based on our user’s locale. Similarly, a stop sign icon should look very different in Japan than it does in the US. Both of these are prime examples of localization.

Localization affects a wide range of application features, including:

• Storyboards and nibs

• Static text

• Icons and graphics

• Sounds and spoken words

• Dynamically generated text

• Text editing

• Sorting orders

Xcode supports localization by creating localized bundles. These bundles are represented by directories ending in .lproj. The localized bundles can be used to distinguish between different languages or, in some cases, even different regional dialects. iOS will try to select the best match, based on the device’s settings; however, it’s generally best to use the most general location specifiers possible.

When we load a resource from our application bundle, the system starts searching in the general bundle. If it cannot find a match, it begins searching through the localized bundles. The actual search order is based on the user’s preferences. By placing localized resources in the correct bundles, we ensure that our application loads the correct versions at runtime.

We have a number of tools to help ease the internationalization effort, especially when it comes to finding and translating string values.

ibtool

This command-line utility can be used to extract strings from a nib file. The resulting string file can then be translated into another language. Once that is done, ibtool can merge the translated strings back with the original nib to create a translated nib file.

NSLocalizedString()

This method and its siblings will return a localized string value for a given key. NSLocalizedString() is the simplest. It takes two parameters: the key and a comment. It then searches the bundle for the Localizable.strings file, and then it searches that file for the key. If a match is found, it returns the string associated with the key; otherwise, it returns the key itself. The other variants let us search different files, return different default values, or otherwise modify the search. Also note that the comment argument is not used at runtime. Instead, it is used by genstrings when creating our .strings files.

genstrings

This command-line utility can parse C and Objective-C files and can find all the keys declared using one of the NSLocalizedString() methods. It will then build the .strings files containing all the unique values it found. This file can then be sent to translators, and the translated versions can be placed in the appropriate language bundles.

Additionally, we don’t need to translate every single string in our application. We only need to localize the strings that the user actually sees. Strings used as internal keys or as the names of notifications should be left alone.

For more information, see the Internationalization Programming Topics.

Accessibility

Recently, iOS has received a lot of praise and press for its excellent accessibility features. Out of the box, iOS provides a wide range of alternate input and output settings to assist people with low vision or blindness, hearing disabilities, and motor or physical disabilities. For the most part, these features are available to our application for free. We may need to be a little careful when creating custom gestures, since assistive touch won’t support them, but other than that, we can focus all our attention on supporting VoiceOver.

For most standard controls, we just need to set the Accessibility settings in Interface Builder. These can be found in the Identity inspector. The label is a string that succinctly identifies the control. For example, “Units” or “Enter Weight.”

The hint is a brief string that describes the effect of performing an action on the control. This should avoid mentioning either the control or the action. For example, “enter a new weight” not “select this text field to enter a new weight.”

This, however, is just the beginning. iOS accessibility support provides a number of methods to help truly customize and refine the interface. I highly recommend reading through the Accessibility Programming Guide for iOS for more information.

File Sharing

As we have seen, iOS 5 added document sharing using iCloud. However there are some older file sharing techniques we can still use. Even in the age of iCloud, these techniques have important roles to play.

For example, adding the UIFileSharingEnabled key to our application’s Info.plist and setting its value to YES shares our application’s Document directory with iTunes. From within iTunes, the user can see all the files in the Document directory. They can add new files and delete existing files.

This is still particularly useful if your users are likely to load a number of large files. Over-the-wire transfers from iTunes are still the fastest way to get large amounts of data onto our device. Furthermore, documents shared this way do not take up space in iCloud storage (though they may take up space in iCloud backup, depending on how the device is configured).

Applications can also transfer documents among themselves. To transfer a document to other applications, simply create an instance of UIDocumentInteraction Controller. Then call either presentOpenInMenuFromBarButtonItem:animated: or presentOpenInMenuFromRect:inView:animated:, depending on whether you want to anchor the menu to an arbitrary rectangle or to a bar button.

- (IBAction) exportButtonPressed:(id)sender {
    // Open file in other apps.
    UIDocumentInteractionController* controller =
    [UIDocumentInteractionController interactionControllerWithURL:
        fileURL];
    [controller presentOpenInMenuFromBarButtonItem:sender
                                          animated:YES];
}

The system will dynamically create a menu, listing all the applications that have registered support for the given document type.

The complement to this is, of course, that our applications can also register all the documents that they support. This requires two steps. First, add an appropriate document type to the target’s Document Types list. We already did this in the “Preparing the Application” section of Chapter 6, when we registered our Health Beat History document type. But when you’re using pre-existing document types, it’s even easier.

Click the project icon, and make sure the correct target is selected. Then select the Info tab and expand the Document Types list. Click the add button and select Add Document Type.

Expand the type, and give it a name. In the Types field, enter its UTI. You can find a complete list of system-supported UTIs in the “System-Declared Uniform Type Identifiers” section of the Uniform Type Identifiers Reference. For example, to register to open text files, set the document Types field to public.text.

Next, in application:didFinishLaunchingWithOptions:, we need to check the options argument for the UIApplicationLaunchOptionsURLKey. If this key is present, we need to try to open the file at the corresponding URL.

NSURL* url =
[launchOptions objectForKey:UIApplicationLaunchOptionsURLKey];
if (url != nil) {
    // Open the file from the URL.
}

Building for Distribution

Once everything’s ready, it’s time to build our application for distribution. There are two ways to do this. First, we can build an ad hoc distribution. This allows us to distribute our application to up to 100 devices. We often do this as part of our application’s testing, letting us send the application out to a select group of beta testers.

To create an ad hoc build, we need to first create a distribution provisioning profile. Log into your account at Apple’s Developer site (http://developer.apple.com/iphone), and click the link for the iOS Provisioning Portal (it should be in the upper-right corner).

Before creating a new profile, be sure to add all of your test devices. We can have up to 100 test devices at any one time. You will need the unique device identifier (UDID) from each device. Your testers can get the ID by viewing the device’s summary in iTunes. Click the serial number to view the UDID.

With all the UDIDs in place, select Provisioning from the left-hand column and select the Distribution tab. Then click the New Profile button.

Select Ad Hoc distribution. Enter a profile name, and select the App ID. Then select the devices you are going to authorize. When that’s done, press Submit. If the provisioning portal seems to be taking a while, you may want to refresh the page. Once the distribution profile is created, download it, and then double-click it to automatically import it into Xcode.

Now we need to create an ad hoc build configuration. Select the project icon in the navigator, but this time select the Health Beat project—not the target. Make sure the Info tab is selected. In the Configurations settings, click the + icon and select Duplicate “Release” Configuration. Name this configuration Ad Hoc.

Switch to the Build Settings tab and scroll down until you find the Code Signing settings. Switch the code signing identity for the Ad Hoc build configuration to our new Ad Hoc distribution profile (Figure 9.2).

Figure 9.2 Setting the code signing identity

image

Next, we have to edit our scheme. In the Archive action settings, change the Build Configuration setting to Ad Hoc. That’s it. Click OK. We can now build and distribute our application. Make sure you have a connected device or the generic iOS Device selected in the scheme. Then select Product > Archive from the main menu.

To access this archive, open the Organizer and select the Archives tab. Highlight the version you wish to share, and click the Share button. In the pop-up screen, leave the Contents option set to the iOS App Store Package (.ipa), but change the Identity setting to the Ad Hoc distribution profile. Then click Next, and select a location to save it.

You can then distribute this file to your beta testers. Users can use either iTunes or Xcode to load the ad hoc application onto their device. For example, on a Mac you would simply drag the application down to the iTunes icon and then sync your device.

Submitting to the App Store

Next, we can submit our application to the App Store for distribution. The procedure is similar. We need to create a distribution profile for the App Store. We’ll also need to make another build configuration to use the distribution profile. This is essentially the same as what we did for the ad hoc distribution.

Next, we need to sign up for an iTunes Connect account. We also need to gather all the required information for our app:

• Description

• Categories

• Parental control rating

• Keywords

• SKU number

• Application URL

• Support URL

• Screen shots

• Support email address

• End user license agreement

• 512 × 512 application icon

• Price

• Availability date

• Available territories

Finally, we modify the scheme to use the correct build configuration. In most cases, I actually prefer to create a new scheme specifically for distribution builds. Archive the app. Then from the Organizer’s Archives tab, we can validate and submit our app.

Remember that all applications submitted to the iTunes App Store must follow both the App Store Review Guidelines and the Human Interface Guidelines. Reviews are typically performed within seven days, and you can monitor the status from iTunes Connect. Good luck.

Wrapping Up

This chapter covered a broad range of topics. If it didn’t answer all your questions, I hope it at least pointed you in the right direction and helped you find the solutions you need.

And that’s all for the book. I hope the information has proven useful. However, the fun doesn’t end here. Check out the book’s website at freelancemadscience.com/book/ for two bonus chapters—additional material that we just couldn’t squeeze in between this book’s covers.

Bonus Chapter A, “From iPhone to iPad,” covers the differences in developing for the iPad. We also convert Health Beat into a Universal application, capable of running on both platforms. Bonus Chapter B, “Other Tools of the Trade,” discusses the tools, tips, and techniques behind source control, unit testing, performance testing, and debugging.

The website also hosts the book’s FAQs and errata, as well as a forum for discussion. Please stop by and leave your questions or comments. I look forward to continuing the conversation with you online.

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

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