iPhone Programming: How to make an Apple Push Notification Service using PHP

Apple Push Notification Service (APNS) alows you to send messages to your iPhone-App even your app is not running. Once a user installed your iPhone-App and agreed to the push service and is somehow reachable by APNS your message will be deployed.

Ok, here is how it works. Any iPhone device has a unique token which is the identifier the APNS uses to send message to. A device token is a 64 byte identifier. Your iPhone App has to send the device token manualy to your server and if you want to send something to this device token your server code has to store it somehow. Later on when sending your notification message to your device token you create a package which is capable of 256 Byte in total including all informations (even the device token itself is included).

Within you XCode App you could optain your device token by adding the following application delegate to your app :

//////////////////////////////////////////////
// CLIENT SIDE CODE
//////////////////////////////////////////////
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken 
{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
 
    // to make sure your device will be just registered once, we store
    // the state in userDefaults.
 
    if ( ![userDefaults boolForKey:@"DeviceTokenRegistered"] )  //if ( null, nil or "false" )
    {
        [userDefaults setBool:YES forKey:@"DeviceTokenRegistered"]; 
        NSLog(@"Device Token: %@", devToken); // log the device token as ascii
 
        // send it somehow to your server - apple says the best way is to
        // send it as bytes : ( assuming you wrote a "sendProviderDeviceToken" method )
        [self sendProviderDeviceToken: [devToken bytes]];
    }
}
 
- (void) applicationDidFinishLaunching:(UIApplication*)application
{
    /*
    UIRemoteNotificationTypeNone
    UIRemoteNotificationTypeBadge
    UIRemoteNotificationTypeSound
    UIRemoteNotificationTypeAlert 
    */
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)]; 
}

Once you created a push notification package you have to authenticate your self as developer for the sandbox APNS-server or as distributor for the real APNS-server. This authentification is done by a so called pem file. To create one of these you have first generate an Apple Push Notification SSL certificate on your Mac.

  1. Ensure to have a valid and working AppID without wildcard at your iPhone Developer Center. You cannot push a notification to an appID with wildcards. Your app ID should look like xxxxxxxxxx.com.yourCompanyName.yourAppName
  2. Inside Apple Developer Center enable Push Notification your app from step 1.
  3. Import your apns_developer_identity.cer into your keychain on your mac.
  4. Launch the keychain assistant on your mac and go to certificates category and expand the option Apple Develoment Push Services.
  5. If you right click on Apple Development Push Services choose export Apple Development Push Services ID888 and save it as apns-dev-cert.p12 file.
  6. Do the same for the private key but save it as apns-dev-key.p12.
  7. Do convert both files to PEM format via:
    openssl pkcs12 -clcerts -nokeys -out apns-dev-cert.pem -in apns-dev-cert.p12
    openssl pkcs12 -nocerts -out apns-dev-key.pem -in apns-dev-key.p12
  8. to disable the passphrase execute:
    openssl rsa -in apns-dev-key.pem -out apns-dev-key-noenc.pem
  9. The last step is to combine the pem files via:
    cat apns-dev-cert.pem apns-dev-key-noenc.pem > apns-dev.pem
    

Now put the pem file in a directory where you can access it within your php code – wich itself is pretty simple. First you have to open a connection to the APNS (gateway.push.apple.com for distribution or gateway.sandbox.push.apple.com for development). In this example I will use the sandbox server:

$ctx = stream_context_create(); 
//////////////////////////////////////////////
// SERVER SIDE CODE
//////////////////////////////////////////////
 
// send our authentification file
stream_context_set_option($ctx, 'ssl', 'local_cert', 'apns-dev.pem'); 
 
// open a connection to the sandbox server
$apnsConnection = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx); 
 
// creating the notification message (256 Byte max)
 
// your device token here
$deviceToken = 'e6636942 e1d5cf29 924628c3 115004af 1caba414 d4e52098 023fef08 07954d6a'; 
 
// your message goes here
$message = "Your push notification text goes here.";
 
// define a sound file if you want here
$sound = 'mySoundFile.caf'; //name of the sound file inside the XCode project.
 
// Construct the notification payload
$body = array();
$body['aps'] = array('alert' => $message);
$badge = (int)$argv[2]; // a number which will be displayed over the apps icon
if ($badge)
{
  $body['aps']['badge'] = $badge;
}
if ($sound)
{
  $body['aps']['sound'] = $sound;
}
$payload = json_encode($body);
 
// remove blanks and pack it.
$msg = chr(0) . pack("n",32) . pack('H*', str_replace(' ', '', $deviceToken)) . pack("n",strlen($payload)) . $payload;
 
// push the message through APNS
fwrite($apnsConnection, $msg); 
 
//close APNS connection
fclose($apnsConnection);

About this entry