我正在使用 Apples iOS Enhanced Notification Format 批量发送推送通知,并使用本文中描述的 PHP 解决方案:https ://stackoverflow.com/a/10059000/300129
此时的经验是,当我发送推送通知时,有些设备正在接收消息,有些设备没有。结果不一致。有时设备 X 会收到通知,有时设备 X 不会。我正在记录所有内容,但没有收到任何错误响应。
任何关于正在发生的事情的想法都会非常有帮助。
我正在使用 Apples iOS Enhanced Notification Format 批量发送推送通知,并使用本文中描述的 PHP 解决方案:https ://stackoverflow.com/a/10059000/300129
此时的经验是,当我发送推送通知时,有些设备正在接收消息,有些设备没有。结果不一致。有时设备 X 会收到通知,有时设备 X 不会。我正在记录所有内容,但没有收到任何错误响应。
任何关于正在发生的事情的想法都会非常有帮助。
即使APNS 服务器接受了推送通知,也不能保证确实会发送。
就您的服务器而言,推送通知是一劳永逸的;将通知发送到APNS后,无法找出通知的状态。交货时间也可能有所不同,从几秒钟到半小时不等。
此外,用户的 iPhone 可能无法一直接收推送通知。它们可能位于不允许与APNS建立连接的WiFi 网络上,因为所需的端口被阻止。或者手机可以关机。
当该设备重新上线时, APNS将尝试传递它收到的最后一个通知,但它只会尝试有限的时间。一旦超时,推送通知将永远丢失!
您链接到的答案中的解决方案有问题。它会在每条消息发送后尝试读取错误响应,但读取会立即返回,并且不会等待响应变为可用。虽然这比在每条消息后等待潜在错误响应 X 毫秒更有效,但您可能会错过错误响应,并且 Apple 可能会在您不知道发生任何错误的情况下断开连接。
虽然我不能给你代码来解决你的问题,但我会给你一些建议。
这是您应该使用的逻辑(根据Apple),但我还没有设法使其可靠地工作(至少在我的Java实现中没有):
推送通知吞吐量和错误检查
如果您看到吞吐量低于每秒 9,000 条通知,则您的服务器可能会受益于改进的错误处理逻辑。
以下是使用增强的二进制接口时如何检查错误的方法。继续写入,直到写入失败。如果流已准备好再次写入,请重新发送通知并继续。如果流尚未准备好写入,请查看流是否可用于读取。
如果是,请从流中读取所有可用的内容。如果返回零字节,则连接因错误(例如无效的命令字节或其他解析错误)而关闭。如果您返回六个字节,这是一个错误响应,您可以检查响应代码和导致错误的通知的 ID。您需要再次发送该通知之后的所有通知。
发送完所有内容后,请最后一次检查错误响应。
仅仅因为正常的延迟,断开的连接可能需要一段时间才能从 APN 回到您的服务器。由于连接断开,在写入失败之前可以发送超过 500 条通知。大约 1,700 次通知写入可能会因为管道已满而失败,因此在流准备好再次写入时重试。
现在,这里是权衡变得有趣的地方。您可以在每次写入后检查错误响应,并立即发现错误。但这会导致发送一批通知所需的时间大幅增加。
如果您正确捕获了设备令牌并将它们发送到正确的环境,那么设备令牌应该几乎都是有效的。因此,假设故障很少见,进行优化是有意义的。如果您在检查错误响应之前等待写入失败或批处理完成,甚至计算再次发送丢弃的通知的时间,您将获得更好的性能。
这些都不是真正特定于 APN 的,它适用于大多数套接字级编程。
如果您选择的开发工具支持多线程或进程间通信,您可以让一个线程或进程一直等待错误响应,并让主发送线程或进程知道何时应该放弃并重试。
这取自 Apple 的技术说明:故障排除推送通知。
我不知道您是如何在 PHP 中检测到写入失败的,但是当它发生时,您应该再次尝试写入失败的通知,如果再次失败,请尝试读取错误响应并关闭连接。
如果您设法阅读错误响应,您将知道哪个通知失败并且您将知道错误类型(最可能的错误是 8 - 无效的设备令牌)。您提到的答案中的代码在识别出该错误后没有做任何事情。如果在编写 100 条消息后收到第 80 条消息的错误响应,则必须重新发送消息 81 到 100,因为 Apple 从未收到它们。就我而言(Java 服务器),我并不总是能够读取错误响应(有时在尝试从套接字读取响应时会出错)。在这种情况下,我只能继续发送下一个通知(并且无法知道 Apple 实际收到了哪些通知)。这就是为什么保持数据库中没有无效标记很重要的原因。
如果您保持数据库清洁(即仅在其中存储 Apple 发送到您的应用程序的设备令牌,并且所有这些设备令牌都属于相同的推送环境 - 沙盒或生产环境),那么您不应该遇到任何无效的设备令牌。
在 Java 中实现推送通知服务器端时,我遇到了与您类似的问题。我无法可靠地获得 Apple 返回的所有错误响应。
我发现在 Java 中有一种禁用 TCP Nagle 算法的方法,该算法会导致在将多条消息批量发送到 Apple 之前对其进行缓冲。尽管 Apple 鼓励我们使用 Nagle 的算法(出于性能原因),但我发现当我禁用它并在我发送给他们的每条消息后尝试读取 Apple 的响应时,我设法收到 100% 的错误响应(我通过编写一个模拟 APNS 服务器的进程来验证它)。
通过禁用 Nagle 的算法并慢慢发送通知并尝试在每条消息后读取错误响应,您可以找到数据库中的所有无效令牌并将其删除。一旦您知道您的数据库是干净的,您就可以启用 Nagle 的算法并快速恢复发送通知,而无需费心阅读来自 Apple 的错误响应。然后,每当您在向套接字写入消息时遇到错误时,您可以简单地创建一个新套接字并重试仅发送最后一条消息。
我在我的几个应用程序中也遇到过这个问题。某些设备没有收到推送通知的原因可能是:
就我而言,在开发过程中,一些 APN 没有在一个设备中接收(我正在使用PushMeBaby进行测试)。
我从我的设备中删除了与我的项目相关的所有以前的配置文件,从那一刻起一切都很好。为此,请转到设置 > 配置文件。
也许我与配置文件有某种冲突,因为我正在处理的项目在此过程中更改了捆绑包 ID 和配置文件。