Powered by coANDco UK

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 from SamuraiBlog.com 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.

Please check out our sponsor, thanks to whom How2s.org is FREE: