且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何清除iOS的远程推送通知?

更新时间:2023-02-26 21:13:33

我最终做到了,就像TawaNicolas在他的答案中建议的那样. a>,通过使用getDeliveredNoti....获取收到的通知,然后检查每个通知的userInfo来查找我要删除的通知.我将可移动通知的标识符存储在数组中,并称为removeDelivered....

这正是他的答案所暗示的,但是起初并没有奏效,我很难找出原因.我仍然不能完全确定是否已修复它,但是我的测试表明它可以正常工作-我的解决方案在一定程度上是合理的.

问题是,在didReceiveRemote..函数内部,您必须最后调用completionHandler(.newData).这是为了通知NotificationCenter发生了某些更改.我开始怀疑此回调被称为 before ,可移动通知实际上已被删除.我检查了文档,并且removeDeliveredNotifications确实是异步的.这意味着当我这样做时:

UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: removableIDs)
completionHandler(.newData)

不能保证在调用第二个函数之前先完成第一个函数.这意味着completionHandler(它告诉我的NotificationCenter某些内容已更新)首先完成,然后将通知从系统中删除. (NotificationCenter显然不调用该函数之后的UI来更新其UI).

所有这可能发生.正如我所经历的;当连接到调试器时,removeDeliveredNotifications功能是如此之快,以至于它总是在调用completionHandler之前完成,这意味着在更新系统之前已删除了通知.因此,开发此工具时,一切看起来都很不错.当我断开与调试器的连接时,removeDeliveredNotifications函数会稍慢一些,并且由于它是异步的,因此在 调用completionHandler后就完成了-导致系统更新太早了.>

解决此问题的***方法是让Apple为我们提供removeDeliveredNotifications的completeBlock并在其中调用我们的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)
    }
}

在这里,我在AppDelegate中的didReceiveRemoteNotification:内部使用它:

UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: removableIDs)
RuntimeUtils.delay(seconds: 0.2, closure: {
    completionHandler(.newData)
})

将此延迟添加到completionHandler之后,它总是在删除通知后执行,并且无论是否连接调试器,它似乎每次都能工作.

这是一个令人作呕的问题,有一个令人讨厌的解决方法.

So I've been reading up on remote notifications, and have finally made it work; our app is receiving notifications from our server. We now want to remove or update an unread notification if a certain condition meets on our server (e.g the notification is no longer valid). I understand that "silent" notifications are the only way to go, but I am still confused as to how. If a silent notification triggers my app to wake up, I would be able to schedule local notifications, but will I be able to remove already existing remote notifications?

Is the only solution to exclusively use silent notifications from the server, and schedule all notifications as local notifications with a custom identifier which I can later remove? E.g, can I never use fire&forget remote push notifications from my server to devices if I want this feature?

Edit: This app supports down to iOS 9 :/

I ended up doing it like TawaNicolas suggested in his answer, by getting the received notifications with getDeliveredNoti...., then check the userInfo of every notification to find which ones I wanted to delete. I stored the removable notifications' identifiers in an array, and called removeDelivered....

This is exactly as his answer suggests, but this didn't work at first, and I had a hard time finding out why. I'm still not completely sure I have fixed it, but my tests shows that it's working - and my solution somewhat makes sense.

The thing was, inside the didReceiveRemote..-function, you have to call completionHandler(.newData) at the end. This is to notify the NotificationCenter that something has changed. I started to suspect that this callback was called before the removable notifications actually got removed. I checked the documentation, and removeDeliveredNotifications is indeed async. This means that when I do this:

UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: removableIDs)
completionHandler(.newData)

it is not guaranteed that the first function is completed before calling the second function. This means that the completionHandler, which tells my NotificationCenter that something has been updated, is completed first, and THEN the notifications gets removed from the system. (NotificationCenter apparently does not invoke its own completionHandler to update the UI after that function).

All this may or may not happen. As I was experiencing; when connected to the debugger, the removeDeliveredNotifications-function was so fast that it was always completed before the completionHandler was invoked, meaning that the notifications were removed before updating the system. So everything looked great when developing this. When I disconnected from the debugger, the removeDeliveredNotifications-function was slightly slower, and since it's async, it was completed after I invoked the completionHandler - causing the system to update too soon.

The best way to solve this would be for Apple to give us a completionBlock for removeDeliveredNotifications and call our completionHandler inside it, but they haven't.

To solve this now I have gone dirty by adding a fixed delay of 0.2 seconds. It could probably be lower than 0.2, but it isn't really important with a second from or to for what we're doing.

This is a class and function I created to easily delay something from anywhere:

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

And here I use it inside didReceiveRemoteNotification: in AppDelegate:

UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: removableIDs)
RuntimeUtils.delay(seconds: 0.2, closure: {
    completionHandler(.newData)
})

After adding this delay to the completionHandler, it is always executed after my deletion of notification, and it seems to work every time, with or without debugger connected.

This was a disgusting problem, with a nasty fix.