Welcome to my iphone development code blog

Welcome to my iphone development code blog
"SIMPLICITY IS BEST PROFESSION"

Friday, June 4, 2010

Intercepting status bar touches on the iPhone

You can configure your iPhone applications so that a touch in the status bar will scroll a UIScrollView to the top. I'll show you how you can intercept this touch event to use status bar touches for other purposes. The sample application will show a hidden drawer that slides out from the status bar when you tap it.
Touches in the status bar

A lesser known user-interface feature on the iPhone is that touches in the status bar will usually scroll the main UIScrollView to the top, providing a quick way to scroll to the top of long documents.

This will work in your application when exactly one UIScrollView returns YES for the scrollsToTop property (YES is the default). If more than one UIScrollView returns YES for this property (or the UIScrollView's delegate returns NO from scrollViewWillScrollToTop:) the scroll to top functionality will be disabled.

That's the ordinary functionality but how do we achieve different functionality?
The HiddenDrawer sample appliction



These screenshots show the HiddenDrawer sample application. When the status bar is tapped on the left, the hidden drawer animates out from under the status bar, resulting in the state shown on the right.
Stealing status bar touch events

The trickiest part of the sample application is detecting a touch in the status bar.

By implementing a custom setContentOffset:animated: method on a UITableView and setting a breakpoint in that method, you can see in the debugger stack that the UIApplication sendEvent: method is invoked for status bar touches, so that's where we'll begin.
CustomApplication

Overriding UIApplication is extremely rare so I'll explain how to make it work. Once you create the subclass of UIApplication you need to tell the program to use that subclass. In Cocoa Senior (Mac OS X) you specify application subclasses in the Info.plist file. In Cocoa Touch, you specify custom application subclasses by name in the UIApplicationMain function in the main.m file:

int retVal = UIApplicationMain(argc, argv, @"CustomApplication", nil);

sendEvent:

The only method override we need in CustomApplication is sendEvent:. The difficult part is then working out from the UIEvent which events are status bar touch events — unfortunately, the allTouches method returns an empty array for status bar touches.

Instead, we delve into the secret GSEvent.

I previously accessed GSEvent in my post Synthesizing a touch event on the iPhone. In that post, I created a PublicEvent class and a fake GSEventProxy class to access the required fields. This time, I'm going to use a different approach and jump straight to the data I need.

- (void)sendEvent:(UIEvent *)anEvent
{
#define GS_EVENT_TYPE_OFFSET 2
#define GS_EVENT_X_OFFSET 6
#define GS_EVENT_Y_OFFSET 7
#define STATUS_BAR_TOUCH_DOWN 1015

// Traverse from the UIEvent to the GSEvent to the type
int *eventMemory = (int *)[anEvent performSelector:@selector(_gsEvent)];
int eventType = eventMemory[GS_EVENT_TYPE_OFFSET];

// Look for status bar touches by event type
if (eventType == STATUS_BAR_TOUCH_DOWN)
{
// The next 6 lines aren't essential but if you want to know where the
// touch coordinates live, here they are:
int xMemory = eventMemory[GS_EVENT_X_OFFSET];
int yMemory = eventMemory[GS_EVENT_Y_OFFSET];

typedef union {int intValue; float floatValue;} Int2Float;
float x = ((Int2Float)xMemory).floatValue;
float y = ((Int2Float)yMemory).floatValue;

NSLog(@"Status bar down at %f, %f", x, y);

// Send a message to the delegate to handle the action
[(HiddenDrawerAppDelegate *)self.delegate toggleDrawer];
}
else
{
[super sendEvent:anEvent];
}
}

You may be curious to know where the OFFSET values come from. The answer is that I spent a while staring at the raw memory values in the GSEvent object while deliberately causing status bar and other touch events — nothing fancier than that. It's tricky and unreliable. If it works at all in iPhoneSDK3.0, it'll be pure luck.

I also use a union here. This is because I step through memory as ints and in C, a basic cast from int to float causes a value conversion (I want a reinterpret, not a value conversion).

I also chose to suppress status bar touch events going through to the UITableView by the normal route. If you want to re-enable this behavior, you can take the [super sendEvent:anEvent]; line out of the else block and put it in the main method body.
Animating the drawer

The sendEvent: implementation above invokes the toggleDrawer method on the application's delegate.

All that's required is to animate the drawer's view in and push the table's view down:

drawerController = [[HiddenDrawerViewController alloc] init];

// Position the drawer below the status bar
CGRect drawerFrame = drawerController.view.frame;
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
drawerFrame.origin.x = statusBarFrame.origin.x;
drawerFrame.size.width = statusBarFrame.size.width;
drawerFrame.origin.y = statusBarFrame.origin.y + statusBarFrame.size.height;

// For the animation, move the drawer up by its own height.
drawerFrame.origin.y -= drawerFrame.size.height;

// Place the drawer and add it to the window
drawerController.view.frame = drawerFrame;
[window addSubview:drawerController.view];

// Start the animation
[UIView beginAnimations:nil context:nil];

// Move the table down
CGRect tableFrame = viewController.view.frame;
tableFrame.origin.y += drawerFrame.size.height;
viewController.view.frame = tableFrame;

// Move the drawer down
drawerFrame.origin.y += drawerFrame.size.height;
drawerController.view.frame = drawerFrame;

// Commit the animation
[UIView commitAnimations];

If you download the whole project, you'll see that there's also an animate up and remove branch that gets run if the drawerController already exists.
Conclusion

You can download the HiddenDrawer sample project (30kB) to see the whole application in action.

A hidden drawer under the status bar isn't necessarily something that every iPhone application should have but the obscure, secretive nature of it appeals to me.

The approach of determining which UIEvent we want by the type field in the GSEvent is a little precarious. Apple are free to change the structure of GSEvent at any time, which could cause your application to misbehave or crash so this type of code would need to be tested on each iPhone OS release to ensure that it still works.

Display YouTube Videos Without Exiting Your Application

if you’d like to play a YouTube video inside your application there are two common ways to do this, by launching the YouTube player and by using a UIWebview.
Launch Native YouTube Application

This approach will exit your application and begin the YouTube player on the iPhone:

[[UIApplication sharedApplication]
openURL:[NSURL URLWithString:@"http://www.youtube.com/watch?v=gczw0WRmHQU"]];

Clickable Thumbnail and UIWebview

If you’ve noticed in Safari on the iPhone, when the browser finds a YouTube video reference, a clickable link is created, which will start the movie when tapped without leaving Safari.

We can use the same approach within an iPhone application using a UIWebView, including a clickable link with a poster frame from the movie.

For this example I have created a separate class that subclasses UIWebView:

@interface YouTubeView : UIWebView
{
}

- (YouTubeView *)initWithStringAsURL:(NSString *)urlString frame:(CGRect)frame;

@end

Here’s the implementation of the class:

#import "YouTubeView.h"

@implementation YouTubeView

#pragma mark -
#pragma mark Initialization

- (YouTubeView *)initWithStringAsURL:(NSString *)urlString frame:(CGRect)frame;
{
if (self = [super init])
{
// Create webview with requested frame size
self = [[UIWebView alloc] initWithFrame:frame];

// HTML to embed YouTube video
NSString *youTubeVideoHTML = @"<html><head>\
<body style=\"margin:0\">\

<embed id=\"yt\" src=\"%@\" type=\"application/x-shockwave-flash\" \

width=\"%0.0f\" height=\"%0.0f\"></embed>\
</body></html>"
;

 


// Populate HTML with the URL and requested frame size
NSString *html = [NSString stringWithFormat:youTubeVideoHTML, urlString, frame.size.width, frame.size.height];

// Load the html into the webview
[self loadHTMLString:html baseURL:nil];
}
return self;
}

#pragma mark -
#pragma mark Cleanup

- (void)dealloc
{
[super dealloc];
}

@end

The magic here is the HTML for embedding the video content, and notice how the HTML is populated with the video URL and the desired frame size.

We can now insert this view inside a ViewController class as shown here:


// Create view that will act as link to youtube video,
// centering the view
YouTubeView *youTubeView = [[YouTubeView alloc]
initWithStringAsURL:@"http://www.youtube.com/watch?v=gczw0WRmHQU"
frame:CGRectMake(100, 170, 120, 120)];

[[self view] addSubview:youTubeView];

Here is how the clickable link looks, the image on the left is before the poster frame has downloaded, the right includes the poster frame:




Tapping the link will start the movie in a webview.

The Basics of Protocols and Delegates

Apple offers a good overview of working with protocols in their Objective-C Programming Reference. However, sometimes a simple working example can go a long ways…
Introduction

Protocols can be helpful in a number of scenarios, a common usage is to define methods that are to be implemented by other classes. A familiar example is when using a tableview, your class implements the cellForRowAtIndexPath method which asks for cell content to insert into a table – the cellForRowAtIndexPath method is defined within the UITableViewDataSource protocol.

Let’s walk through a very simple example of defining and adopting a protocol.
Protocol Definition

Here is an example of a protocol which includes one method, notice the instance variable delegate is of type id, as it will be unknown at compile time the type of class that will adopt this protocol.

#import

@protocol ProcessDataDelegate
@required
- (void) processSuccessful: (BOOL)success;
@end

@interface ClassWithProtocol : NSObject
{
id delegate;
}

@property (retain) id delegate;

-(void)startSomeProcess;

@end

Protocol Implementation

Inside the implementation section for the interface defined above we need to do two things at a minimum – first synthesize the delegate instance variable and second, call the method defined in the protocol as needed (more on that in a moment).

Let’s look at a bare bones implementation of the ClassWithProtocol.m:

#import "ClassWithProtocol.h"

@implementation ClassWithProtocol

@synthesize delegate;

- (void)processComplete
{
[[self delegate] processSuccessful:YES];
}

-(void)startSomeProcess
{
[NSTimer scheduledTimerWithTimeInterval:5.0 target:self
selector:@selector(processComplete) userInfo:nil repeats:YES];
}

@end

Understand this is a rather contrived example – the intention is to show how/where one might use a protocol. For the sake of discussion assume you have a class that is processing (or downloading) some type of data. Further, assume this class is called from another class to begin the processing. Chances are, at some point the caller will want to be notified that the class processing the data is done, this is where the protocol comes in.

In the calling class, the method defined in the protocol, processSuccessful, will be implemented and will be called from the object doing the processing, once it is complete.

For this example, inside the class where the protocol is defined, I have one method, startSomeProcess, which simply starts a timer and calls processComplete after 5 seconds. Inside processComplete the calling object will be notified through its delegate that the process is done.
Adopting the Protocol

To keep the example short, I am using the applicaton delegate as the class that adopts the protocol. Here is how the app delegate looks:

#import
#import "ClassWithProtocol.h"

@class testAppObject;

@interface TestAppDelegate : NSObject
{
UIWindow *window;
ClassWithProtocol *protocolTest;
}

@property (nonatomic, retain) UIWindow *window;

@end

A few things to note – ProcessDataDelegate is defined as part of the interface, which signifies that this class will adhere to the protocol. Looking back to the code for defining the protocol, notice that I added @required to the definition, which means that any class that adopts the protocol must implement the processComplete method (you will receive a compile warning if you don’t).

Here is the implementation of the app delegate and the required method for the protocol:

#import "TestAppDelegate.h"
#import "ClassWithProtocol.h"

@implementation TestAppDelegate

@synthesize window;

UITableViewDelegate

- (void)processSuccessful:(BOOL)success;
{
NSLog(@"Process completed");
}

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
// Create and initialize the window
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

protocolTest = [[ClassWithProtocol alloc] init];
[protocolTest setDelegate:self];
[protocolTest startSomeProcess];

[window makeKeyAndVisible];
}

- (void)dealloc
{
[window release];
[super dealloc];
}

@end

How it all works

Things goes as follows: the app delegate will create a new instance of the ClassWithProtocol object. It sets itself as the delegate and then calls the startSomeProcess method. At some point in the future, when the protocolTest object has completed its work – after the 5 second timer has fired – it will call the processSuccessful method in the app delegate to let it know it is done processing.

Simple methods for date formatting and transcoding

There is no single-line method for converting between formatting date strings and date objects in Cocoa — the API opts for flexibility rather than simplicity. Unfortunately, this combines with documentation that omits, misdirects and occasionally misinforms, making NSDateFormatter one of the more confusing classes for new Cocoa programmers. In this post, I'll try to address some of the documentation issues and I'll present some methods that will turn NSDate into a formatted string or convert between date strings in a single method.
Default, locale-based date formatting

Before I get into date formatting strings (which is the real purpose of this post) I will quickly show you how to get a string from an NSDate:

NSDate *date = [NSDate date];
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateStyle:NSDateFormatterLongStyle];
NSString *dateString = [dateFormatter stringFromDate:date];

This code formats the string according to the user's preferences set in the International General Settings (iPhone) or System Preferences (Mac OS X).

Personally, I think this is verbose for such a common activity and normally use a category method on NSDate to reduce it:

@implementation NSDate (FormattedStrings)
- (NSString *)dateStringWithStyle:(NSDateFormatterStyle)style
{
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateStyle:style];
return [dateFormatter stringFromDate:self];
}
@end

This reduces the first code sample to:

NSString *dateString = [[NSDate date] dateStringWithStyle:NSDateFormatterLongStyle];

If you need time strings instead of date strings, create a timeStringWithStyle: method by replacing the setDateStyle: invocation with setTimeStyle:.

I have read rants by other Objective-C programmers who hate seeing projects with hundreds of small categories for every little task.

Frankly, I've never understood the objection. In fact, I think lots of small categories used to choose the settings you prefer on top of common interfaces is essential for establishing consistent aesthetics for your program — your entire program will have the same style and you can easily update the aesthetic for the whole program by editing a single location.

An example would be to replace this dateStringWithStyle: method with a dateStringWithProjectStyle method that returns the appropriately configured string for use throughout your program. One of your projects might use NSDateFormatterLongStyle and the next might use a totally customized format (as I'll describe in the next sections) but you as a programmer can still invoke dateStringWithProjectStyle everywhere you need a string from an NSDate.
Date formatting documentation issues

At its heart, NSDateFormatter is very simple to use and yet it repeatedly baffles new users. I don't think this is really the fault of the API as much as the history behind it and the effect that it has had on the documentation.

Despite NSDateFormatterBehavior10_4 being the only date formatting you should ever use and the only style that should exist in the documentation, Apple's documentation has the following quirks:

1. The actual syntax for NSDateFormatterBehavior10_4 is never given in the documentation and you can easily miss the links to Unicode Standard (tr35) which describe it.
2. A majority of the pages in the date formatting documentation seem concerned with the old NSDateFormatterBehavior10_0 style formatter behavior even though this is functionally deprecated.
3. The documentation for defaultFormatterBehavior claims NSDateFormatterBehavior10_0 is the default style but it is actually NSDateFormatterBehavior10_4 in Leopard and iPhoneSDK2.0.

Then, if you've been skimming through the documentation getting confused by the different styles, you may overlook one line at the top of the NSDateFormatter API reference page:

iPhone OS Note: iPhone OS supports only the modern 10.4+ behavior. 10.0-style methods and format strings are not available on iPhone OS.

All that documentation in the iPhone SDK concerned with the old NSDateFormatterBehavior10_0 style is completely meaningless — you can't use NSDateFormatterBehavior10_0 at all on the iPhone.

Adding to the iPhone frustration, NSDateFormatterBehavior10_0 will work in the simulator, causing headaches when code suddenly stops working on the device.

On Mac OS X, even though you can use NSDateFormatterBehavior10_0, it is deprecated for all practical purposes so you probably shouldn't. Annoyingly, since the documentation still claims NSDateFormatterBehavior10_0 is the default, you should explicitly set the formatter behavior to NSDateFormatterBehavior10_4 to remain safe — at least until the documented default is updated to formally match the actual default.

I don't mean to be cruel to Apple — documentation is difficult, time consuming and annoying — but I suspect these quirks in the documentation and behavior are responsible for a lot of confusion.
Date formatting syntax

Setting a date formatting string looks like this:

NSDate *date = [NSDate date];
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
[dateFormatter setDateFormat:@"dd MMM, yyyy"];
NSString *dateString = [dateFormatter stringFromDate:date];

This will create a string of the format "26 May, 2009". The arrangement of data in this string is determined by the format string passed to the setDateFormat: method.

A quick summary of the date formatting options useable in this format string:
Character Matches/Outputs Multiples
y Year 1, 2 or 4 'y's will show the value, 2 digit zero-padded value or 4 digit zero-padded value respectively
M Month 1, 2, 3, 4 or 5 'M's will show the value, 2 digit zero-padded value, short name, long name or initial letter months
d Day of Month 1 or 2 'd's will show the value or 2 digit zero-padded value representation respectively.
E Weekday 1, 2, 3, 4 or 5 'e's will show the value weekday number, 2 digit zero-padded value weekday number, short name, long name or initial letter respectively. Weekday numbers starts on Sunday. Use lowercase 'e' for weekday numbers starting on Monday.
a AM or PM No repeat supported
h Hour 1 or 2 'h's will show the value or 2 digit zero-padded value representation respectively. Use uppercase for 24 hour time.
m Minute 1 or 2 'm's will show the value or 2 digit zero-padded value representation respectively.
s Second 1 or 2 's's will show the value or 2 digit zero-padded value representation respectively.
z Timezone 1, 2, 3 or 4 'z's will show short acronym, short name, long acronym, long name respectively. Use uppercase to show GMT offset instead of name — 1 or 2 digit zero-padded values shows GMT or RFC 822 respectively.

Case is important — using the wrong case can cause parsing to fail. Use lowercase by default for all values except Month.

Alphabetic and numeric characters should be enclosed in single quotes (asterisk character) if you want them to pass through the parser as literal characters. A double asterisk will pass through as a single asterisk (self escaping). Most other punctuation and spaces will go through as normal except backslash which works like a normal C-string escape character to handle tabs, newlines and other special characters.

For the complete specification, including the more obscure options that I haven't bothered to list, see Unicode Standard (tr35).
Date string transcoding

The date formatting options can also be used to parse strings. With parsing and output formatting, we can create a date string transcoder method in a category on NSDateFormatter:

+ (NSString *)dateStringFromString:(NSString *)sourceString
sourceFormat:(NSString *)sourceFormat
destinationFormat:(NSString *)destinationFormat
{
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
[dateFormatter setDateFormat:sourceFormat];
NSDate *date = [dateFormatter dateFromString:sourceString];
[dateFormatter setDateFormat:destinationFormat];
return [dateFormatter stringFromDate:date];
}

We can use this method to convert one date string (for example "2007-08-11T19:30:00Z") into another ("7:30:00PM on August 11, 2007") in the following manner:

NSString *inputDateString = @"2007-08-11T19:30:00Z";
NSString *outputDateString = [NSDateFormatter
dateStringFromString:inputDateString
sourceFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"
destinationFormat:@"h:mm:ssa 'on' MMMM d, yyyy"];

Calendar stuff

The NSDateFormatter class is just for parsing and formatting strings. You shouldn't use it to build dates from their components or to decompose dates into components. For that task, use NSCalendar. It's a little outside the scope of this post but since I know it will come up, here's how to set an NSDate to the 26th of May, 2009 using NSCalendar:

NSDateComponents *components = [[[NSDateComponents alloc] init] autorelease];
[components setDay:26];
[components setMonth:5];
[components setYear:2009];
NSCalendar *gregorian =
[[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSDate *date = [gregorian dateFromComponents:components];

To get the components from a date, use:

unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDate *date = [NSDate date];
NSCalendar *gregorian =
[[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSDateComponents *components = [gregorian components:unitFlags fromDate:date];

Conclusion

As I've said a few times now, the actual API for date formatting in Cocoa is simple. The only reason why I consider it a topic worthy of a post is that I still see at least one question a week on StackOverflow and other forums asking why NSDateFormatter is failing in their code and the answer is normally because their code confuses the formatting behaviors, uses the wrong format specifiers or has otherwise misunderstood the required steps.

Developing Split View Based Apps for the iPad

An iPhone Developer Program (IDP) membership (costs $99 for Individuals) is required to officially deploy your application on the iPhone – even during the development and testing. Though I have applied for the IDP membership long ago, mine is yet to be approved. Perhaps India is not a listed country for IDP.

Not having an IDP membership will not affect your iPhone development and further testing on a real iPhone. But you would still require a Jailbroken iPhone. You will have to tweak your XCode (Version 3.1.2) and individual project settings – along with the iPhone (Firmware 2.2) – to get the Applications deployed on the phone. Here are the steps. These information were collated by the results of endless queries posted on different forums and by reading various material available on the Web. All the credits are due to their respective owners :)

Common Instructions to Install :-

• Jailbreaking the iPhone requires you to follow the clear instructions given by iClarified. This includes a Video demonstration also. There is no need to Unlock your iPhone. Just Jailbreak should suffice.

• Install the iPhoneTunnel and CyberDuck applications on the Mac

• Install OpenSSH, BossPrefs and Link-Identity-Editor applications using the Cydia application on the iPhone. After installation Reboot the iPhone

• Add source in Cydia (if you have not yet done so), please remember there is a slash (/) at the end of the url Code: http://www.iphone.org.hk/apt/ . Install MobileInstallation Patch version 2.2 in Section “Tweaks”

• Connect the iPhone using the USB Cable to the Mac

• Close the iTunes.

Setting up XCode to Compile and Build the iPhone Application

• Create a Signing Identify on your Mac by following this simple guide from Apple. I suggest you name the Certificate as “iPhone Developer”

• TextEdit the /Developer/Platforms/iPhoneOS.platform/Info.plist file to look the respective portions like:-

1: NATIVE_ARCH

2: armv6

3: PLIST_FILE_OUTPUT_FORMAT

4: binary

5: PROVISIONING_PROFILE_ALLOWED

6: NO

7: PROVISIONING_PROFILE_REQUIRED

8: NO

9: SDKROOT

10: iphoneos2.2

• Change your own Project Settings by taking [Menu] Project->Edit Project Settings. In the Properties List, find the Code-Signing-Identity and Select the Certificate Name(iPhone Developer) you created earlier.

• Add the following snippet on to your projects info.plist using TextEdit

1: SignerIdentity

2: Apple iPhone OS Application Signing

Transferring the Application Binary to the iPhone over USB

• You may duplicate the following steps using an Ad-Hoc WiFi connection too, of which I am not so fond off!. I prefer the USB.

• Start the iPhoneTunnel Application on the Mac. You should see a respective icon on the Superior Bar at the top of the screen. Click on that Icon and select [Turn Tunnel ON]

• Again click on the same icon on top and select [Tools->SFTP]. The Cyberduck should start automatically. Enter the username as ‘root’ and password as ‘alpine’ in the cyberduck login window.

• Copy the TestApp.app (Your Own App) to the /Application folder of the iPhone using Cyberduck

• Click on the iPhoneTunnel icon and select [Tools->SSH(root)]. Enter the root/alpine credentials at the command prompt.

• At this command prompt enter the following two commands:-

ldid -S /Applications/TestApp.app/TestApp

chmod +x /Applications/TestApp.app/TestApp

• Open the BossPrefs application on the iPhone and choose the “ReSpring” option. This will restart the SpringBoard application to show your application on the Home Screen.

• Enjoy Your App!

If you have a proper Code signing Signature from Apple , you can follow these great instructions to deploy on to AppStore.

Deploying iPhone Apps to Real Devices

For testing purposes, you used the iPhone Simulator, provided as part of the iPhone SDK. While the iPhone Simulator is a very handy tool that allows you to test your iPhone applications without needing a real device, nothing beats testing on a real device. This is especially true when you are ready to roll out your applications to the world - you must ensure that it works correctly on real devices. In addition, if your application requires accesses to hardware features on an iPhone/iPod Touch, such as the accelerometer and GPS, you need to test it on a real device - the iPhone Simulator is simply not adequate.

A repeated criticism from iPhone app developers comes from the difficulty they find in deploying their application to a real iPhone or iPod Touch. Apple, for better or worse, has designed a process involving many hoops that must be jumped through, and this has prompted developers to grumble, and others to explore alternative, non-official open tool chains, which do not require app signing. In this article, I will walk you through the steps you need to take in order to test your iPhone apps on a real device, be it iPhone, or iPod Touch, the offical Apple way.
Sign up for the iPhone Developer Program

The first step towards testing your applications on a real device is to sign up for the iPhone Developer Program at http://developer.apple.com/iphone/program/. There are two programs available - Standard and Enterprise. For most developers wanting to release applications on the App Store, they can simply sign up for the Standard program, which costs US$99. Check out http://developer.apple.com/iphone/program/apply.html to know more about the differences between the Standard and Enterprise programs.
Start your Xcode

In order to test your iPhone applications on your device, you need to obtain an iPhone Development Certificate from the iPhone Developer Program Portal. This needs to be done once for every device you wish to test your apps on. The following sections walk you through the various steps, from obtaining your certificate, to deploying your applications onto the device.

First, obtain the 40-character identifier that uniquely identitfies your iPhone/iPod Touch. To do so, connect your device to your Mac and start Xcode. Select the Window > Organizer menu item to launch the Organizer application. Figure 1 shows the Organizer application showing the identifier of my iPhone. Copy this identifier and save it somewhere. You will need it later on.



Figure 1 Obtaining the identifier for your iPhone/iPod Touch
Generating a Certificate Signing Request

Before you can request a development certificate from Apple, you need to generate a Certificate Signing Request. This step must be performed once for every device you wish to test on. To generate the request, you can use the Keychain Access application located in the Applications/Utilities/ folder (see Figure 2).



Figure 2 Launching the Keychain Access application

In the Keychain Access application, select the Keychain Access > Certificate Assistant menu and select Request a Certificate From a Certificate Authority (see Figure 3).



Figure 3 Requesting a certificate

In the Certificate Assistant window (see Figure 4), enter your email address, check the Saved to disk radio button and check the Let me specify key pair information checkbox. Click Continue.




Choose a key size of 2048 bits and use the RSA algorithm (see Figure 5). Click Continue.



Figure 5 Specifying key pair information

You will be asked to save the request to a file. Use the default name suggested and click Save (see Figure 6).



Logging in to the iPhone Developer Program Portal

Once you have generated the certificate signing request, you need to login to Apple's iPhone Dev Center (see Figure 7). Click on the iPhone Developer Program Portal link on the right of the page. Remember, you need to pay US$99 in order to access this page.



In the iPhone Developer Program Portal page, click the Launch Assistant button (see Figure 8) to walk you through the process of provisioning your iPhone and generating the development certificate.



Figure 8 Launching the provisioning assistant

You should see the welcome page as shown in Figure 9. Click Continue.



Figure 9 The welcome page of the provisioning assistant

First, you will be asked to create an App ID (see Figure 10). An App ID is a series of characters used to uniquely identify an application (or applications) on your iPhone. You only need to create an App ID once per application, i.e. you do not need a new App ID for new versions of your app. Enter a friendly name to describe this App ID (to be generated by Apple). Click Continue.



Figure 10 Creating an App ID

The next screen allows you to provide a description of your iPhone/iPod Touch. You need to provide the device ID that you have obtained earlier (see Figure 11). Click Continue.



igure 11 Assigning a device for the provisioning

You are now ready to submit the certificate signing request to Apple (see Figure 12). The instructions on the screen show you the steps that you have performed earlier. Click Continue.



Figure 12 Generating a certificate signing request

In this screen, click the Choose File button (see Figure 13) to select the certificate signing request file that you have created earlier. Once the file has been selected, click Continue.



Figure 13 Submitting a certificate signing request

Provide a description for your provisioning profile (see Figure 14). A Provisioning profile will be generated so that you can download it at a later stage and install it on your device. Click Generate.



Figure 14 Naming your provisioning profile

A Provisioning profile will now be generated (see Figure 15). Once it is generated, click Continue.



Figure 15 Generating a provisioning profile

You are now ready to download the generated Provisioning profile onto your Mac (see Figure 16). Click Continue.



Figure 16 Downloading and installing your provisioning profile

Drag and drop the downloaded Provisioning profile (in the Downloads folder) onto Xcode (located in the Dock). This will install the Provisioning profile onto your connected iPhone/iPod Touch. Click Continue (see Figure 17).



Figure 17 Instructions to verify the installation

You can verify that the Provisioning profile is installed correctly on your device by going to the Organizer application and viewing the Provisioning section (see Figure 18) to see if the profile has been added.



Figure 18 Verifying the provisioning profile on the Organizer

Back in the iPhone Developer Program Portal, you are now ready to download and install the development certificate onto your iPhone/iPod Touch. Click the Download Now button (see Figure 19) to download the development certificate to your Mac. Click Continue.



Figure 19 Downloading and installing the development certificate

In the Downloads folder of your Mac, double-click on the developer_identify.cer file that you have just downloaded to install it into a keychain on your Mac. When prompted (see Figure 20), click OK.



Figure 20 Adding a certificate to the keychain

Back in the iPhone Developer Program Portal, you can now verify that the certificate has been installed properly in the Keychain Access application (see Figure 21). Click Continue.



Figure 21 Instructions for verifying the installation of the certificate

In the Keychain Access application, select the login keychain and look for the certificate named "iPhone Developer:" (see Figure 22). If you can see it there, your certificate is installed correctly.



Figure 22 Verifying the installation of the certificate

You are now almost ready to deploy your iPhone application onto your iPhone/iPod Touch. Click Continue (see Figure 23).



Figure 23 Instructions for installing your applications with Xcode

Click Done to dismiss the dialog (see Figure 24).



Figure 24 Finishing the installation

In Xcode, under the Active SDK item (if this item is not already on the toolbar, go to View > Customize Toolbar and add it to the toolbar), select the OS version number of the device that is currently connected to your Mac. In my case, my iPhone is running the older iPhone OS 2.0, hence I selected "iPhone Device (2.0)" (see Figure 25).



With your application project open in Xcode, press Command-R to run the application. You will now be prompted for permission to access the certificate saved in your keychain. Click Allow (or Always Allow) to go ahead with the signing (see Figure 26).




Your application will now be deployed to the device. You can see its progress in the Summary tab of the Organizer application (see Figure 27).



Figure 27 Checking the Organizer for installation progress

Once the application is deployed onto your device, it will be running automatically. You can capture screenshots of your device by going to the Screenshot tab of the Organizer application, and pressing the capture button (see Figure 28).



Figure 28 Capturing screenshots using Organizer
Summary

In this article, you have seen the various steps required to deploy your application to your iPhone or iPod Touch. While the number of steps looked intimidating, it is actually quite straightforward. The iPhone Developer program allows you to provision up to 100 devices for testing purposes. Once a device is provisioned, you can then use the development certificate to deploy your applications onto it.