Supprimer une notification locale particulière

92

Je développe une application d'alarme iPhone basée sur des notifications locales.

Lors de la suppression d'une alarme, la notification locale associée devrait être annulée. Mais comment puis-je déterminer exactement quel objet du tableau de notifications locales doit être annulé?

Je connais la [[UIApplication sharedApplication] cancelLocalNotification:notification]méthode mais comment puis-je obtenir cette «notification» pour l'annuler?

Yogi
la source

Réponses:

218

Vous pouvez enregistrer une valeur unique pour la clé dans les informations utilisateur de votre notification locale. Obtenez toutes les notifications locales, parcourez le tableau et supprimez la notification particulière.

Code comme suit,

OBJ-C:

UIApplication *app = [UIApplication sharedApplication];
NSArray *eventArray = [app scheduledLocalNotifications];
for (int i=0; i<[eventArray count]; i++)
{
    UILocalNotification* oneEvent = [eventArray objectAtIndex:i];
    NSDictionary *userInfoCurrent = oneEvent.userInfo;
    NSString *uid=[NSString stringWithFormat:@"%@",[userInfoCurrent valueForKey:@"uid"]];
    if ([uid isEqualToString:uidtodelete])
    {
        //Cancelling local notification
        [app cancelLocalNotification:oneEvent];
        break;
    }
}

RAPIDE:

var app:UIApplication = UIApplication.sharedApplication()
for oneEvent in app.scheduledLocalNotifications {
    var notification = oneEvent as UILocalNotification
    let userInfoCurrent = notification.userInfo! as [String:AnyObject]
    let uid = userInfoCurrent["uid"]! as String
    if uid == uidtodelete {
        //Cancelling local notification
        app.cancelLocalNotification(notification)
        break;
    }
}

Notification de l'utilisateur:

Si vous utilisez UserNotification (iOS 10+), suivez simplement ces étapes:

  1. Lors de la création du contenu UserNotification, ajoutez un identifiant unique

  2. Supprimer une notification spécifique en attente à l'aide de removePendingNotificationRequests (withIdentifiers :)

  3. Supprimez la notification livrée spécifique à l'aide de removeDeliveredNotifications (withIdentifiers :)

Pour plus d'informations, UNUserNotificationCenter

KingofBliss
la source
@ kingofBliss, pouvez-vous s'il vous plaît me dire de donner là-bas à "uidtodelete" .parce que ce n'est pas déclaré dans mon cas.
ishhhh
@ishhh c'est juste une valeur strig .. vous devez le déclarer et l'initialiser avec une valeur de l'uid à supprimer
KingofBliss
@ kingofBliss, l'uid affiche toujours null dans NSLog.dont vous savez comment vous en débarrasser.Veuillez m'aider
ishhhh
@ishhh avez-vous stocké une valeur pour uid dans le dictionnaire userinfo lors de la création d'une notification locale? Je pense que vous avez raté cela.
KingofBliss
@kingofBliss, le "uid" est un nom de votre propre variable, vous pouvez utiliser n'importe quel nom significatif comme "notificationID", et le stocker dans un NSDictionaryavec la valeur de l'id de l'entité liée au UILocalNotification. Définissez ensuite la propriété notification.userInfo sur le dictionnaire avec vos données personnalisées. Désormais, lorsque vous recevez les notifications, vous pouvez les distinguer avec cet identifiant personnalisé ou tout ce dont vous avez besoin.
IgniteCoders
23

Autre option:

Tout d'abord, lorsque vous créez une notification locale, vous pouvez la stocker dans les valeurs par défaut de l'utilisateur pour une utilisation future, l'objet de notification local ne peut pas être stocké directement dans les valeurs par défaut de l'utilisateur, cet objet doit d'abord être converti en objet NSData, puis NSDatapeut être stocké dans User defaults. Voici le code pour cela:

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:localNotif];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:[NSString  stringWithFormat:@"%d",indexPath.row]];

Après avoir stocké et planifié la notification locale, à l'avenir, il se peut que vous deviez annuler toute notification que vous avez créée précédemment, afin que vous puissiez la récupérer à partir des paramètres par défaut de l'utilisateur.

NSData *data= [[NSUserDefaults standardUserDefaults] objectForKey:[NSString   stringWithFormat:@"%d",UniqueKey]];

UILocalNotification *localNotif = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(@"Remove localnotification  are %@", localNotif);
[[UIApplication sharedApplication] cancelLocalNotification:localNotif];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:[NSString stringWithFormat:@"%d",UniqueKey]];

J'espère que cela t'aides

iMOBDEV
la source
Merci, je l'ai implémenté de la première manière mais votre réponse est également correcte.Je vais prendre cela en considération.Pouvez-vous s'il vous plaît dire lequel est le plus efficace? Merci pour l'aide :)
Yogi
1
@Yogi: Si vous regardez la première réponse, vous devez exécuter la boucle for à chaque fois si vous souhaitez annuler la notification locale, mais dans la réponse ci-dessus, vous n'aurez pas besoin d'exécuter une boucle for, vous pouvez accéder directement à la notification locale et l'annuler notification locale et supprimez
paramètres
@JigneshBrahmkhatri Votre méthode est efficace. Mais cela échouera lorsque l'utilisateur désinstallera l'application et la réinstallera.
KingofBliss
@KingofBliss, dans ce cas, nous devons annuler toutes les notifications, non? Donc je suppose que cette solution est plus rapide. :)
Sufian
@Sufian Pour annuler toutes les notifications, il existe un moyen beaucoup plus rapide [[UIApplication sharedApplication] cancelAllLocalNotifications]; ;)
KingofBliss
8

Voici ce que je fais.

Lors de la création de votre notification, procédez comme suit:

  // Create the notification

UILocalNotification *notification = [[UILocalNotification alloc]  init] ;



notification.fireDate = alertDate;
notification.timeZone = [NSTimeZone localTimeZone] ;
notification.alertAction = NSLocalizedString(@"Start", @"Start");
notification.alertBody = **notificationTitle**;
notification.repeatInterval= NSMinuteCalendarUnit;

notification.soundName=UILocalNotificationDefaultSoundName;
notification.applicationIconBadgeNumber = 1;

[[UIApplication sharedApplication] scheduleLocalNotification:notification] ;

lorsque vous essayez de le supprimer, procédez comme suit:

 NSArray *arrayOfLocalNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications] ;

for (UILocalNotification *localNotification in arrayOfLocalNotifications) {

    if ([localNotification.alertBody isEqualToString:savedTitle]) {
        NSLog(@"the notification this is canceld is %@", localNotification.alertBody);

        [[UIApplication sharedApplication] cancelLocalNotification:localNotification] ; // delete the notification from the system

    }

}

Cette solution devrait fonctionner pour plusieurs notifications, et vous ne gérez pas de tableaux, de dictionnaires ou de paramètres par défaut de l'utilisateur. Vous utilisez simplement les données que vous avez déjà enregistrées dans la base de données de notification des systèmes.

J'espère que cela aidera les futurs concepteurs et développeurs.

Heureux les gars de codage! :RÉ

abhi
la source
Merci de partager votre réponse mais comment cette logique fonctionne si toutes vos notifications ont le même corps ou si le corps doit être pris à l'utilisateur.Dans ce cas, l'utilisateur peut donner le même corps à plusieurs notifications.
Yogi
@Yogi, comme alertbody, vous pouvez vérifier, notification.firedate pour obtenir la notification requise. merci à abhi pour une solution simple.voter 1 pour vous
Azik Abdullah
1
@NAZIK: Merci de l'intérêt que vous portez à la discussion. Mais l'utilisateur peut toujours programmer deux notifications à la même date d'incendie car il s'agit d'une application d'alarme. Au moins, cela peut être un cas de test pour un testeur et cette solution semble y échouer.
Yogi
@ Yogi, sage tests, pourquoi ne pouvons-nous pas vérifier si ([localNotification.alertBody isEqualToString: savedTitle] || [localNotification.firedate == quelque chose]), puisque les deux notifications avec la même date devraient contenir des alertBody différents
Azik Abdullah
N'abusez pas du alertBodyou fireDatepour identifier une notification; utilisez le userInfochamp pour ce faire, comme la réponse de @KingOfBliss détaille ...
severin
8

Planification et suppression de la notification dans Swift:

    static func scheduleNotification(notificationTitle:String, objectId:String) {

    var localNotification = UILocalNotification()
    localNotification.fireDate = NSDate(timeIntervalSinceNow: 24*60*60)
    localNotification.alertBody = notificationTitle
    localNotification.timeZone = NSTimeZone.defaultTimeZone()
    localNotification.applicationIconBadgeNumber = 1
    //play a sound
    localNotification.soundName = UILocalNotificationDefaultSoundName;
    localNotification.alertAction = "View"
    var infoDict :  Dictionary<String,String!> = ["objectId" : objectId]
    localNotification.userInfo = infoDict;

    UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
}
    static func removeNotification(objectId:String) {
    var app:UIApplication = UIApplication.sharedApplication()

    for event in app.scheduledLocalNotifications {
        var notification = event as! UILocalNotification
        var userInfo:Dictionary<String,String!> = notification.userInfo as! Dictionary<String,String!>
        var infoDict :  Dictionary = notification.userInfo as! Dictionary<String,String!>
        var notifcationObjectId : String = infoDict["objectId"]!

        if notifcationObjectId == objectId {
            app.cancelLocalNotification(notification)
        }
    }



}
Roman Barzyczak
la source
1
N'abusez pas du alertBodyou fireDatepour identifier une notification; utilisez le userInfochamp pour ce faire, comme la réponse de @KingOfBliss détaille ...
severin
Oui, alertBody n'est pas une bonne option pour identifier une notification. Je l'ai changé en userInfo
Roman Barzyczak
6

La solution iMOBDEV fonctionne parfaitement pour supprimer une notification spécifique (par exemple après la suppression de l'alarme) mais elle est particulièrement utile lorsque vous devez supprimer sélectivement toute notification qui a déjà été déclenchée et est toujours sur le centre de notification.

Un scénario possible serait: la notification d'une alarme se déclenche, mais l'utilisateur ouvre l'application sans appuyer sur cette notification et planifie à nouveau cette alarme. Si vous voulez vous assurer qu'une seule notification peut être sur le centre de notification pour un élément / alarme donné, c'est une bonne approche. Cela vous permet également de ne pas avoir à effacer toutes les notifications à chaque fois que l'application est ouverte, si cela convient mieux à l'application.

  • Lors de la création d'une notification locale, utilisez NSKeyedArchiverpour la stocker comme Datadans UserDefaults. Vous pouvez créer une clé égale à ce que vous enregistrez dans le dictionnaire userInfo de la notification. S'il est associé à un objet Core Data, vous pouvez utiliser sa propriété objectID unique.
  • Récupérez-le avec NSKeyedUnarchiver. Vous pouvez maintenant le supprimer à l'aide de la méthode cancelLocalNotification.
  • Mettez à jour la clé en UserDefaultsconséquence.

Voici une version Swift 3.1 de cette solution (pour les cibles inférieures à iOS 10):

Boutique

// localNotification is the UILocalNotification you've just set up
UIApplication.shared.scheduleLocalNotification(localNotification)
let notificationData = NSKeyedArchiver.archivedData(withRootObject: localNotification)
UserDefaults.standard.set(notificationData, forKey: "someKeyChosenByYou")

Récupérer et supprimer

let userDefaults = UserDefaults.standard
if let existingNotificationData = userDefaults.object(forKey: "someKeyChosenByYou") as? Data,
    let existingNotification = NSKeyedUnarchiver.unarchiveObject(with: existingNotificationData) as? UILocalNotification {

    // Cancel notification if scheduled, delete it from notification center if already delivered    
    UIApplication.shared.cancelLocalNotification(existingNotification)

    // Clean up
    userDefaults.removeObject(forKey: "someKeyChosenByYou")
}
Rygen
la source
A travaillé pour moi. Toutes les autres suggestions non, car le tableau est vide.
Maksim Kniazev
Une idée pour iOS 10?
Danpe
1
@Danpe: jetez un œil à la section «Gestion des notifications livrées» ici: developer.apple.com/reference/usernotifications/…
Rygen
a travaillé pour moi avec swift 3 avec des mods mineurs, que Xcode a gérés.
beshio
@beshio: merci pour la mise en garde. J'ai mis à jour sa syntaxe.
Rygen
4

Version Swift, si besoin:

func cancelLocalNotification(UNIQUE_ID: String){

        var notifyCancel = UILocalNotification()
        var notifyArray = UIApplication.sharedApplication().scheduledLocalNotifications

        for notifyCancel in notifyArray as! [UILocalNotification]{

            let info: [String: String] = notifyCancel.userInfo as! [String: String]

            if info[uniqueId] == uniqueId{

                UIApplication.sharedApplication().cancelLocalNotification(notifyCancel)
            }else{

                println("No Local Notification Found!")
            }
        }
    }
Sohil R. Memon
la source
4

Solution Swift 4:

UNUserNotificationCenter.current().getPendingNotificationRequests { (requests) in
  for request in requests {
    if request.identifier == "identifier" {
      UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: ["identifier"])
    }
  }
}   
Nupur Sharma
la source
2

Vous pouvez conserver une chaîne avec l'identificateur de catégorie lors de la planification de la notification comme ceci

        localNotification.category = NotificationHelper.categoryIdentifier

et recherchez-le et annulez en cas de besoin comme tel

let  app = UIApplication.sharedApplication()

    for notification in app.scheduledLocalNotifications! {
        if let cat = notification.category{
            if cat==NotificationHelper.categoryIdentifier {
                app.cancelLocalNotification(notification)
                break
            }

        }
    }
pantos27
la source
1

L'objet UILocalNotification auquel vous passez cancelLocalNotification:correspondra à tout objet UILocalNotification existant avec des propriétés correspondantes.

Alors:

UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = @"foo";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];

présentera une notification locale qui pourra être annulée ultérieurement avec:

UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = @"foo";
[[UIApplication sharedApplication] cancelLocalNotification:notification];
jhibberd
la source
1
Merci. Je pense que vous créez une nouvelle notification et que vous l'annulez. Cela n'aura aucun effet sur ma notification précédemment programmée et il sera toujours déclenché.
Yogi
Existe-t-il une propriété qui peut correspondre à une propriété à l'exception de alertBody?
Shamsiddin
1

J'utilise cette fonction dans Swift 2.0:

  static func DeleteNotificationByUUID(uidToDelete: String) -> Bool {
    let app:UIApplication = UIApplication.sharedApplication()
    // loop on all the current schedualed notifications
    for schedualedNotif in app.scheduledLocalNotifications! {
      let notification = schedualedNotif as UILocalNotification
      let urrentUi = notification.userInfo! as! [String:AnyObject]
      let currentUid = urrentUi["uid"]! as! String
      if currentUid == uidToDelete {
        app.cancelLocalNotification(notification)
        return true
      }
    }
    return false
  }

Inspiré de la réponse de @ KingofBliss

MBH
la source
1

style 3 rapide:

final private func cancelLocalNotificationsIfIOS9(){


//UIApplication.shared.cancelAllLocalNotifications()
let app = UIApplication.shared
guard let notifs = app.scheduledLocalNotifications else{
    return
}

for oneEvent in notifs {
    let notification = oneEvent as UILocalNotification
    if let userInfoCurrent = notification.userInfo as? [String:AnyObject], let uid = userInfoCurrent["uid"] as? String{
        if uid == uidtodelete {
            //Cancelling local notification
            app.cancelLocalNotification(notification)
            break;
        }
    }
}

}

pour l'utilisation d'iOS 10:

    let center = UNUserNotificationCenter.current()
    center.removePendingNotificationRequests(withIdentifiers: [uidtodelete])
ingconti
la source
0

Pour les rappels répétés (par exemple, vous voulez que votre alarme se déclenche le dimanche, samedi et mercredi à 16 heures, puis vous devez faire 3 alarmes et régler repeatInterval sur NSWeekCalendarUnit).

Pour faire un rappel unique:

UILocalNotification *aNotification = [[UILocalNotification alloc] init];
                aNotification.timeZone = [NSTimeZone defaultTimeZone];
                aNotification.alertBody = _reminderTitle.text;
                aNotification.alertAction = @"Show me!";
                aNotification.soundName = UILocalNotificationDefaultSoundName;
                aNotification.applicationIconBadgeNumber += 1;

                NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
                NSDateComponents *componentsForFireDate = [calendar components:(NSYearCalendarUnit | NSWeekCalendarUnit|  NSHourCalendarUnit | NSMinuteCalendarUnit| NSSecondCalendarUnit | NSWeekdayCalendarUnit) fromDate: _reminderDate];

                [componentsForFireDate setHour: [componentsForFireDate hour]] ; //for fixing 8PM hour
                [componentsForFireDate setMinute:[componentsForFireDate minute]];

                [componentsForFireDate setSecond:0] ;
                NSDate *fireDateOfNotification = [calendar dateFromComponents: componentsForFireDate];
                aNotification.fireDate = fireDateOfNotification;
                NSDictionary *infoDict = [NSDictionary dictionaryWithObject:_reminderTitle.text forKey:kRemindMeNotificationDataKey];
                aNotification.userInfo = infoDict;

                [[UIApplication sharedApplication] scheduleLocalNotification:aNotification];

Pour faire un rappel répété:

for (int i = 0 ; i <reminderDaysArr.count; i++)
                {

                    UILocalNotification *aNotification = [[UILocalNotification alloc] init];
                    aNotification.timeZone = [NSTimeZone defaultTimeZone];
                    aNotification.alertBody = _reminderTitle.text;
                    aNotification.alertAction = @"Show me!";
                    aNotification.soundName = UILocalNotificationDefaultSoundName;
                    aNotification.applicationIconBadgeNumber += 1;

                    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
                    NSDateComponents *componentsForFireDate = [calendar components:(NSYearCalendarUnit | NSWeekCalendarUnit|  NSHourCalendarUnit | NSMinuteCalendarUnit| NSSecondCalendarUnit | NSWeekdayCalendarUnit) fromDate: _reminderDate];


                    [componentsForFireDate setWeekday: [[reminderDaysArr objectAtIndex:i]integerValue]];

                    [componentsForFireDate setHour: [componentsForFireDate hour]] ; // Setup Your Own Time.
                    [componentsForFireDate setMinute:[componentsForFireDate minute]];

                    [componentsForFireDate setSecond:0] ;
                    NSDate *fireDateOfNotification = [calendar dateFromComponents: componentsForFireDate];
                    aNotification.fireDate = fireDateOfNotification;
                    aNotification.repeatInterval = NSWeekCalendarUnit;
                    NSDictionary *infoDict = [NSDictionary dictionaryWithObject:_reminderTitle.text forKey:kRemindMeNotificationDataKey];
                    aNotification.userInfo = infoDict;

                    [[UIApplication sharedApplication] scheduleLocalNotification:aNotification];
                }
            }

Pour le filtrage, vous disposez d'un tableau pour l'afficher.

-(void)filterNotficationsArray:(NSMutableArray*) notificationArray{

    _dataArray = [[NSMutableArray alloc]initWithArray:[[UIApplication sharedApplication] scheduledLocalNotifications]];
    NSMutableArray *uniqueArray = [NSMutableArray array];
    NSMutableSet *names = [NSMutableSet set];

    for (int i = 0 ; i<_dataArray.count; i++) {
        UILocalNotification *localNotification = [_dataArray objectAtIndex:i];
        NSString * infoDict = [localNotification.userInfo objectForKey:@"kRemindMeNotificationDataKey"];

        if (![names containsObject:infoDict]) {
            [uniqueArray addObject:localNotification];
            [names addObject:infoDict];
        }
    }
    _dataArray = uniqueArray;
}

Pour supprimer le rappel même s'il était une fois seulement ou répété:

- (void) removereminder:(UILocalNotification*)notification
{
    _dataArray = [[NSMutableArray alloc]initWithArray:[[UIApplication sharedApplication]scheduledLocalNotifications]];

    NSString * idToDelete = [notification.userInfo objectForKey:@"kRemindMeNotificationDataKey"];
    for (int i = 0 ; i<_dataArray.count; i++)
    {
        UILocalNotification *currentLocalNotification = [_dataArray objectAtIndex:i];
        NSString * notificationId = [currentLocalNotification.userInfo objectForKey:@"kRemindMeNotificationDataKey"];

        if ([notificationId isEqualToString:idToDelete])
            [[UIApplication sharedApplication]cancelLocalNotification:currentLocalNotification];
    }

    _dataArray = [[NSMutableArray alloc]initWithArray:[[UIApplication sharedApplication]scheduledLocalNotifications]];
    [self filterNotficationsArray:_dataArray];
    [_remindersTV reloadData];

}
Abo3atef
la source
0

J'ai développé un peu la réponse de KingofBliss, j'ai écrit ceci un peu plus à la manière de Swift2, supprimé du code inutile et ajouté des protections contre les accidents.

Pour commencer, lors de la création de la notification, vous devez vous assurer de définir l'uid (ou toute propriété personnalisée en fait) de la notification userInfo:

notification.userInfo = ["uid": uniqueid]

Ensuite, lors de sa suppression, vous pouvez faire:

guard
    let app: UIApplication = UIApplication.sharedApplication(),
    let notifications = app.scheduledLocalNotifications else { return }
for notification in notifications {
    if
        let userInfo = notification.userInfo,
        let uid: String = userInfo["uid"] as? String where uid == uidtodelete {
            app.cancelLocalNotification(notification)
            print("Deleted local notification for '\(uidtodelete)'")
    }
}
brandonscript
la source
1
Pour plus de sécurité, vous pouvez utiliser le guard-statement guard let app = UIApplication.sharedApplication () else {return false} pour schedualedNotif dans app.scheduledLocalNotifications {...} Ensuite, vous n'avez pas besoin de forcer le déballage dans la boucle for
troligtvis