Eliminar una notificación local en particular

92

Estoy desarrollando una aplicación de alarma para iPhone basada en notificaciones locales.

Al eliminar una alarma, la notificación local relacionada debe cancelarse. Pero, ¿cómo puedo determinar exactamente qué objeto de la matriz de notificaciones locales se cancelará?

Conozco el [[UIApplication sharedApplication] cancelLocalNotification:notification]método, pero ¿cómo puedo obtener esta 'notificación' para cancelarlo?

Yogui
fuente

Respuestas:

218

Puede guardar un valor único para la clave en la información de usuario de su notificación local. Obtenga todas las notificaciones locales, recorra la matriz y elimine la notificación en particular.

Codifique como sigue,

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

RÁPIDO:

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

UserNotification:

Si usa UserNotification (iOS 10+), simplemente siga estos pasos:

  1. Al crear el contenido de UserNotification, agregue un identificador único

  2. Elimine la notificación pendiente específica usando removePendingNotificationRequests (withIdentifiers :)

  3. Elimine la notificación entregada específica usando removeDeliveredNotifications (withIdentifiers :)

Para obtener más información, UNUserNotificationCenter

KingofBliss
fuente
@ kingofBliss, ¿podrías decirme que dé allí en "uidtodelete", porque en mi caso no está declarado?
ishhhh
@ishhh es solo un valor de strig ... debe declararlo e inicializarlo con un valor del uid que se eliminará
KingofBliss
@ kingofBliss, el uid siempre se muestra nulo en NSLog. No sé cómo deshacerse de esto. Por favor, ayúdame
ishhhh
@ishhh, ¿ha almacenado algún valor para uid en el diccionario userinfo al crear una notificación local? Creo que te lo has perdido.
KingofBliss
@kingofBliss, el "uid" es un nombre de su propia variable, puede usar cualquier nombre significativo como "notificationID", y almacenarlo en un NSDictionarycon el valor de la identificación de la entidad relacionada con UILocalNotification. Luego, establezca la propiedad notification.userInfo en el diccionario con sus datos personalizados. Ahora, cuando reciba las notificaciones, puede diferenciarlas con esa identificación personalizada o cualquier otra cosa que pueda necesitar.
IgniteCoders
23

Otra opción:

En primer lugar, cuando crea una notificación local, puede almacenarla en los valores predeterminados del usuario para uso futuro, el objeto de notificación local no se puede almacenar directamente en los valores predeterminados del usuario, este objeto debe convertirse primero en un objeto NSData y luego NSDatase puede almacenar en User defaults. A continuación se muestra el código para eso:

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

Después de haber almacenado y programado la notificación local, en el futuro, puede surgir el requisito de cancelar cualquiera de las notificaciones que creó anteriormente, para que pueda recuperarla de los valores predeterminados del usuario.

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

Espero que esto ayude

iMOBDEV
fuente
Gracias, lo he implementado por primera vez pero tu respuesta también es correcta. Lo tomaré en consideración. ¿Puedes decir cuál es más eficiente? Gracias por la ayuda :)
Yogi
1
@Yogi: Si observa la primera respuesta, debe ejecutar el bucle for cada vez que desee cancelar la notificación local, pero en la respuesta anterior, no necesitará ejecutar ningún bucle for, puede acceder directamente a la notificación local y cancelarla. notificación local y elimínela de los valores predeterminados del usuario, según mi respuesta, es una forma más eficiente
iMOBDEV
@JigneshBrahmkhatri Tu método es eficaz. Pero fallará cuando el usuario desinstale la aplicación y la vuelva a instalar.
KingofBliss
@KingofBliss, en ese caso tenemos que cancelar todas las notificaciones, ¿verdad? Entonces supongo que esta solución es más rápida. :)
Sufian
@Sufian Para cancelar todas las notificaciones, hay una manera mucho más rápida [[UIApplication sharedApplication] cancelAllLocalNotifications]; ;)
KingofBliss
8

Esto es lo que hago.

Al crear su notificación, haga esto:

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

al intentar eliminarlo, haga esto:

 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

    }

}

Esta solución debería funcionar para múltiples notificaciones y no administrar matrices, diccionarios o valores predeterminados del usuario. Simplemente usa los datos que ya ha guardado en la base de datos de notificaciones del sistema.

Espero que esto ayude a los futuros diseñadores y desarrolladores.

¡Felices chicos de codificación! :RE

abhi
fuente
Gracias por compartir tu respuesta, pero cómo funciona esta lógica si todas tus notificaciones tienen el mismo cuerpo o si el cuerpo debe ser tomado del usuario, en ese caso el usuario puede dar el mismo cuerpo a múltiples notificaciones.
Yogi
@Yogi, al igual que alertbody, puede verificar, notification.firedate para obtener la notificación requerida. gracias a abhi por una solución simple
upvote
1
@NAZIK: Gracias por su interés en la discusión. Pero aún así, el usuario puede programar dos notificaciones en la misma fecha de incendio, ya que es una aplicación de alarma. Al menos puede ser un caso de prueba para un probador y esta solución parece estar fallando allí.
Yogi
@ Yogi, prueba inteligente, ¿por qué no podemos verificar si ([localNotification.alertBody isEqualToString: SavedTitle] || [localNotification.firedate == algo]), ya que las dos notificaciones con la misma fecha deberían contener un alertBody diferente
Azik Abdullah
No abuse del alertBodyo fireDatepara identificar una notificación; use el userInfocampo para hacer esto, ya que la respuesta de @KingOfBliss detalla ...
Severin
8

Programación y eliminación de notificaciones en rápido:

    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
fuente
1
No abuse del alertBodyo fireDatepara identificar una notificación; use el userInfocampo para hacer esto, ya que la respuesta de @KingOfBliss detalla ...
severin
Sí, alertBody no es una buena opción para identificar una notificación. Lo cambié a userInfo
Roman Barzyczak
6

La solución de iMOBDEV funciona perfectamente para eliminar una notificación específica (por ejemplo, después de eliminar la alarma), pero es especialmente útil cuando necesita eliminar de forma selectiva cualquier notificación que ya se haya disparado y todavía se encuentre en el centro de notificaciones.

Un escenario posible sería: la notificación de una alarma se dispara, pero el usuario abre la aplicación sin tocar esa notificación y programa esa alarma nuevamente. Si desea asegurarse de que solo pueda haber una notificación en el centro de notificaciones para un elemento / alarma determinado, es un buen enfoque. También le permite no tener que borrar todas las notificaciones cada vez que se abre la aplicación, si eso se ajusta mejor a la aplicación.

  • Al crear una notificación local, utilice NSKeyedArchiverpara almacenarla como Dataen UserDefaults. Puede crear una clave igual a la que está guardando en el diccionario userInfo de la notificación. Si está asociado con un objeto Core Data, puede usar su propiedad objectID única.
  • Recupéralo con NSKeyedUnarchiver. Ahora puede eliminarlo utilizando el método cancelLocalNotification.
  • Actualice la clave en UserDefaultsconsecuencia.

Aquí hay una versión Swift 3.1 de esa solución (para objetivos por debajo de iOS 10):

Tienda

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

Recuperar y eliminar

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
fuente
Trabajó para mi. Todas las demás sugerencias no, porque la matriz está vacía.
Maksim Kniazev
¿Alguna idea para iOS 10?
Danpe
1
@Danpe: eche un vistazo a la sección "Gestión de notificaciones
enviadas
funcionó para mí con swift 3 con modificaciones menores, que Xcode manejó.
Beshio
@beshio: gracias por el aviso. Actualicé su sintaxis.
Rygen
4

Versión rápida, si es necesario:

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
fuente
4

Solución Swift 4:

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

Puede mantener una cadena con el identificador de categoría al programar la notificación así

        localNotification.category = NotificationHelper.categoryIdentifier

y búscalo y cancela cuando sea necesario así

let  app = UIApplication.sharedApplication()

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

        }
    }
pantos27
fuente
1

El objeto UILocalNotification al que pase cancelLocalNotification:coincidirá con cualquier objeto UILocalNotification existente con propiedades coincidentes.

Entonces:

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

presentará una notificación local que luego se puede cancelar con:

UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = @"foo";
[[UIApplication sharedApplication] cancelLocalNotification:notification];
Jhibberd
fuente
1
Gracias. Creo que estás creando una nueva notificación y luego la cancelas. No tendrá ningún efecto en mi notificación previamente programada y aún así se activará.
Yogi
¿Hay alguna propiedad que pueda coincidir con la propiedad excepto alertBody?
Shamsiddin
1

Yo uso esta función en 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
  }

Inspirado en la respuesta de @ KingofBliss

MBH
fuente
1

Swift 3 estilos:

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

}

para uso de iOS 10:

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

Para recordatorios repetidos (por ejemplo, desea que su alarma se active los domingos, sábados y miércoles a las 4 p.m., luego debe hacer 3 alarmas y configurar repeatInterval en NSWeekCalendarUnit).

Para hacer un recordatorio de una sola vez:

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

Para hacer recordatorio repetido:

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

Para filtrar su matriz para mostrarlo.

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

Para eliminar el recordatorio incluso si fue solo una vez o se repitió:

- (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
fuente
0

Amplié un poco la respuesta de KingofBliss, escribí esto un poco más como Swift2, eliminé algunos códigos innecesarios y agregué algunos protectores contra choques.

Para comenzar, al crear la notificación, debe asegurarse de establecer el uid (o cualquier propiedad personalizada realmente) de la notificación userInfo:

notification.userInfo = ["uid": uniqueid]

Luego, al eliminarlo, puede hacer:

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
fuente
1
Por seguridad, puede usar la declaración de guardia guard let app = UIApplication.sharedApplication () else {return false} para schedualedNotif en app.scheduledLocalNotifications {...} Entonces no es necesario forzarlo a desenvolverlo en el bucle for
troligtvis