How to get started with Apple Push Notifications for iPhone or iPhone Touch
From How2s
A good link which describes the steps can be found under http://blog.boxedice.com/2009/07/10/how-to-build-an-apple-push-notification-provider-server-tutorial/
A good link to get your head around the certificate issues, check out Urban Airship:
http://urbanairship.com/docs/keys.html
And regarding the approval, it's good to know:
- app signed with a dev cert = sandbox url & dev apns cert, app signed with
- appstore/adhoc cert = prod url & prod apns cert
also using an adhoc/appstore app on a device that has previously used the dev app will cause springboard to crash. (so basically need two devices) (to be confirmed.)
Important: you MUST keep the connection to the sandbox, i.e. you must NOT connect, send push, disconnect. If you do, Apple may throttle you as a possible ddos
A PHP example script to trigger a push notification from a server could look something like this:
<?php // from http://www.macoscoders.com/2009/05/17/iphone-apple-push-notification-service-apns/ // call: /apns/apns.php?message=Hello%20from%20macoscoders&badge=2&sound=received5.caf $deviceToken = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; // Passphrase for the private key (ck.pem file) // $pass = ; // Get the parameters from http get or from command line $message = $_GET['message'] or $message = $argv[1] or $message = 'Message sent ' . @date("H:i:s d/M/Y", mktime()); $badge = (int)$_GET['badge'] or $badge = (int)$argv[2] or $badge = 111; $sound = $_GET['sound'] or $sound = $argv[3] or $sound = 'chime'; // Construct the notification payload $body = array(); $body['aps'] = array('alert' => $message); if ($badge) $body['aps']['badge'] = $badge; if ($sound) $body['aps']['sound'] = $sound; /* End of Configurable Items */ $ctx = stream_context_create(); stream_context_set_option($ctx, 'ssl', 'local_cert', 'push/apns-dev.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"; return; } else { print "Connection OK
"; } $payload = json_encode($body); // request one $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); ?>
Keeping the connection open
You need to keep the connection to the apns open, so you can't have a script running it. I did install a python daemon called pyapns (http://github.com/samuraisam/pyapns) from SamuraiBlog.com (http://samuraiblog.com/wordpress/) to deal with that. Installation on debian as follows:
Get all packages:
# apt-get update # apt-get install python-setuptools # apt-get install python-twisted # apt-get install python-all-dev # apt-get install libcurl4-openssl-dev # apt-get install libev-dev # apt-get install python-simplejson
Get OpenSSL:
# wget http://pypi.python.org/packages/source/p/pyOpenSSL/pyOpenSSL-0.10.tar.gz#md5=34db8056ec53ce80c7f5fc58bee9f093
Unzip, then build:
/usr/src/pyOpenSSL-0.10# python setup.py build
Install PyApns:
# easy_install pyapns
Start the server:
# python /usr/bin/twistd -r epoll web --class=pyapns.server.APNSServer --port=7077
Test it:
# python
Then in the python shell, type:
>>> from pyapns import configure, provision, notify
>>> configure({'HOST': 'http://localhost:7077/'})
True
>>> provision('appid', open('/path/to/certificate.pem').read(), 'sandbox')
>>> notify('appid', '6bcda4c0d2cd5fc1835ada95bd25fb1bbad39edb344699fc33e4e975caffc8ab', {'aps':{'alert': 'Hello!' }})
More detailled instructions and documentation can be found under: http://github.com/samuraisam/pyapns
Testing with PHP:
You can create a PHP script based on http://phpxmlrpc.sourceforge.net/ to test the script. You only need the client, so all you need is the file xmlrpc.inc from that package. Then you can use a test script similar to this:
<?
include '../vendors/xmlrpc.inc';
$hostName = 'localhost'; //your services endpoint here.
$rpcPath = '';
$port = 7077;
if($_GET['action'] == 'provisioning'){
$echoString = new xmlrpcmsg ( 'provision', array(
php_xmlrpc_encode('appid'),
php_xmlrpc_encode ('/path/to/certificate.pem'),
php_xmlrpc_encode ( 'sandbox' ),
php_xmlrpc_encode ( 100 )
)
);
$continue = true;
}
if($_GET['action'] == 'notify') {
$echoString = new xmlrpcmsg ( 'notify', array(
php_xmlrpc_encode('paparazzme'),
php_xmlrpc_encode (array('6bcda...', '7c008...')),
php_xmlrpc_encode (array(array("aps" => array("alert" => "Hello User 1" )), array("aps" => array("alert" => "Hello User 2" ))))
)
);
$continue = true;
}
if($continue == true) {
//create a client handle and send request
$client = new xmlrpc_client ( $rpcPath, $hostName, $port );
//a little verbose debug
$client->setDebug ( 2 );
//the response
$response = &$client->send ( $echoString );
//check if response is good
if (! $response->faultCode ()) {
$returnedString = php_xmlrpc_decode($response->value());
print "
Returned string is: " . $returnedString . "
";
} else {
print "An error occurred:
";
print "Code: " . $response->faultCode () . " Reason: '" . htmlspecialchars ( $response->faultString () ) . "'
";
}
}
?>
Don't get confused by the error message Code: 2 Reason: 'Invalid return payload: enable debugging to examine incoming payload found not-xmlrpc xml element NIL' ... that's normal because the server doesn't reply.

