Polling Apple Push Notification feedback service with Node.js

Apple assumes that your app polls the Push Notification Feedback Service to get information about App uninstalls so you can stop sending  notifications to those devices. Service returns list of tokens with uninstall timestamps.

This is how you can do it with Node.js. First, check TLS Example and how to create SSL certs to understand basics of how to make secure SSL connection with Node.js.

First simple utility to convert binary data to hex

function bintohex(buf) {

    var hexbuf = new Buffer(buf.length * 2);

    function nibble(b) {
	if (b <= 0x09) return 0x30 + b;
	return 0x41 + (b - 10);
    }

    for(var i=0; i < buf.length; i++) {
        hexbuf[i*2] = nibble(buf[i] >> 4);
        hexbuf[i*2+1] = nibble(buf[i] & 0x0F);
    }
    return hexbuf.toString('ascii', 0, hexbuf.length);
}

Then define function that will be called with push device tokens

function processTokens( pdtokens ) {

    // send or process tokens here
    pdtokens.forEach( function( pd  ){
	console.log('TOKEN ' + pd.token ' INVALIDATED AT ' + new Date( pd.timestamp ) );
    });
}

Then polling function that does it all, note that it assumes function connectAPN that needs simply create SSL connection to ‘feedback.push.apple.com’ port 2196 with your apps client cert and private key.

function pollAPNFeedback() {

    console.log("Connecting APN feedback service");

    connectAPN(function( apnc ) {

	var bufferlist = [];
	apnc.on('data', function(data) {
	    // APN feedback starts sending data immediately on successful connect
	    bufferlist.push(data)
	});

	apnc.on('end', function() {
	    console.log("APN Connection closed");

	    // tokens are parsed to object
	    var pdtokens = []

	    // concatenate all asynchronously collected buffers, and parse the PDU's from them
	    var parsebuf;
	    var totall = 0;
	    for(var i=0; i < bufferlist.length; i++) {
	        totall += bufferlist[i].length;
	    }
	    parsebuf = new Buffer(totall);
	    var offset = 0;
	    for(var i=0; i < bufferlist.length; i++) {
		bufferlist[i].copy(parsebuf, offset, 0);
		offset += bufferlist[i].length;
	    }

	    var count = 0;
	    for(var k = 0; k < parsebuf.length; ) {
		count++;
                 // parse timestamp
		var ts = ((parsebuf[k] << 24) + (parsebuf[k+1] << 16) + (parsebuf[k+2] << 8) + parsebuf[k+3]) >>> 0;
		k += 4;
		var l = ((parsebuf[k] << 8) + parsebuf[k]) >>> 0;
                  k += 2;
                  var pdtokenbuf = new Buffer(l);
		parsebuf.copy(pdtokenbuf, 0, k, k + l);
		k += l;

		var hextoken = bintohex(pdtokenbuf);
		pdtokens.push({timestamp: ts, token:hextoken});

		// process tokens in 100 item batches
	        if( count >= 100 ) {
		    processTokens( pdtokens );
		    count = 0;
		    pdtokens = [];
		}
	}
	processTokens(pdtokens);
         setTimeout(pollAPNFeedback, 1000*60*60*4);
    });
}

pollAPNFeedback();

The function read raw binary data from connection and after Feedback services closes the socket (this happens immediately after it has sent the data) it parses tokens and calls processing function to handle them. Function connects to server every 4 hours.

Note that feedback service host and port is different for sandbox (testing environment) that also needs its own SSL certificates.

4 Responses to Polling Apple Push Notification feedback service with Node.js

  1. York says:

    Hi,

    Thanks for sharing, but I found some glitches in the article,

    > for(var i=0; i > 4);
    > hexbuf[i*2+1] = nibble(buf[i] & 0x0F);
    > }

    did you miss something here?

    and,

    > setTimeout(pollAPNFeedback, 1000*60*4);

    it’s 4 minutes indeed, not 4 hours.

    Regards.

    • tikonen says:

      Thanks for pointing those out, the code was indeed botched on copy-paste. Should be ok now.

  2. Jonathon says:

    Would you be able to show an example of if you wanted to send notifications to only specific phones? I have an app where users filter what push notifications they receive, and the info is stored on the server, but I haven’t been able to parse where the specific phones are identified in this code.

  3. Pingback: Simple test server for Apple push notification and feedback integration | Brave New Method

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: