如何实现接收推送撤回通知栏指定通知?

实现方式请参照 SealTalk 中的 ServiceExtension。

具体步骤如下:

  1. 给工程添加一个 target :Notification Service Extension。

  2. 主工程开启 Push Notifications 和 Background Modes 功能。

  3. Service Extension target 开启 Push Notifications 功能。

  4. NotificationService.m 中实现 - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler :

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {

    UNNotificationContent *content1 = request.content;
    NSDictionary *userInfo = content1.userInfo;
    NSDictionary *aps = [userInfo objectForKey:@"aps"];
    NSString *category = [aps objectForKey:@"category"];
    if (aps && category && [category isEqualToString:@"RC:RcCmd"]) {
        NSString *appData = [userInfo objectForKey:@"appData"];
        NSDictionary *appDataDic = [NSJSONSerialization JSONObjectWithData:[appData dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:nil];
        NSString *idString = [appDataDic objectForKey:@"rc-dlt-identifier"];
        if (idString) {
            [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
                if (notifications.count == 0) {
                    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                        self.contentHandler = contentHandler;
                        self.bestAttemptContent = [request.content mutableCopy];
                        self.contentHandler(self.bestAttemptContent);
                    });
                    return;
                }

                for (UNNotification *notice in notifications) {
                    UNNotificationRequest *request = notice.request;
                    UNNotificationContent *content = request.content;
                    NSDictionary *userInfo1 = content.userInfo;
                    NSString *identifier = userInfo1[@"rc"][@"id"];
                    if ([idString isEqualToString:identifier]) {
                        [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:@[request.identifier]];
                    }
                }
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    self.contentHandler = contentHandler;
                    self.bestAttemptContent = [request.content mutableCopy];
                    self.contentHandler(self.bestAttemptContent);

                });

            }];
        }
    } else {
        self.contentHandler = contentHandler;
        self.bestAttemptContent = [request.content mutableCopy];
        self.contentHandler(self.bestAttemptContent);
    }
}

撤回消息的推送内容示例:

{
    appData = "{\"rc-dlt-identifier\":\"B7EE-8T9S-OI44-8NSS\"}";
    aps =     {
        alert =         {
            body = "\U4f60\U6536\U5230\U4e86\U4e00\U6761\U6d88\U606f";
        };
        badge = 2;
        category = "RC:RcCmd";
        "mutable-content" = 1;
        sound = "aaaaaa.caf";
    };
    rc =     {
        cType = PR;
        fId = 1xTlsmAn9;
        id = "B7EE-918C-GI64-8NSS";
        oName = "RC:RcCmd";
        sourceType = 0;
        tId = 1xTlsmAn9;
    };
    richMediaUri = "";
}

其中通过 aps 中的 category 判断是不是撤回消息,如果是撤回消息,appData 中的 rc-dlt-identifier 表示要撤回消息的 id

注:

  1. 只有公有云支持该功能;

  2. 该功能只在 iOS 10 以上有效。