PHP technique to query the APNs Feedback Server
Can someone clarify what the APNs (Apple Push Notification) wants as far as how you query it?
The docs say it starts sending as soon as the connection is made. Does this mean that I don't do an fread()
on it?
Here's my current code to try and read it. I did NOT put the fread()
in a loop as I do not know what response indicates "no more records to read" and I didn't want an infinite loop on my server.
<?php
$apnsCert = 'HOHRO-prod.pem';
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
stream_context_set_option($streamContext, 'ssl', 'verify_peer', false);
$apns = stream_socket_client('ssl://feedback.push.apple.com:2196', $error, $errorString, 60, STREAM_CLIENT_CONNECT, $streamContext);
echo 'error=' . $error;
echo 'errorString=' . $errorString;
$result = fread($apns, 38);
echo 'result=' . $result;
fclose($apns);
?>
So far all I am getting is a null reply. There are no errors so it is connecting.
I don't know if the null reply means no data is there, or my fread()
is the wrong way to do it.
Thanks
Here's a big gotcha which confused me when I first tried connecting: the APNS feedback servers only return the device tokens that have "expired" since your last feedback request. Which means most of the time you'll get a NULL response unless you're already dealing with a high volume of users of your app.
So make sure you store the expired device tokens to disk or db, because after your feedback query they're gone for good. This makes testing a pain to say the least!
Here's a complete function to fetch the device tokens from the APNS feedback servers (many thanks to the answers above for helping me put it all together):
function send_feedback_request() {
//connect to the APNS feedback servers
//make sure you're using the right dev/production server & cert combo!
$stream_context = stream_context_create();
stream_context_set_option($stream_context, 'ssl', 'local_cert', '/path/to/my/cert.pem');
$apns = stream_socket_client('ssl://feedback.push.apple.com:2196', $errcode, $errstr, 60, STREAM_CLIENT_CONNECT, $stream_context);
if(!$apns) {
echo "ERROR $errcode: $errstr\n";
return;
}
$feedback_tokens = array();
//and read the data on the connection:
while(!feof($apns)) {
$data = fread($apns, 38);
if(strlen($data)) {
$feedback_tokens[] = unpack("N1timestamp/n1length/H*devtoken", $data);
}
}
fclose($apns);
return $feedback_tokens;
}
If all is well, the return values from this function will look something like this (via print_r()):
Array
(
Array
(
[timestamp] => 1266604759
[length] => 32
[devtoken] => abc1234..............etcetc
),
Array
(
[timestamp] => 1266604922
[length] => 32
[devtoken] => def56789..............etcetc
),
)
That code looks right however you need to loop and check for end of stream in order to read all the device codes.
while (!feof($apns)) {
$devcon = fread($apns, 38);
}
However my problem is the actual unpacking of the data. Does anyone know how to unpack the binary data which you've just read to get the actual device ID (as string) along with the timestamp etc?
I got the solution from apple forum and it is for development. Try this for production also.
"Well, as dumb as it sounds, I found a solution:
Create a dummy app id in the program portal, enable development push notifications on it Create and download the associated provisioning profile Create a new xcode project, and invoke the registerForRemoteNotificationTypes method on start. Install the dummy app on your device. At this point, you should have two DEVELOPMENT apps running on your device: the original app and the dummy app. Both should be registered to receive push notifications. Uninstall the original app, and try to send a push notification to that app. Invoke the feedback service, and you should receive data back."