Why would only some devices be receiving push noti

2019-02-10 20:05发布

问题:

I set up a push notification service to send out notifications to clients based on an RSS feed. I have a service that runs every minute to see if a new post was added to the feed. If so, the service will send out a notification to all the clients. However, some people have been complaining saying that they are not receiving any push notifications. Here is the function that I use to send out the messages:

function _sendMessages($tokens, $message) {
        $payload['aps'] = array('alert' => $message, 'sound' => 'default');
        $payload = json_encode($payload);

        $context = stream_context_create();
        stream_context_set_option($context, 'ssl', 'local_cert', $this->certificate);
        stream_context_set_option($context, 'ssl', 'passphrase', '*********');

        $apns = stream_socket_client('ssl://' . $this->server . ':' . $this->port, $error, $errorString,60, STREAM_CLIENT_CONNECT, $context);

        foreach($tokens as $row) {
            $apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $row->device_token)) . chr(0) . chr(strlen($payload)) . $payload;
            $fwrite = fwrite($apns, $apnsMessage);

            if (!$fwrite) echo 'push error';
            else echo 'push success';
        }

        fclose($apns);
    }

Am I doing anything wrong? Can PHP not handle going through this for loop thousands of times and streaming messages over the connection?

回答1:

Other than the suggestions already made by others, here's a checklist of things to consider when pushes don't work.

  1. If your total push packet exceeds 256 bytes, including the initial header, token, and JSON payload, APNS will simply drop it. If you are not using the "advanced" error detection, you will never know until your users start complaining. What you have to do is check the encoded packet size, that is, the size of the actual data you will pump down the wire, and if it's longer than 256 bytes, either reject it, or cut off some of the message text and encode it again until it is <= 256 bytes long.
  2. If there is anything wrong with your payload in any way, including the length, APNS will drop it, and APNS will drop your connection, too.
  3. If you have a persistent connection, and it is idle for about 20 minutes or so, APNS will silently drop the connection. You have to be prepared for that and reconnect.
  4. If your APNS certificate has expired or is incorrect, and you continue trying to connect at too high a rate, APNS will blacklist your IP address for an unknown period of time, but it's much more than a few minutes, maybe even an hour or more.
  5. If the iPhone does not have 3G reception, but does have WiFi, it will try to use that for push notifications. If you are in a firewalled area that does not allow outbound connections to Apple's network, your iPhone will not be able to open a socket to APNS and you are SOL.
  6. I am not sure if your SQL DB is updated with push tokens every time a client connects to APNS. Having a static database of push tokens is an issue, because push tokens don't stay the same forever - it even says so in the APNS programming guide. The iPhone is supposed to get the push token each time it launches, and communicate it to the server side (and I am sure you can optimize this - the iPhone could store the last token persistently and send it only if it has changed). But some things can cause the push token to change, such as re-registering the iPhone for push, and I am not sure what else. All I know is that relying on a push token to be like a GUID is asking for trouble. The next time the token changes, if your DB is not updated, goodbye push to that client.

Hope this helps.



回答2:

I think there's 3 potential problems here:

1) You're connecting too often (maybe more often than you think you are), and Apple is refusing/dropping the connection because it thinks you're too spammy. That would be pretty obvious to be honest - your fwrite would fail because the stream would have gone dead.

APNS ideally like the connection held open for as long as possible (10 minutes is the inactivity timeout we use) rather than re-establishing it every minute. SSL negotiation costs CPU, but a connection being held open is relatively cheap. So I'd hold that connection open between runs if you can, and re-establish it automatically if it's been dropped for any reason.

2) You're not doing any error checking. See the APNS guide, but it may be responding back along the same connection with error responses and you're just ignoring that. I think that each time round the loop you should be checking if there's any data to read, reading it and interpreting it as an error response packet. At the very least you should be logging error responses out.

3) This one's a long shot. Is it possible that you have actually removed those users, perhaps because the feedback service told you to? If a user has been disconnected for a long time, notifications would fail to be delivered by the service, and it might tell you to remove those devices from your list. If you don't re-subscribe those users (or at least confirm that they are still subscribed) when the app launches, then they would think that they were subscribed to notifications when in fact you'd already chosen to forget about them.



回答3:

Hmm... I don't see anything wrong with it. Did the clients actually enable push notifications for your app?