July 10,
2009
By David mytton
See also:
How
To renew your apple push notification push SSL Certificate
One of the widely anticipated features of the new iPhone OS 3.0
Is push
Communications
Which allow messages to be sent directly to
Individual device relevant to the application that has been installed.
Apple have demoed this as useful for news alerts, or IM communications
However it fits in perfectly with the nature of our server monitoring
Service, server Density
.
Wp-image-288 "Title =" Server
Monitoring iPhone application alert view "src =" http://boxedice.files.wordpress.com/2009/07/sd-iphone-push-alert.png? W = 200 & H = 300 "alt =" server monitoring iPhone application alert view "width =" 200 "Height =" 300 ">
As part of the product, we
Have an iPhone application
That between des push notifications as
Alerting option so you can be notified via push direct to your iPhone
When one of your server alerts have been triggered. This is useful since
Our app can then be launched to instantly see the details of the server
That has caused the alert.
Apple provides detailed
Code documentation for the iPhone OS code
That is needed
Implement and handle the alerts on the device but only provides a higher
Level guide for the provider server side.
As a provider, you need to communicate with the apple push
Notification Service (apns) to send the messages that are then pushed
The phone. This is necessary so that the device only needs to maintain 1
Connection to the apns, helping to reduce battery usage.
This tutorial will go into code-level detail about how we built our
Push notification provider server to allow us to interact with the apns
And use the push notifications with our server monitoring iPhone
Application. Since we develop in PHP, our examples will be in PHP 5.
Basic Structure
- You connect to the apns using your unique SSL Certificate
- Cycle through the messages you want to send (or just send 1 if you
Only have 1)
- Construct the payload for each message
- Disconnect from apns
The flow of Remote-Notification data is one-way.
Provider composes a notification package that includes des the device token
For a client application and the payload. The provider sends
Notification to apns which in turn pushes the notification to
Device.
-Apple
Documentation
Wp-image-289 "Title =" apns flow "src =" http://boxedice.files.wordpress.com/2009/07/remote_notif_simple.jpg? W = 600 & H = 82 "alt =" apns flow "width =" 600 "Height =" 82 ">
Restrictions
- The payload is limited to 256 bytes in total-this has des both
The actual body message and all of the optional and additional
Attributes you might wish to send. push notifications are not designed
For large data transfer, only for small alerts. For example we only send
A short alert message detailing the server monitoring alert triggered.
- Apns does not provide any Status feedback as to whether your message
Was successfully delivered. One reason for this is that messages are
Queued to be sent to the device if it is unreachable, however only
Last sent message will be queued-overwriting any previously sent
Undelivered messages.
- Push configurications shoshould not be used for Critical alerts because
The message will only be delivered if the device has Wifi or cellular
Connectivity, which is why we recommend combining push with another
Alerting method such as e-mail or SMS for our server monitoring alerts.
- The SSL certificates used to communicate with apns, discussed below,
Are generated on an application level. The Implementation discussed in
This tutorial only concerns a single iPhone application so if you have
Several, you will need to adapt the Code to use the appropriate
Certificate (s) where necessary.
Device token
Each push message must be "addressed" to a specific device. This is
Achieved by using a unique devicetoken generated by apns within your
IPhone application. Once this token has been retrieved, you need
Store it on your server, not within your iPhone application itself. It
Looks something like this:
c9d4c07c fbbc26d6 ef87a44d 53e16983 1096a5d5 fd825475 56659ddd
f715defc
For the server density iPhone application, we call the necessary
Generation methods on app launch and pass it back to our servers via an HTTP
API call
. This stores the devicetoken in a database on our servers
For that user so we can then communicate with the device linked to that
User.
Feedback Service
Apple provide a feedback
Service
Which you are supposed to occasionally poll. This will
Provide a list of devicetokens that were previusly but are no longer
Valid, such as if the user has uninstalled your iPhone application. You
Can then remove the devicetoken from your database so you do not
Communicate with an invalid device.
Using the feedback service is not covered by this tutorial.
Certificates
The first thing you need is your push certificates. These identify
You when communicating with apns over SSL.
Generating the apple push notification SSL certificate on Mac:
- Log in to the iPhone
Developer Connection Portal
And click app IDS
- Ensure you have created an app ID without a wildcard. wildcard IDS
Cannot use the push notification service. For example, our iPhone
Application ID looks something likeAB123346CD.com.serverdensity.iphone
- Click Configure next to your app ID and then click the button
Generate a push notification certificate. A wizard will appear guiding
You through the steps to generate a signing authority and then upload it
To the portal, then download the newly generated certificate. This step
Is also covered
In the apple documentation
.
- Import your
aps_developer_identity.cer
Into your
Keychain by double clicking.cer
File.
- Launch keychain assistant from your local Mac and from the login
Keychain, filter by the certificates category. You will see
Expandable option called "Apple development push services"
- Expand this option then right click on "Apple development push
Services> export "Apple development push services id123". Save this
As apns-dev-cert.p12 file somewhere you can access it.
- Do the same again for the "Private Key" that was revealed when you
Expanded "Apple development push services" ensuring you save it
A apns-dev-key.p12 file.
- These files now need to be converted to the PEM format by executing
This command from the terminal: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
- If you want to remove the passphrase, either do not set one when
Exporting/converting or execute:openssl rsa -in apns-dev-key.pem -out apns-dev-key-noenc.pem
- Finally, you need to combine the key and Cert files into
Apns-dev.pem file we will use when connecting to apns:cat apns-dev-cert.pem apns-dev-key-noenc.pem > apns-dev.pem
It is a good idea to keep the files and give them descriptive names
Shocould you need to use them at a later date. The same process above
Applies when generating the production certificate.
Payload Contents
The payload
Is formatted in JSON, compliant with the RFC 4627 standard. It consists
Of several parts:
- Alert-the text string to display on the device
- Badge-the integer number to display as a badge by the application
Icon on the device home screen
- Sound-the text string of the name of the sound to accompany
Display of the message on the device
- This tutorial will only deal with the basics by sending a simple
Alert text string but this can also be another dictionary containing
Various options to display custom buttons and the like.
Creating the payload
Using PHP it is very easy to create the payload based on an array and
Convert
It To JSON
:
$payload['aps'] = array('alert' => 'This is the alert text', 'badge' => 1, 'sound' => 'default');
$payload = json_encode($payload);
Echoing the contents$payload
Wocould show you the JSON
String that can be sent to apns:
{
"aps" : { "alert" : "This is the alert text", "badge" : 1, "sound" : "default" }
}
This will cause a message to be displayed on the device, trigger
Default alert sound and place a "1" in the badge by the application
Icon. The default buttons "close" and "view" wocould also appear on
Alert that pops up.
For the server density server monitoring iPhone application, it is
Important for the user to be able to tap "View" and go directly to
Server that generated the alert. To do this, we add an extra dictionary
In of our own custom values:
$payload['aps'] = array('alert' => 'This is the alert text', 'badge' => 1, 'sound' => 'default');
$payload['server'] = array('serverId' => $serverId, 'name' => $name);
$output = json_encode($payload);
The custom dictionaryserver
Is passed to the application
On the device when the user taps "view" so we can load the right server.
The JSON looks like this:
{
"aps" : { "alert" : "This is the alert text", "badge" : 1, "sound" : "default" },
"server" : { "serverId" : 1, "name" : "Server name")
}
The size limit of 256 bytes applies to this entire payload, including
Any custom dictionaries.
The raw Interface
Once an alert is generated within server density, the payload is
Built and then inserted into a queue. This is processed separately so
That we can send multiple payloads in one go if necessary.
Apple recommends this method because if you are constantly ing
And disconnecting to send each payload, apns may block your IP.
As described
By Apple:
The raw interface employs a raw socket, has binary
Content, is streaming in nature, and has zero acknowledgment responses.
Size-full wp-image-293 "Title =" apns binary format "src =" http://boxedice.files.wordpress.com/2009/07/aps_provider_binary.jpg? W = 522 & H = 111 "alt =" apns binary format "width =" 522 "Height =" 111 ">
Opening the connection
The PHP 5 code to open the connection looks like this:
$apnsHost = 'gateway.sandbox.push.apple.com';
$apnsPort = 2195;
$apnsCert = 'apns-dev.pem';
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
$apns = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
If an error has occurred you can pick up the error message from$errorString
.
This will also contain the details if your SSL certificate is not
Correct.
The certificate file is read in relative to the current working
Directory of the executing PHP script, so specify the full absolute path
To your certificate if necessary.
Note that when testing you must use the sandbox with the development
Certificates. The production hostname isgateway.push.apple.com
And must use the separate and different production certificate.
Sending the payload
At this point, the code we use loops through all the queued payloads
And sends them. Constructing the binary content to send to apns is
Simple:
$apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
fwrite($apns, $apnsMessage);
Note that$deviceToken
Is supported ded from our database
And stripped of the spaces it is provided with by default. We also
Include a check to send an error to us in the event that$payload
Is Over 256 bytes.
$apnsMessage
Contains the correctly binary formatted
Payload andfwrite
Call writes the payload to
Currently active streaming connection we opened previusly, contained in
$apns
.
Once completed, you can close the connection:
socket_close($apns);
fclose($apns);
Php-apns
There is a free, open source server library that does all the above
Functionality called PHP-apns
.
We chose to implement it ourselves because it has a further dependancy
On memcached
, We do not
Want to rely on 3rd party code for large and critical aspects of our
Code-base and I am apprehensive about the suitability of PHP for running
A continuous server process. We do all the above queue Processing Using
Our own Crom cron system which runs every few seconds-that way PHP
Scripts do not need to be run as processes, something I'm not sure they
Were designed to do!
All done
That's it! If you have any problems, post in the comments below and
We'll do our best to help out. Also, stack
Overflow
Is your friend.
//////////////////////////////////////// //////////////////////////////////////// //////////////////////////////////////// //////////////////////////////////////// //
Http://blog.boxedice.com/2009/07/10/how-to-build-an-apple-push-notification-provider-server-tutorial/