为什么只有部分设备会收到推送通知

发布于 2024-10-02 03:39:29 字数 1096 浏览 3 评论 0原文

我设置了一个推送通知服务,根据 RSS 源向客户端发送通知。我有一项服务每分钟运行一次,以查看是否有新帖子添加到提要中。如果是这样,该服务将向所有客户端发送通知。然而,一些人一直抱怨说他们没有收到任何推送通知。这是我用来发送消息的函数:

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

我做错了什么吗? PHP 不能处理数千次的 for 循环并通过连接传输消息吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

胡大本事 2024-10-09 03:39:30

我认为这里有 3 个潜在的问题:

1)你连接太频繁(可能比你想象的更频繁),而 Apple 拒绝/放弃连接,因为它认为你太垃圾了。老实说,这是非常明显的 - 你的 fwrite 会失败,因为流会死掉。

理想情况下,APNS 会尽可能长时间地保持连接打开状态(我们使用的不活动超时时间为 10 分钟),而不是每分钟都重新建立连接。 SSL 协商会消耗 CPU 资源,但保持打开的连接相对便宜。因此,如果可以的话,我会在运行之间保持该连接打开,并在由于任何原因断开时自动重新建立它。

2)您没有进行任何错误检查。请参阅 APNS 指南,但它可能会沿着同一连接做出错误响应,而您只是忽略它。我认为每次循环时您都应该检查是否有任何数据要读取,读取它并将其解释为错误响应数据包。至少您应该记录错误响应。

3)这个机会渺茫。您是否有可能实际上已经删除了这些用户,也许是因为反馈服务告诉您这样做?如果用户长时间断开连接,服务将无法发送通知,并且可能会告诉您从列表中删除这些设备。如果您在应用程序启动时不重新订阅这些用户(或至少确认他们仍然订阅),那么他们会认为他们已订阅通知,而实际上您已经选择忘记它们。

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.

岁月静好 2024-10-09 03:39:30

嗯……我没觉得有什么问题。客户端是否真的为您的应用程序启用了推送通知?

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

伏妖词 2024-10-09 03:39:29

除了其他人已经提出的建议之外,这里还有推送不起作用时需要考虑的事项清单。

  1. 如果您的总推送数据包超过 256 字节(包括初始标头、令牌和 JSON 负载),APNS 将直接丢弃它。如果您不使用“高级”错误检测,您将永远不会知道,直到您的用户开始抱怨。您要做的就是检查编码数据包的大小,即您将通过线路传输的实际数据的大小,如果它超过 256 字节,要么拒绝它,要么截掉一些消息文本并进行编码再次直到它的长度 <= 256 字节。
  2. 如果您的有效负载有任何问题(包括长度),APNS 将丢弃它,APNS 也会丢弃您的连接。
  3. 如果您有持久连接,并且空闲时间大约为 20 分钟左右,APNS 会默默地断开该连接。您必须为此做好准备并重新连接。
  4. 如果您的 APNS 证书已过期或不正确,并且您继续尝试以过高的速率进行连接,APNS 会将您的 IP 地址列入黑名单,持续一段未知的时间,但这不仅仅是几分钟,甚至可能是一个小时或更长时间。
  5. 如果 iPhone 没有 3G 接收,但有 WiFi,它会尝试使用它来推送通知。如果您位于不允许出站连接到 Apple 网络的防火墙区域,您的 iPhone 将无法打开到 APNS 的套接字,并且您是 SOL。
  6. 我不确定每次客户端连接到 APNS 时您的 SQL DB 是否都会使用推送令牌进行更新。拥有推送令牌的静态数据库是一个问题,因为推送令牌不会永远保持不变 - 甚至在 APNS 编程指南中也是这么说的。 iPhone 应该在每次启动时获取推送令牌,并将其传送到服务器端(我相信你可以优化这一点 - iPhone 可以持久存储最后一个令牌,并且仅在它发生更改时才发送它)。但有些事情可能会导致推送令牌发生变化,例如重新注册iPhone进行推送,我不确定还有什么。我所知道的是,依赖推送令牌就像 GUID 一样是自找麻烦。下次令牌更改时,如果您的数据库未更新,则告别推送到该客户端。

希望这有帮助。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文