某些设备未收到 Apple 推送通知

Posted

技术标签:

【中文标题】某些设备未收到 Apple 推送通知【英文标题】:Some Devices Not Receiving Apple Push Notifications 【发布时间】:2014-02-10 15:34:53 【问题描述】:

我正在使用 Apples ios Enhanced Notification Format 批量发送推送通知,并使用本文中描述的 php 解决方案:https://***.com/a/10059000/300129

此时的体验是,当我发送推送通知时,有些设备正在接收消息,有些设备没有。结果不一致。有时设备 X 会收到通知,有时设备 X 不会。我正在记录所有内容,但没有收到任何错误响应。

对正在发生的事情的任何想法都会非常有帮助。

【问题讨论】:

您没有收到任何货物,还是需要很长时间?如果设备没有 SIM 卡,我们有时会看到半小时延迟 另外,您确定令牌适用于正确环境中的正确版本吗? 故障设备永远不会收到消息。是的,令牌是正确的,有时相同的故障设备会收到在不同时间发送的不同消息。同一台设备可能在周一出现故障,但在周二工作 - 或者可能在下午 1 点出现故障,然后在下午 3 点工作,然后在同一天下午 6 点出现故障。 当您说同一设备有时会发生故障而有时会工作时,当它发生故障时 - 您是单独向该设备发送通知,还是在同一连接上发送的多个通知的一部分短时间内?如果是后者,则在该设备之前发送到无效设备令牌的消息(有时有效)将导致连接关闭并忽略好令牌。很容易错过 Apple 指示哪个令牌无效的错误响应。 【参考方案1】:

即使 APNS 服务器接受了推送通知,也无法保证确实会发送。

就您的服务器而言,推送通知是一劳永逸的;在您将通知发送到 APNS 后,无法了解通知的状态。交货时间也可能有所不同,从几秒到半小时不等。 此外,用户的 iPhone 可能无法一直接收推送通知。它们可能位于不允许与 APNS 建立连接的 WiFi 网络 上,因为所需的端口已被阻止。或者手机可以关机。

APNS 将尝试在该设备返回在线时发送它收到的最后通知 em>,但它只会在有限的时间内尝试。一旦超时,推送通知将永远丢失!

【讨论】:

我理解这是现实,但我认为我们不会因为苹果方面的交付失败而遭受损失。相同的设备将 100% 接收通过不同脚本发送的消息,因此这可能是发送批量消息而不是发送个性化消息的结果。【参考方案2】:

您链接到的答案中的解决方案有问题。它会在每条消息发送后尝试读取错误响应,但读取会立即返回,并且不会等待响应变为可用。虽然这比在每条消息后等待潜在错误响应 X 毫秒更有效,但您可能会错过错误响应,并且 Apple 可能会在您不知道发生任何错误的情况下断开连接。

虽然我不能给你代码来解决你的问题,但我可以给你一些建议。

这是您应该使用的逻辑(根据 Apple),但我还没有设法使其可靠地工作(至少在我的 Java 实现中没有):

推送通知吞吐量和错误检查

如果您发现吞吐量低于每秒 9,000 条通知,您的服务器可能会受益于改进的错误处理逻辑。

以下是使用增强型二进制接口时检查错误的方法。继续写入,直到写入失败。如果流已准备好再次写入,请重新发送通知并继续。如果流尚未准备好写入,请查看流是否可供读取。

如果是,请从流中读取所有可用的内容。如果返回零字节,则连接因错误(例如无效命令字节或其他解析错误)而关闭。如果您返回六个字节,这是一个错误响应,您可以检查响应代码和导致错误的通知的 ID。您需要再次发送该通知之后的所有通知。

所有内容发送完毕后,最后一次检查错误响应。

由于正常延迟,断开的连接可能需要一段时间才能从 APN 回到您的服务器。由于连接断开,在写入失败之前可以发送超过 500 条通知。大约 1,700 次通知写入可能会因为管道已满而失败,因此在这种情况下,请在流准备好再次写入时重试。

现在,权衡取舍变得有趣了。您可以在每次写入后检查错误响应,并立即发现错误。但这会导致发送一批通知所需的时间大幅增加。

如果您正确捕获了设备令牌并将它们发送到正确的环境,那么它们几乎都应该是有效的。因此,假设故障很少见,进行优化是有意义的。如果您在检查错误响应之前等待写入失败或批处理完成,甚至计算再次发送丢弃的通知的时间,您将获得更好的性能。

这些都不是真正特定于 APN 的,它适用于大多数套接字级编程。

如果您选择的开发工具支持多线程或进程间通信,您可以让一个线程或进程一直等待错误响应,并让主发送线程或进程知道何时应该放弃并重试。

这摘自 Apple 的技术说明:Troubleshooting Push Notifications。

我不知道你是如何在 PHP 中检测到写入失败的,但是当它发生时,你应该再次尝试写入失败的通知,如果再次失败,尝试读取错误响应并关闭连接.

如果您设法阅读错误响应,您将知道哪个通知失败并且您将知道错误类型(最可能的错误是 8 - 无效的设备令牌)。您提到的答案中的代码在识别出该错误后没有做任何事情。 如果在编写 100 条消息后收到第 80 条消息的错误响应,则必须重新发送消息 81 到 100,因为 Apple 从未收到它们。在我的情况下(Java 服务器),我并不总是能够读取错误响应(有时在尝试从套接字读取响应时会出错)。在这种情况下,我只能继续发送下一个通知(并且无法知道 Apple 实际收到了哪些通知)。这就是为什么保持数据库中没有无效令牌很重要的原因。

如果您保持数据库清洁(即仅在其中存储由 Apple 发送到您的应用程序的设备令牌,并且所有设备令牌都属于相同的推送环境 - 沙盒或生产环境),您应该不会遇到任何无效的设备令牌。

在用 Java 实现推送通知服务器端时,我遇到了与您类似的问题。我无法可靠地获得 Apple 返回的所有错误响应。

我发现在 Java 中有一种方法可以禁用 TCP Nagle 算法,该算法会导致在将多条消息批量发送给 Apple 之前对其进行缓冲。尽管 Apple 鼓励我们使用 Nagle 的算法(出于性能原因),但我发现当我禁用它并在我发送给他们的每条消息后尝试读取 Apple 的响应时,我设法收到 100% 的错误响应(我通过编写一个模拟 APNS 服务器的进程来验证它)。

通过禁用 Nagle 的算法并慢慢发送通知并尝试在每条消息后读取错误响应,您可以找到数据库中的所有无效令牌并将其删除。一旦您知道您的数据库是干净的,您就可以启用 Nagle 的算法并快速恢复发送通知,而无需费心阅读来自 Apple 的错误响应。然后,每当您在向套接字写入消息时遇到错误时,您只需创建一个新套接字并重试仅发送最后一条消息。

【讨论】:

这可能与我需要解决的问题相符。我将对此进行探索并报告。【参考方案3】:

我在我的几个应用程序中也遇到过这个问题。部分设备收不到推送通知的原因可能是:

使用带有生产 APNS 证书的沙盒 APNS 服务器。 -> 请检查一下 设备上安装了开发和生产临时配置文件。 -> 删除两个临时的,然后您必须等待至少 24 小时,以便苹果也从其服务器中删除设备令牌。

【讨论】:

【参考方案4】:

就我而言,在开发过程中,一些 APN 无法在一台设备中接收(我正在使用 PushMeBaby 进行测试)。

我从我的设备中删除了与我的项目相关的所有先前配置文件,从那一刻起一切都很好。为此,请转到“设置”>“个人资料”。

也许我与配置文件有某种冲突,因为我正在处理的项目在此过程中更改了捆绑包 ID 和配置文件。

【讨论】:

以上是关于某些设备未收到 Apple 推送通知的主要内容,如果未能解决你的问题,请参考以下文章

某些设备在 android 中未收到推送通知

某些 android 设备未收到 GCM 推送通知

推送通知有效负载未保存在某些设备上

APNS Apple 推送服务通知未收到

Apple 反馈服务和推送通知错误

APNS Apple 推送通知服务未收到来自 Apple 的成功消息