如何清除 iOS 的远程推送通知?
Posted
技术标签:
【中文标题】如何清除 iOS 的远程推送通知?【英文标题】:How to clear a remote pushed notification for iOS? 【发布时间】:2017-10-11 13:23:58 【问题描述】:所以我一直在阅读远程通知,并终于让它工作了;我们的应用程序正在从我们的服务器接收通知。如果我们的服务器上满足特定条件(例如通知不再有效),我们现在想要删除或更新未读通知。我知道“无声”通知是唯一的方法,但我仍然对如何做感到困惑。 如果静默通知触发我的应用唤醒,我可以安排本地通知,但我可以删除已经存在的远程通知吗?
唯一的解决方案是专门使用来自服务器的静默通知,并将所有通知安排为带有自定义标识符的本地通知,我以后可以将其删除? 例如,如果我想要这个功能,我可以永远不要使用从我的服务器到设备的 fire&forget 远程推送通知吗?
编辑:此应用支持低至 iOS 9:/
【问题讨论】:
【参考方案1】:我最终按照his answer 中建议的 TawaNicolas 进行操作,通过使用getDeliveredNoti....
获取收到的通知,然后检查每个通知的 userInfo 以找到我想要删除的通知。我将可移动通知的标识符存储在一个数组中,并调用removeDelivered...
。
这正是他的回答所暗示的,但一开始并没有奏效,我很难找出原因。我仍然不能完全确定我是否已修复它,但我的测试表明它正在工作 - 我的解决方案有点道理。
问题是,在didReceiveRemote..
函数中,你必须在最后调用completionHandler(.newData)
。这是为了通知 NotificationCenter 发生了一些变化。我开始怀疑这个回调是在 可移动通知实际被删除之前调用的。我检查了文档,removeDeliveredNotifications
确实是异步的。这意味着当我这样做时:
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: removableIDs)
completionHandler(.newData)
不保证第一个函数在调用第二个函数之前完成。这意味着 completionHandler
告诉我的 NotificationCenter 某些内容已经更新,首先完成,然后通知从系统中删除。 (NotificationCenter 显然不会在该函数之后调用自己的 completionHandler 来更新 UI)。
所有这些可能会或可能不会发生。正如我所经历的那样;当连接到调试器时,removeDeliveredNotifications
函数非常快,以至于它总是在调用completionHandler
之前完成,这意味着在更新系统之前通知已被删除。所以在开发这个时一切看起来都很棒。当我与调试器断开连接时,removeDeliveredNotifications
-函数稍微慢了一点,并且由于它是异步的,它在我调用 completionHandler
之后完成 - 导致系统更新得太快。 p>
解决此问题的最佳方法是 Apple 为 removeDeliveredNotifications
提供一个 completionBlock,并在其中调用我们的 completionHandler
,但他们没有。
为了解决这个问题,我现在添加了 0.2 秒的固定延迟。它可能低于 0.2,但对于我们正在做的事情来说,它并不重要。
这是我创建的一个类和函数,可以轻松地从任何地方延迟某些东西:
class RuntimeUtils
class func delay(seconds delay:Double, closure:@escaping ()->())
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(delay*Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure)
这里我在didReceiveRemoteNotification:
AppDelegate
中使用它:
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: removableIDs)
RuntimeUtils.delay(seconds: 0.2, closure:
completionHandler(.newData)
)
将这个延迟添加到completionHandler后,它总是在我删除通知后执行,并且似乎每次都有效,无论是否连接了调试器。
这是一个令人作呕的问题,而且修复得很糟糕。
【讨论】:
感谢您的详细回答,我刚刚在我们的应用程序中实现了相同的功能,并将报告您的延迟修复是否也需要在 prd 中进行。如果没有调试器,它在本地开发设置中仍然可以正常工作,但让我们看看。 @mitschmidt 这是 4 年前的事了。你真的还需要支持 ios 9 吗?如果没有,还有其他解决方案。 确实它在没有解决方法的情况下工作,到目前为止可靠。仍然感谢您的文档和努力。【参考方案2】:在您的应用从静默通知中唤醒后,您需要使用以下命令循环接收到的通知:
目标-C:
[[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications)
];
斯威夫特:
UNUserNotificationCenter.current().getDeliveredNotifications (notifications: [UNNotification]) in
然后检查每个通知的request.content.userInfo
属性,以确定是否是您要删除的通知。
然后,您使用以下命令将其从通知中心删除:
目标-C:
[[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:@[identifier]];
斯威夫特:
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [identifier])
其中identifier
是notification.request.identifier
属性。
编辑:如果您想识别正确的通知,您必须找出您在userInfo
中可以识别正确通知的有效负载中发送的内容。 (可能是用户 ID 或事件 ID?这取决于您的项目。)
【讨论】:
好提示!每个通知都将包含一个自定义 ID 字段,以识别应该删除哪些。但是,这个应用程序必须支持到 iOS 9,据我所知,我不能使用UNUserNotificationCenter
:( 但一个很好的答案!
@Sti 谢谢你,老实说,你必须在这方面支持 iOS 9,这很糟糕。因为我认为在 iOS 10 之前这是不可能的。但无论如何,您可以使用 iOS 10 及更高版本使您的应用程序支持此功能,但对于 iOS 9,它应该具有默认行为,这意味着应用程序会清除所有通知当它进入前台时。
Followup-question.. 应用程序的哪一部分从无声通知中“唤醒”?我不明白我应该把他的代码放在哪里..
@Sti 我不确定,但我认为这是处理它的方法:developer.apple.com/documentation/uikit/uiapplicationdelegate/…
嘿,我最终为 iOS 10+ 执行此操作,但我遇到了一些奇怪的事情。当我连接到调试器时,一切正常,但在 AdHoc/TestFlight 中安装此应用程序时/AppStore 似乎我的“背景”工作根本没有发生。我只是在实现didReceiveRemoteNotification...
并使用getDeliveredNotifications
,找到与我的相关用户信息值匹配的任何通知,并使用其他ID 调用removeDeliveredNotifications
,而不是最后一个。这在连接到调试器时工作得很好,但在测试版本时似乎有 10% 的时间工作【参考方案3】:
对于 iOS >= 10,您可以使用 UNUserNotificationCenter.current().getDeliveredNotifications
和/或 UNUserNotificationCenter.current().removeAllDeliveredNotifications
您还必须添加import UserNotifications
,这是一个不错的新通知框架。
【讨论】:
天哪,看起来不错,但我们的应用必须支持到 iOS 9 :(以上是关于如何清除 iOS 的远程推送通知?的主要内容,如果未能解决你的问题,请参考以下文章