How code push notifications on the iPhone 3.0

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

Leave a Reply