how to properly send push notifications

2019-08-09 17:12发布

问题:

This is not my first app sending push notifications but it is my first app where I send a notification to all my users at the same time.

What Im experiencing is that not all my users receive the notification, only some of them, even though they have the settings correct(ie notifications for my app enabled), also the code is correct since it is sent to some of them, so my guess is that the code "misses" some executions, since the conection with the APNS is asyncronous so somehow( you tell me if im wrong) that it messes the queue of sending notifications.

Here's the code:

function sendNotification(){

$sql = "SELECT * FROM users WHERE phone = 'iPhone' AND pushID != ''";
try {
    $db = getConnection();
    $stmt = $db->prepare($sql);  
    $stmt->execute();
    $users = $stmt->fetchAll(PDO::FETCH_OBJ);

    $request = Slim::getInstance()->request();
    $content = json_decode($request->getBody());
    $message = $content->message;

    foreach($users as $user){

            // Put your device token here (without spaces):
            $deviceToken = $user->pushID;


            // Put your private key's passphrase here:
            $passphrase = 'xxxxxxx';

            ////////////////////////////////////////////////////////////////////////////////

            $ctx = stream_context_create();
            stream_context_set_option($ctx, 'ssl', 'local_cert', 'xxxxx.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);

            echo 'Connected to APNS' . PHP_EOL;

            // Create the payload body
            $body['aps'] = array(
                'alert' => $message,
                'sound' => 'default'
                );

            // 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));

            if (!$result)
                echo 'Message not delivered' . PHP_EOL;
            else
                echo 'Message successfully delivered' . PHP_EOL;

            // Close the connection to the server
            fclose($fp);

    }
    $db = null;
} catch(PDOException $e) {
    echo '{"error":{"text":'. $e->getMessage() .'}}'; 
}
}

As you can see I fetch all my users with an iPhone and I send them the notification. My phone is the last user in that list and I didnt get it, another user that I know is one of the first ones and she got it. It either misses some of the users in the array or it just does the first half, no error is shown.

Im using Slim for this.

hope you can help me, thanks!

回答1:

It's possible that some of the device tokens you are sending to are invalid. Even one invalid device can explain what you are experiencing. When you send a notification with an invalid device token, Apple returns an error response and closes the socket.

It's possible that by the time your code detects that the socket is closed you already sent many notifications after the invalid one (it's even possible you finished sending all the notifications before detecting the socket is closed), which causes all of the notifications sent after the invalid one to be discarded. Such notifications must be resent to Apple after you create a new socket.

I suggest you read the Push Notification Throughput and Error Checking section in this document for further details.

Make sure that your database doesn't contain a mix of production device tokens and sandbox device tokens, since production tokens are invalid in sandbox environment and vice versa.