Right now I'm using the following piece of code to send my push notifications
function applePush($deviceToken,$sound,$message,$object,$thread = 0)
{
$passphrase = 'Secret';
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'secret.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)
exit("Failed to connect: $err $errstr" . PHP_EOL);
//Customizable sounds
if ($sound == 0) { $sound = 'default'; }
else {$sound = '/' . $sound . '.wav'; }
// Create the payload body
if ($thread > 0)
{
$body['aps'] = array(
'alert' => $message,
'sound' => $sound,
'obj' => $object,
't' => $thread,
);
}
else
{
$body['aps'] = array(
'alert' => $message,
'sound' => $sound,
'obj' => $object
);
}
// Encode the payload as JSON
$payload = json_encode($body);
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
// Close the connection to the server
fclose($fp);
}
What I am in essence doing is:
1) Pulling 5000 (and growing) device token's from an SQL database.
2) Using a PHP loop, for each device token I run the above listed applePush function
Now this works just fine and everyone is getting the push from apple. Now the kicker is that, my own personal iphone was the first device in my SQL database, and I would get the push notification instantly. BUT, I just bought a new iphone and I am the last device in the database now, and I notice it takes me almost 30 minutes to get the notificaions now. I am thinking this has to do with the physical time to make all those connections to apple, but the time it gets to the 5000th device ID, 30 minutes has lapsed.
This got me reading and it seems that Apple actually suggests keeping a connection open to APNS instead of opening and closing connections constantly.
So I write to get everyones opinion on this, am I doing this all wrong? And if I am, how can I modify my code to get it inline with apple policy and make it faster/more efficient
Thank you!
Do not open and close connection 5000 times this is very expensive and not acceptable.
The Problem is unlike Android , Apple Server does not take an array of device tokens along with the playload.
A better approach is to loop trough your database and return an array.
This array will then be used in a loop once connection is open.
So you will have something like this:
//Apple Push Notifcations
$apn = new Apple_Push_Notifications();
//Get Device tokens into an array
$deviceTokens = array();
$deviceTokens = $apn->GetDeviceTokens();
//Push the notifications
if(count($deviceTokens) > 0){
$apn->applePush($deviceTokens,$sound,$message,$object,$thread);
}
//In applePush loop through all the tokens and submit
function applePush($deviceTokens,$sound,$message,$object,$thread = 0)
{
....
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
....
....
// Encode the payload as JSON
$payload = json_encode($body);
//Send the Push to each token the close connection
foreach ($deviceTokens as $deviceToken) {
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
}
// Close the connection to the server
fclose($fp);
}
You should keep the connection open as long as possible. Another way to improve performance is to have multiple threads (each with its own connection to APN server, which remains open) and divide the work of sending the push notifications between them.
Closing the connection after each message is not only bad for performance, it might also get your IP banned if Apple considers this as a DOS attack.
Keep your connections with APNs open across multiple notifications; don’t repeatedly open and close connections. APNs treats rapid connection and disconnection as a denial-of-service attack. You should leave a connection open unless you know it will be idle for an extended period of time—for example, if you only send notifications to your users once a day it is ok to use a new connection each day.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With