Elimina una particolare notifica locale


92

Sto sviluppando un'app di allarme per iPhone basata su notifiche locali.

Quando si elimina un allarme, la relativa notifica locale dovrebbe essere annullata. Ma come posso determinare esattamente quale oggetto dall'array di notifiche locali deve essere cancellato?

Sono a conoscenza del [[UIApplication sharedApplication] cancelLocalNotification:notification]metodo, ma come posso ottenere questa "notifica" per annullarla?

Risposte:


218

È possibile salvare un valore univoco per la chiave nelle informazioni utente della notifica locale. Ottieni tutte le notifiche locali, scorri l'array ed elimina la notifica specifica.

Codice come segue,

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

SWIFT:

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

Notifica utente:

Se utilizzi UserNotification (iOS 10+), segui questi passaggi:

  1. Quando si crea il contenuto UserNotification, aggiungere un identificatore univoco

  2. Rimuovi una specifica notifica in sospeso utilizzando removePendingNotificationRequests (withIdentifiers :)

  3. Rimuovi una specifica notifica consegnata utilizzando removeDeliveredNotifications (withIdentifiers :)

Per ulteriori informazioni, UNUserNotificationCenter


@ kingofBliss, puoi dirmi di dare lì a "uidtodelete" .perché nel mio caso non è dichiarato.
ishhhh

@ishhh è solo un valore strig .. dovresti dichiararlo e inizializzarlo con un valore di uid da eliminare
KingofBliss

@ kingofBliss, l'uid mostra sempre null in NSLog. non sa come sbarazzarsi di questo.Per favore aiutami
ishhhh

@ishhh hai memorizzato qualche valore per uid nel dizionario userinfo durante la creazione della notifica locale? Penso che tu l'abbia perso.
KingofBliss

@kingofBliss, "uid" è un nome della tua variabile, puoi usare qualsiasi nome significativo come "notificationID" e memorizzarlo in un NSDictionary con il valore dell'id dell'entità correlata al UILocalNotification. Quindi imposta la proprietà notification.userInfo sul dizionario con i tuoi dati personalizzati. Ora, quando ricevi le notifiche, puoi distinguerle con quell'ID personalizzato o qualsiasi altra cosa di cui hai bisogno.
IgniteCoders

23

Altra opzione:

Prima di tutto, quando crei una notifica locale, puoi memorizzarla nelle impostazioni predefinite dell'utente per un uso futuro, l'oggetto di notifica locale non può essere memorizzato direttamente nelle impostazioni predefinite dell'utente, questo oggetto deve essere prima convertito nell'oggetto NSData, quindi NSDatapuò essere archiviato in User defaults. Di seguito è riportato il codice per questo:

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

Dopo aver memorizzato e pianificato la notifica locale, in futuro potrebbe sorgere la necessità di annullare qualsiasi notifica creata in precedenza, in modo da poterla recuperare dalle impostazioni predefinite dell'utente.

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]];

Spero che questo ti aiuti


Grazie, l'ho implementato in primo luogo ma anche la tua risposta è corretta Prenderò in considerazione questo.Per favore, puoi dire quale è più efficiente? Grazie per l'aiuto :)
Yogi

1
@Yogi: Se guardi la prima risposta, devi eseguire il ciclo ogni volta se vuoi annullare la notifica locale, ma nella risposta sopra, non dovrai eseguire alcun ciclo for, puoi accedere direttamente alla notifica locale e annullarla notifica locale e rimuoverlo dalle impostazioni predefinite dell'utente, come da mia risposta, è un modo più efficiente
iMOBDEV

@JigneshBrahmkhatri Il tuo metodo è efficace. Ma fallirà quando l'utente disinstalla l'app e la reinstalla.
KingofBliss

@KingofBliss, in tal caso dobbiamo annullare tutte le notifiche, giusto? Quindi immagino che questa soluzione sia più veloce. :)
Sufian

@Sufian Per annullare tutte le notifiche c'è un modo molto più veloce [[UIApplication sharedApplication] cancelAllLocalNotifications]; ;)
KingofBliss

8

Ecco cosa faccio.

Quando crei la tua notifica, procedi come segue:

  // 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] ;

quando si tenta di eliminarlo, fare questo:

 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

    }

}

Questa soluzione dovrebbe funzionare per più notifiche e non gestisci array, dizionari o impostazioni predefinite dell'utente. Stai semplicemente utilizzando i dati che hai già salvato nel database delle notifiche di sistema.

Spero che questo aiuti i futuri designer e sviluppatori.

Felici ragazzi di programmazione! : D


Grazie per aver condiviso la tua risposta ma come funziona questa logica se tutte le tue notifiche hanno lo stesso corpo o se il corpo deve essere preso dall'utente.In tal caso l'utente può dare lo stesso corpo a più notifiche.
Yogi

@Yogi, come alertbody, puoi controllare, notification.firedate per ottenere la notifica richiesta. grazie ad abhi per una soluzione semplice
voto

1
@NAZIK: Grazie per il tuo interesse nella discussione. Tuttavia, l'utente può programmare due notifiche nella stessa data dell'incendio poiché si tratta di un'applicazione di allarme. Almeno può essere un banco di prova per un tester e questa soluzione sembra fallire lì.
Yogi

@ Yogi, saggio test, perché non possiamo controllare se ([localNotification.alertBody isEqualToString: savedTitle] || [localNotification.firedate == something]), poiché le due notifiche con la stessa data dovrebbero contenere un alertBody diverso
Azik Abdullah

Non abusare del alertBodyo fireDateper identificare una notifica; usa il userInfocampo per farlo, come risposta dei dettagli di @KingOfBliss ...
severin

8

Scheduling and removeNotification in 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)
        }
    }



}

1
Non abusare del alertBodyo fireDateper identificare una notifica; usa il userInfocampo per farlo, come risposta dai dettagli di @KingOfBliss ...
severin

Sì, avviso Il corpo non è una buona opzione per identificare una notifica. L'ho cambiato in userInfo
Roman Barzyczak

6

La soluzione di iMOBDEV funziona perfettamente per rimuovere una notifica specifica (ad esempio dopo aver eliminato l'allarme) ma è particolarmente utile quando è necessario rimuovere selettivamente qualsiasi notifica che è già stata attivata e si trova ancora nel centro notifiche.

Un possibile scenario potrebbe essere: la notifica per un allarme si attiva, ma l'utente apre l'app senza toccare quella notifica e pianifica di nuovo quell'allarme. Se vuoi assicurarti che solo una notifica possa essere nel centro notifiche per un dato elemento / allarme, è un buon approccio. Ti consente inoltre di non dover cancellare tutte le notifiche ogni volta che l'app viene aperta, perché l'app si adatta meglio.

  • Dopo aver creato una notifica locale, utilizzare NSKeyedArchiverper archiviarla come DatainUserDefaults . Puoi creare una chiave uguale a quanto stai salvando nel dizionario userInfo della notifica. Se è associato a un oggetto Core Data, è possibile utilizzare la sua proprietà objectID univoca.
  • Recuperalo con NSKeyedUnarchiver . Ora puoi eliminarlo utilizzando il metodo cancelLocalNotification.
  • Aggiorna la chiave di UserDefaultsconseguenza.

Ecco una versione Swift 3.1 di quella soluzione (per target inferiori a iOS 10):

Negozio

// 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")

Recupera ed elimina

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

Ha funzionato per me. Tutti gli altri suggerimenti no, perché l'array è vuoto.
Maksim Kniazev

Qualche idea per iOS 10?
Danpe

1
@Danpe: dai un'occhiata alla sezione "Gestione delle notifiche consegnate" qui: developer.apple.com/reference/usernotifications/…
Rygen

ha funzionato per me con swift 3 con mod minori, che Xcode ha gestito.
beshio

@beshio: grazie per l'avvertimento. Ho aggiornato la sua sintassi.
Rygen

4

Versione rapida, se necessario:

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

4

Soluzione Swift 4:

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

2

È possibile mantenere una stringa con l'identificatore di categoria durante la pianificazione della notifica in questo modo

        localNotification.category = NotificationHelper.categoryIdentifier

e cercalo e annulla quando necessario in questo modo

let  app = UIApplication.sharedApplication()

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

        }
    }

1

L'oggetto UILocalNotification a cui si passa cancelLocalNotification:corrisponderà a qualsiasi oggetto UILocalNotification esistente con proprietà corrispondenti.

Così:

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

presenterà una notifica locale che potrà essere successivamente cancellata con:

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

1
Grazie. Penso che tu stia creando una nuova notifica e poi annullandola. Non avrà alcun effetto sulla mia notifica precedentemente pianificata e verrà comunque attivato.
Yogi

Esiste una proprietà che può corrispondere a una proprietà eccetto alertBody?
Shamsiddin

1

Uso questa funzione in 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
  }

Ispirato dalla risposta di @ KingofBliss


1

stile 3 rapido:

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

}

per iOS 10 utilizzare:

    let center = UNUserNotificationCenter.current()
    center.removePendingNotificationRequests(withIdentifiers: [uidtodelete])

0

Per promemoria ripetuti (ad esempio, si desidera che la sveglia si attivi domenica, sabato e mercoledì alle 16:00, quindi è necessario creare 3 allarmi e impostare repeatInterval su NSWeekCalendarUnit).

Per creare un solo promemoria:

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];

Per fare promemoria ripetuti:

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];
                }
            }

Per filtrare l'array per visualizzarlo.

-(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;
}

Per rimuovere il promemoria anche se era solo una volta o ripetuto:

- (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];

}

0

Ho ampliato un po 'la risposta di KingofBliss, l'ho scritto in modo un po' più simile a Swift2, ho rimosso del codice non necessario e ho aggiunto alcune protezioni per i crash.

Per iniziare, quando crei la notifica, devi assicurarti di impostare l'uid (o qualsiasi proprietà personalizzata realmente) della notifica userInfo:

notification.userInfo = ["uid": uniqueid]

Quindi, quando lo elimini, puoi fare:

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

1
Per sicurezza potresti usare guard-statement guard let app = UIApplication.sharedApplication () else {return false} for schedualedNotif in app.scheduledLocalNotifications {...} Quindi non è necessario forzare lo scartamento nel ciclo for
troligtvis
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.