Archive for the ‘iPhone’ category

iPhone push problems on unlocked phones

July 22nd, 2009

I read an article today about Push Notifications being displayed on the wrong people’s phones.

Now if the story is taken at face value then this would be a huge security flaw with the Apple Push Notification Service. However if you dig a little further you discover that it isn’t Apple’s problem at all, more the work of the unlocking community.

Now I’ll first start by explaining how the push notification service works. When you first load an application with push notification enabled, the application makes a call to the APNS (Apple Push Notification Service) servers. Those servers respond with a unique key for that device for push services. That unique key allows Apple to identify which device and which application to target for a push notification.

The App then communicates with the application’s author’s web servers and stores the key somewhere. The author’s servers then use that key to push a JSON encoded payload the APNS servers and the notification gets displayed on the user’s phone.

With me so far? So how does this break on unlocked iPhones?

Well unlocked / hacktivated phones haven’t actually been activated with Apple’s activations servers, they’ve simply been fooled into thinking that they have.

From what I’ve read about this situation is that the hacktivating / unlocking community have taken the key(s) from a properly activated device and put as part of the process.

So what is actually happening is that multiple phones are recieving legitimate push messages for the original key holder but not for them.

At present it would seem that push notifications simply won’t work on hacktivated / unlocked phones.

I guess the lesson is, if the software is written to prevent you from unlocking / by passing activation and then you do bypass it, then don’t expect everything to work properly!

How code push notifications on the iPhone 3.0

July 15th, 2009

I recently spent an entire evening trying to get this to work within an App and then post the message from my PHP application to Apple’s service.

First up you must create a CSR using your private key, you must have done this before to even be using the SDK so I’ll skip over it.

Login to the Apple Dev Center then to the iPhone Developer Program Portal.

Click on App IDs and add a New App ID.

  1. You need to create an App ID without wildcard in the Program Portal (that means one cert for one app.  They explain how to do this in the portal)
  2. Generate a certificate signing request from your Mac’s keychain and save to disk
  3. Upload the CertificateSigningRequest.certSigningRequest to the Program Portal
  4. Wait for the generation of cert (about 1 min). Download the certificate (aps_developer_identity.cer) from the Program Portal (and also the distribution certificate if you wish too, we’ll deal with just the developer identity for this)
  5. Keep the 2 files (steps 2 and 4) in a safe place. You might need the CertificateSigningRequest.certSigningRequest file to request a production cert in the future or renew it again.
  6. Import the aps_developer_identity.cer to the keychain. Then you have to export these new cert and the private key of this cert (not the public key) and saved as .p12 files.
  7. Then you use these commands to generate the cert and key in Mac’s Terminal for PEM format (Privacy Enhanced Mail Security Certificate)
    openssl pkcs12 -clcerts -nokeys -out certificate.pem -in cert.p12
    openssl pkcs12 -nocerts -out key.pem -in key.p12
  8. The certificate and private key files are used by your software to communicate with APNS
  9. You might want to remove the passphrase from the private key (you don’t have to do this but it makes it slightly more complicated in your code). To do this
    openssl rsa -in key.pem -out key.unencrypted.pem

    Then you’ll need to generate a single .pem file combining your certificate and key files

    cat certificate.pem key.unencrypted.pem > apnsdev.pem

So copy the generate apnsdev.pem file to your server and then you can setup your PHP application to push notifications to your iPhone.

$deviceToken = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // masked for security reason
// Passphrase for your private key
// $pass = '';

$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'apnsdev.pem');
// assume the private key passphase was removed.
// stream_context_set_option($ctx, 'ssl', 'passphrase', $pass);

$fp = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
if (!$fp) {
  print "Failed to connect $err $errstr\n";
}
else {
  print "Connection OK\n";
  $payload = '{"aps":{"badge":' . $number . '}}';
  $msg = chr(0) . pack("n",32) . pack('H*', str_replace(' ', '', $deviceToken)) . pack("n",strlen($payload)) . $payload;
  print "sending message :" . $payload . "\n";
  fwrite($fp, $msg);
  fclose($fp);
}

Note: if as a developer you install your app with your developer provision profile you’ll have to use the sandbox to communicate with your phone, you won’t be able to use the production push servers without the distribution profile

So that’s stage one, how to configure your web server with PHP to push to an iPhone, but how does the App actually register itself for push and secondly how do you get the device token to your server?

In XCode, in AppDelegate.m

- (void)applicationDidFinishLaunching:(UIApplication *)application {

 // This tells APNS that you wish to receive both Badge notifications and sound
 [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
}

Then we can make two delegate functions in AppDelegate.m too

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  NSLog(@"deviceToken: %@", deviceToken);
  [self sendToMyServer:deviceToken];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
  NSLog(@"Error in registration. Error: %@", error);
}

You’ll need to create a function for ‘sendToMyServer’ and deal with the deviceToken, such as convert it to a string, etc. But essentially that is how you deal with push notifications on your iPhone!

Update: Oh and if you get the error

Warning: stream_socket_client() [function.stream-socket-client]: Unable to set local cert chain file `apnsdev.pem'; Check that your cafile/capath settings include details of your certificate and its issuer in /Library/WebServer/Documents/notifyTest/anps.php on line 33

or similar, the chances are you’ve exported the wrong certificate and/or key from your OS X Keychain

Some more iPhone SDK tips and tricks

April 8th, 2009

In working on an update to one of my applications on the Apple iPhone I thought I’d share another quick tip.

I found on a blog and it works brilliantly,  to make rounded corners on any UIImage.

ImageManipulator.h

@interface ImageManipulator : NSObject {
}
+(UIImage *)makeRoundCornerImage:(UIImage*)img :( int) cornerWidth :( int) cornerHeight;
@end

ImageManipulator.m

#import "ImageManipulator.h"

@implementation ImageManipulator

static void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth, float ovalHeight)
{
    float fw, fh;
    if (ovalWidth == 0 || ovalHeight == 0) {
        CGContextAddRect(context, rect);
        return;
    }
    CGContextSaveGState(context);
    CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect));
    CGContextScaleCTM (context, ovalWidth, ovalHeight);
    fw = CGRectGetWidth (rect) / ovalWidth;
    fh = CGRectGetHeight (rect) / ovalHeight;
    CGContextMoveToPoint(context, fw, fh/2);
    CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);
    CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);
    CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);
    CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);
    CGContextClosePath(context);
    CGContextRestoreGState(context);
}

+(UIImage *)makeRoundCornerImage : (UIImage*) img : (int) cornerWidth : (int) cornerHeight
{
	UIImage * newImage = nil;

	if( nil != img)
	{
		NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
		int w = img.size.width;
		int h = img.size.height;

		CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
		CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);

		CGContextBeginPath(context);
		CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
		addRoundedRectToPath(context, rect, cornerWidth, cornerHeight);
		CGContextClosePath(context);
		CGContextClip(context);

		CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);

		CGImageRef imageMasked = CGBitmapContextCreateImage(context);
		CGContextRelease(context);
		CGColorSpaceRelease(colorSpace);
		[img release];

		newImage = [[UIImage imageWithCGImage:imageMasked] retain];
		CGImageRelease(imageMasked);

		[pool release];
	}

    return newImage;
}

@end

Just call the static method makeRoundCornerImage and pass your image to have the image rounded off the way you want.

For example

UIImage *imageFromFile = [UIImage imageNamed:@"myimage.png"];
imageFromFile = [ImageManipulator makeRoundCornerImage:imageFromFile : 20 : 20];

Note that you do need the CoreGraphics framework for this to compile.

More information can be found at the blog post link above.

The second tip is to load a remote image over the web and display it in a UIImageView object.

Create the following method in your interface

-(UIImage*) newUIImageWithURLString:(NSString*)urlString
{
	return [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]]];
}

Then call the following

UIImage *myImage = [self newUIImageWithURLString:@"http://url.to/image.jpg"];

.tel goes live

March 25th, 2009

media_right_3Well I’ve just got my .tel domain http://richardhyland.tel

Time will tell if it’s any good or going to work, however I’ve actually got a .tel iPhone management tool awaiting approval from Apple.

Some cool tips and tricks for the iPhone SDK

December 21st, 2008

During the course of developing my latest iPhone application (currently awaiting approval from Apple) I solved a number of issues I’ve had in previous attempts but I’ve finally solved them.  Apologies to anyone reading this that thinks, derrr I’ve known this for ages, but hopefully it’ll help some developers with their iPhone applications.

1) Updating the main UI from a thread.

If you call a function using a thread

[NSThread detachNewThreadSelector:@selector(getXML) toTarget:self withObject:nil];

then you might want to update the main user interface e.g. to display a status on a toolbar.  Well as it turns out the thread is protected and can’t access the main ui whilst the thread is running.  The way to solve this is using the following code

[self performSelectorOnMainThread: @selector(updateBadge) withObject:nil waitUntilDone:NO];

where updateBadge is a function.

2) Changing a refresh button to display a UIActivityIndicatorView on a toolbar
Let’s say we have a toolbar at the bottom of the screen and we’ve added a refresh button e.g.
UIBarButtonItem *flexItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];

refreshItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(actionRefresh:)];

refreshItem.style = UIBarButtonItemStylePlain;

NSArray *items = [NSArray arrayWithObjects: flexItem, refreshItem, nil];

[toolbar setItems:items animated:NO];

Then by default with that code it would display a refresh button at the right hand side of the toolbar, and when clicking on it would call refreshAction:(id)sender.  To be helpful to the end user we might want to change the refresh button to an activity indicator whilst the refresh action was taking place.

The first job is to make the refresh button and flex item a global property so you can call them from different place.  Now we also need to create a UIActivityIndicator.

When the refresh action starts you can call the following code to display the activity indicator

CGRect frame = CGRectMake(0.0, 0.0, 25.0, 25.0);

UIActivityIndicatorView *loading = [[UIActivityIndicatorView alloc] initWithFrame:frame];

[loading sizeToFit];

loading.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin);

[loading startAnimating];

UIBarButtonItem *statusInd = [[UIBarButtonItem alloc] initWithCustomView:loading];

statusInd.style = UIBarButtonItemStylePlain;

NSArray *items = [NSArray arrayWithObjects: flexItem, statusInd, nil];

[toolbar setItems:items animated:NO];

Then when the refresh action stops, simply call the following, as we’ve already made flexItem and refreshItem a global property we don’t need to redefine them or re-point them to their action selector.

NSArray *items = [NSArray arrayWithObjects: flexItem, refreshItem, nil];

[toolbar setItems:items animated:NO];
3) How to display an application badge
Now of the three items I discovered this is probably the easiest and it simply the code you need to display the little red badge icon, like the one you see when you have unread email on the mail icon on the home screen.
[UIApplication sharedApplication].applicationIconBadgeNumber = 10;
To hide the badge simply set the value to 0

The dilemma of iPhone Apps

December 6th, 2008

I’m sure other iPhone developers have come up against the same dilemma as me, you come up with what you think is a great idea for a new iPhone Application to perform a quick search on the iTunes App Store and discover that 5 other people have done the same thing.  So the dilemma, do you still write the app because you think you can do better, or do you think of another idea?

Well so far I’ve developed one that I came up with the idea and the same day it got published two others of the same subject did.  For the second idea no one had written an app on this subject yet.  Yet when I came to submit the final code there were three, yet I still submitted because I’d spend enough time working on it.

Now the second dilemma, I’ve got another idea, which obviously I won’t share until I’ve completed it, but do I actually bother as at the time of writing, no one has done this yet, but will they have done by the time I finish coding the application.  Although it will probably only take a fortnight to code.

Heck I’ll probably write it anyway… watch this space!

myTube for the iPhone

October 1st, 2008
What is myTube?: Information and navigation of the London Underground network.

Highlights:

  • Tube Status: browse the latest tube status updates, including DLR. Change the look and feel from pre-defined skins.
  • Map: view the London Underground map live on the TfL website and optionally download and save the map to your iPhone for viewing offline
  • Nearest Station: find the nearest Tube or DLR station from your current GPS location, distance and directions over ground
  • Route Planner: whilst overground just select your starting station, your destination and find out how to get there including line changes, then view that route whilst underground
  • Navigation: how to get to or from a Tube station using an address or post code
  • Tourist Attractions: Find attractions near to stations and how to get there overground

This application is designed for usage in connection with the UK London Underground network.

Because of TfL copyright we cannon bundle the Tube map for offline browsing with the application itself. When you use the map it will use the one on TfL’s site, however you can optionally download and save the map for viewing without an Internet connection.

This Application is available from the iTunes App Store.

iPhone development

September 1st, 2008
Xcode icon

Xcode icon

I’ve developed in a number of languages and systems over the years from Windows Batch Files, Perl, PHP, C#, VB, ASP, etc, etc and I absolutely love Visual Studio 2008 and it’s intellisense.

Now I thought I’d dab my hand at iPhone development.  For those that don’t know you have to use a Mac OSX application called Xcode to be able to develop for the iPhone and iPod touch, and then using this in a language called Objective C which seems to be Apple’s own extension to C and C++.  To be honest I’ve never gone down the C++ programming route and it probably wouldn’t have been so difficult had the Apple Developer Documentation been any good but basically before Apple lifted their NDA and allowed discussion about developing for the iPhone it was basically trial and error which insanely cryptic compiler debug errors.

Anyway I’ve solved many of the issues now and coming next I’ll talk about my first App that’s already on the iTunes App Store.