当推送通知到达(未收到)设备时调用委托

Posted

技术标签:

【中文标题】当推送通知到达(未收到)设备时调用委托【英文标题】:Delegate called when push notification arrives (not received) on a device 【发布时间】:2016-07-25 10:44:39 【问题描述】:

我知道当推送通知到达设备时(并且应用程序没有打开它),没有办法检查(我可能错了)。但是在我的应用程序中有一种这样的情况,必须知道通知已经到达设备。 我在应用程序中有多个选项卡,其中 2 个具有徽章实现,具体取决于推送通知。所以基本上有两种不同类型的推送通知

假设如果一种类型的通知到达设备并且用户选择不看到通知。这样,特定标签的徽章计数将增加 1。但问题是,哪一个。因为当时我打开应用程序,我没有信息,哪种通知类型已经到达。或者更准确地说,要增加哪个标签标记数。 简而言之,我怎么知道通知已到达设备(未收到)?

【问题讨论】:

您可以在服务器的通知负载中传递"badge" : count,这行不通? @BhumitMehta :问题是,在这种情况下,didReceiveRemoteNotification 永远不会从我们获取有效负载的地方调用,因为我没有打开通知。 是的,但如果通知负载包含非 0 值的“徽章”键,则应自动设置徽章。 @BhumitMehta :我猜这就是应用程序徽章。而且即使我有徽章值,我在打开应用程序时也不知道我需要设置哪个标签徽章。 无法保证您总是会获得 apns 有效负载。你可能会错过一些东西,在某些情况下,如果用户没有点击通知。为确保您拥有正确的徽章计数,请在您的应用启动时与您的服务器同步。这样,您将获得更新的徽章数量。 【参考方案1】:

无法使用公共 API 获取此信息。

来自Local and Remote Notifications Programming Guide:

让我们回顾一下系统在运行时可能出现的情况 为应用提供本地通知或远程通知。

当应用程序未在 前景。在这种情况下,系统会显示通知, 显示警报、标记图标、可能播放声音,以及 可能会显示一个或多个操作按钮供用户点击。

用户点击 ios 8 通知中的自定义操作按钮。在这个 情况下,iOS 调用 应用程序:handleActionWithIdentifier:forRemoteNotification:completionHandler: 或者 应用程序:handleActionWithIdentifier:forLocalNotification:completionHandler:。 在这两种方法中,您都可以获得操作的标识符,以便您可以 确定用户点击了哪个按钮。您还可以获得遥控器 或本地通知对象,以便您可以检索任何信息 你需要处理这个动作。

用户点击警报中的默认按钮或点击(或单击) 应用程序图标。如果点击默认操作按钮(在正在运行的设备上 iOS),系统启动应用程序,应用程序调用其委托的 application:didFinishLaunchingWithOptions: 方法,传入 通知负载(用于远程通知)或 local-notification 对象(用于本地通知)。虽然 application:didFinishLaunchingWithOptions: 不是最好的地方 处理通知,此时获取有效负载会给你 在处理程序方法之前启动更新过程的机会 被调用。

对于远程通知,系统还会调用 应用程序:didReceiveRemoteNotification:fetchCompletionHandler: 应用委托的方法。

如果在运行 OS X 的计算机上单击应用程序图标,应用程序会调用 委托的 applicationDidFinishLaunching: 方法,其中 委托可以获取远程通知有效负载。如果应用程序图标 在运行 iOS 的设备上被点击,应用程序调用相同的方法,但 未提供有关通知的任何信息。

如您所见,当应用程序从终止状态或未停靠状态启动时,只会检查被点击的通知。

还有一点很重要:

服务质量

Apple 推送通知服务包含默认的服务质量 (QoS) 执行存储和转发功能的组件。如果 APN 尝试发送通知但设备处于离线状态,则 通知会存储一段有限的时间,并传递给 设备可用时。只有一个最近的通知 存储特定的应用程序。如果同时发送多个通知 设备处于离线状态,新的通知会导致先前的 被丢弃的通知。这种只保留最新的行为 通知称为合并通知。

如果设备长时间处于离线状态,任何通知 被丢弃了。

因此,长话短说,推送通知的交付和存在是非常可预期的,但不能保证。此外,设备上的推送通知路径不能以编程方式控制 - 作为应用程序,您在设备上订阅了 APNS 守护程序,并且您在推送通知方面依赖它。

这就是为什么,如果您的应用程序有一些业务逻辑(在您的情况下,计数器更新),您不应该依赖推送通知。您应该使用更可靠/可控的机制在您的应用程序和后端之间同步数据。通过使用 REST 并在我的应用程序的问题域中指定 Notification 实体,我已经多次实现了这个目标 - 用户可以通过 REST API 获取通知、将其标记为已读/未读、删除它们等。

【讨论】:

感谢您的解释。说得通。似乎 Facebook 等应用程序为此目的使用了私有 api。我喜欢您为处理通知创建单独实体的方法。使功能更加清晰。 我相信,facebook 和 linkedin 不为此使用私有 API - AFAIK,它们为每个选项卡都有单独的计数器(当涉及 facebook 时,信使、通知、朋友请求和在linkedin 几乎相同) .我认为,他们使用 REST 或一些 websocket 机制来获取更新和某种缓存。如果您在 Facebook 应用程序开始的早期就有徽章计数 - 它们 99.99% 是从缓存中获取的,然后在网络连接时从网络更新 您能否详细说明您的最后一句话:“通过使用 REST 并在我的应用程序的问题域中专用通知实体,我已经多次实现了这个目标 - 用户可以获取通知,将它们标记为已读/未读,通过 REST API 删除它们等"【参考方案2】:

您可以通过为推送通知使用后台获取模式来解决此问题。将您的特殊徽章编号存储到某种持久存储(可能是用户默认值)中,并在您打开应用程序时使用该值。

对于后台提取,请查看以下问题: Will iOS launch my app into the background if it was force-quit by the user?

但是,请注意,用户可以选择退出后台提取。

【讨论】:

【参考方案3】:

所以基本上,总结其他人所说的话,您将有两个用户案例。但是在您需要在有效负载中指定必须增加哪个徽章之前(正如@Andrew 建议的那样)。 以下是用户案例:

    应用可以拨打didReceiveRemoteNotification。在这种情况下,这意味着应用程序处于后台、前台或通过点击通知启动。您将必须实现您的逻辑来处理这种情况。只需解析通知的有效负载(以 json 格式)并确定应该增加哪个徽章。 应用无法调用didReceiveRemoteNotification。在这种情况下,用户已经杀死了您的应用程序,或者设备已关闭,或者用户对您的应用程序具有阻止获取后台功能。要处理这种情况,您的应用程序和服务器上也需要更多逻辑。 您可以做的是在服务器端存储已发送的所有待处理通知。一旦用户设备上的应用程序收到解析通知(didReceiveRemoteNotification被调用),您将向您的服务器发出新的调用,要求从待处​​理的数据库中删除通知。最后,在你的应用程序启动时调用你的服务器,询问所有待处理的通知,这样在你的应用程序被杀死或设备关闭的情况下,当用户再次打开应用程序时,他将收到所有通知错过了。您还可以在服务器上设置一个计时器,每隔 x 天/小时再次发送一次通知(这并不是真正的建议,您不希望用户因为您向他发送垃圾邮件而删除您的应用)。

也正如其他人所说,信任您的服务器上的哪个数字应该显示在您的徽章中比通知本身要好得多。上面的逻辑用于我最近正在开发的一个类似 Tinder 的应用程序中,以显示用户有多少匹配项;)

【讨论】:

【参考方案4】:

您可以将一些参数添加到json 接收到推送通知的数据中,例如"type":1 以识别通知类型。见Examples of JSON Payloads。但是从 API 加载通知的数量比将每种类型的通知都统计到应用中要好。

【讨论】:

【参考方案5】:

只有当用户通过点击通知打开应用或应用已打开时,您才能获取通知负载信息。在这两种情况下,didReceiveRemoteNotification 都会调用。除了这些情况,您还可以在应用程序打开时调用包含通知计数信息的服务器上的服务。

【讨论】:

以上是关于当推送通知到达(未收到)设备时调用委托的主要内容,如果未能解决你的问题,请参考以下文章

如何在应用程序未运行并点击推送通知时调试远程推送通知?

如何在日志中获取推送通知收到消息

从 appery 发送时,iPhone 上未收到推送通知消息

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

当应用程序处于非运行状态时,推送通知委托触发的解决方案是啥?

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