iOS Push Notifications

Push Notifications on iOS are handled by the Apple Push Notification Service (APNS), a comprehensive set of instructions can be found here http://www.raywenderlich.com/32960/apple-push-notification-services-in-ios-6-tutorial-part-1 but we will summarise them here.

Before you begin

You will need a server capable of running PHP scripts for this example to work

You will need an iOS device, the simulator won't work, and an Apple developer membership.

You must know how to create a certificate signing request to request a certificate from Apple, this is the same process used to generate Distribution and Development certificates.

To simplify the process we will only cover Distribution (including AdHoc) builds, not Development builds.

Server Setup

Apple push notifications involve an SSL certificate that is used to sign all notifications, this certificate is part of the App ID setup and must be generated per app. When generating the App ID the "Push Notification" tick box must be ticked, you can also edit an existing App ID to turn it on.

Once enabled select the App ID and choose Edit (if you are not already there) and scroll down to the push notification section. Click Create Certificate in the Production SSL Certificate box and generate a certificate for it. Download the certificate and place it in a folder that is easy to access via the command line (there is no need to add the certificate to your keychain). In your keychain find the private key that was generated for this certificate, export it, and place it in the same folder.

For the purposes of this example we will convert the certificate and private key into a PEM file so that our server running PHP can use it to sign notifications. These steps may vary if you are using another language.

Open a terminal window and browse to the folder containing the certificate and private key. Run the following command to convert the certificate into a PEM file.

openssl x509 -in downloaded_certificate.cer -inform der -out PushCert.pem

Now run the following command to convert the private key to PEM. Note that if you type your p12 password incorrectly OpenSSL may still generate a PEM file but it will not contain the private key.

openssl pkcs12 -nocerts -out PushKey.pem -in exported_private_key.p12

It will ask you to generate a password for this PEM, you will need to use this in the server code later. Now to combine the two into a single PEM file

cat PushCert.pem PushKey.pem > ck.pem

You will need to upload this ck.pem file to your server, for this example we will store it in a folder anemd "certs" next to the PHP script. You can use the following PHP code on the server to send requests

function SendPushNotificationiOS( $deviceToken, $message, $badgecount )
{
    $cert = "certs/ck.pem";
    
    $ctx = stream_context_create();
    stream_context_set_option($ctx, 'ssl', 'local_cert', $cert);
    stream_context_set_option($ctx, 'ssl', 'passphrase', 'myPEMpassword');
 
    // Open a connection to the APNS server
    $fp = stream_socket_client( 'ssl://gateway.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
    if (!$fp) 
    {
        echo "Failed to connect: $err $errstr";
        return;
    }
 
    // Create the payload body, you can add a path to a custom sound in the app media folder, or remove the sound line completely, the badgecount is the number that will appear on the app icon
    $body['aps'] = array(
         'alert' => $message,
         'sound' => 'media/sfx/YouveWon.wav',
         'badge' => $badgecount
         );
 
    // Encode the payload as JSON
    $payload = json_encode($body);
 
    // Build the binary notification
    $msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
 
    // Send it to the server
    $result = fwrite($fp, $msg, strlen($msg));
    fclose($fp);
}

Tier 1 Setup

On iOS there is no need to call SetPushNotificationKeys, start by calling PushNotificationSetup(). If this returns 0 then this platform does not support push notifications. Otherwise wait for GetPushNotificationToken() to return something other than an empty string, if it returns "Error" then something went wrong. Once you have the token you need to send it to your server, you might also want to send some identifying information like a userID so you know who this token belongs to. The code we use looks something like this

g_Net_UserID = 01234 // some user ID that your server can use to recognise whos key this is
result = PushNotificationSetup()
if ( result = 1 )
    token = GetPushNotificationToken()
    while ( token = "" )
        token = GetPushNotificationToken()
    endwhile
 
    params$ = "token="+token+"&platform="+getdevicebasename() + "&id=" + str(g_Net_UserID)
    SendHTTPRequestASync( conn, "sendToken.php", params$ ) // we do not need the server to return anything so we can ignore getting the response
endif

In this example we also send the output of GetDeviceBaseName so we know which platform this token belongs to, iOS and Android use different methods. The server will need to remember the token and who it belongs to so you can send them push notifications later, be aware that the tokens can be 183 characters or more in the case of Android. The device takes no further action after this, it simply sends off its token and the server decides when to send a notification.

When you want to send a notification use the device token to send a message to a particular device. For example when two users are playing a turn based game and one device notifies your server it has finished its turn, the server can use the user ID to find the token that belongs to the opponent and send them a notification.