Löschen Sie eine bestimmte lokale Benachrichtigung

90

Ich entwickle eine iPhone-Alarm-App basierend auf lokalen Benachrichtigungen.

Beim Löschen eines Alarms sollte die zugehörige lokale Benachrichtigung abgebrochen werden. Aber wie kann ich genau bestimmen, welches Objekt aus dem Array lokaler Benachrichtigungen abgebrochen werden soll?

Ich kenne die [[UIApplication sharedApplication] cancelLocalNotification:notification]Methode, aber wie kann ich diese "Benachrichtigung" erhalten, um sie abzubrechen?

Yogi
quelle

Antworten:

216

Sie können einen eindeutigen Wert für den Schlüssel in der Benutzerinfo Ihrer lokalen Benachrichtigung speichern. Holen Sie sich alle lokalen Benachrichtigungen, durchlaufen Sie das Array und löschen Sie die jeweilige Benachrichtigung.

Code wie folgt:

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

SCHNELL:

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:

Wenn Sie UserNotification (iOS 10+) verwenden, führen Sie einfach die folgenden Schritte aus:

  1. Fügen Sie beim Erstellen des UserNotification-Inhalts eine eindeutige Kennung hinzu

  2. Entfernen Sie bestimmte ausstehende Benachrichtigungen mit removePendingNotificationRequests (withIdentifiers :)

  3. Entfernen Sie bestimmte gelieferte Benachrichtigungen mit removeDeliveredNotifications (withIdentifiers :)

Weitere Informationen finden Sie im UNUserNotificationCenter

KingofBliss
quelle
@ kingofBliss, kannst du mir bitte sagen, dass ich dort bei "uidtodelete" geben soll, weil es in meinem Fall nicht deklariert ist.
ishhhh
@ishhh itsjust ein strig Wert .. Sie sollten es deklarieren und es mit einem Wert der zu löschenden UID initialisieren
KingofBliss
@ kingofBliss, die UID zeigt immer null in NSLog.dont konw, wie man dies loswird. Bitte helfen Sie mir
ishhhh
@ishhh Haben Sie beim Erstellen einer lokalen Benachrichtigung einen Wert für uid im Benutzerinfo-Wörterbuch gespeichert? Ich denke, Sie haben das verpasst.
KingofBliss
@kingofBliss, die "UID" ist ein Name Ihrer eigenen Variablen. Sie können einen beliebigen signifikanten Namen wie "Benachrichtigungs- NSDictionaryID " verwenden und diesen in einem mit dem Wert der ID der Entität speichern, die sich auf die bezieht UILocalNotification. Setzen Sie dann die Eigenschaft notification.userInfo auf das Wörterbuch mit Ihren benutzerdefinierten Daten. Wenn Sie die Benachrichtigungen erhalten, können Sie sie mit dieser benutzerdefinierten ID oder anderen Elementen unterscheiden, die Sie benötigen.
IgniteCoders
23

Andere Option:

Wenn Sie eine lokale Benachrichtigung erstellen, können Sie diese zunächst für die zukünftige Verwendung in den Benutzerstandards speichern. Das lokale Benachrichtigungsobjekt kann nicht direkt in den Benutzerstandards gespeichert werden. Dieses Objekt muss zuerst in ein NSData-Objekt konvertiert und dann NSDatain gespeichert werden User defaults. Unten ist der Code dafür:

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

Nachdem Sie die lokale Benachrichtigung gespeichert und geplant haben, kann es in Zukunft erforderlich sein, dass Sie eine zuvor erstellte Benachrichtigung abbrechen müssen, damit Sie sie aus den Benutzerstandards abrufen können.

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

Hoffe das hilft

iMOBDEV
quelle
Danke, ich habe es auf den ersten Weg implementiert, aber Ihre Antwort ist auch richtig. Ich werde dies berücksichtigen. Können Sie bitte sagen, welches effizienter ist? Danke für die Hilfe :)
Yogi
1
@Yogi: Wenn Sie sich die erste Antwort ansehen, müssen Sie jedes Mal eine for-Schleife ausführen, wenn Sie die lokale Benachrichtigung abbrechen möchten. In der obigen Antwort müssen Sie jedoch keine for-Schleife ausführen. Sie können direkt auf die lokale Benachrichtigung zugreifen und diese abbrechen lokale Benachrichtigung und entfernen Sie es aus den Benutzerstandards.
Gemäß
@JigneshBrahmkhatri Ihre Methode ist effektiv. Es schlägt jedoch fehl, wenn der Benutzer die App deinstalliert und neu installiert.
KingofBliss
@KingofBliss, in diesem Fall müssen wir alle Benachrichtigungen stornieren, oder? Ich denke, diese Lösung ist schneller. :)
Sufian
@Sufian Um alle Benachrichtigungen abzubrechen, gibt es einen viel schnelleren Weg [[UIApplication sharedApplication] cancelAllLocalNotifications]; ;)
KingofBliss
8

Hier ist was ich tue.

Gehen Sie beim Erstellen Ihrer Benachrichtigung folgendermaßen vor:

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

Wenn Sie versuchen, es zu löschen, gehen Sie wie folgt vor:

 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

    }

}

Diese Lösung sollte für mehrere Benachrichtigungen funktionieren und Sie sollten keine Arrays oder Wörterbücher oder Benutzerstandards verwalten. Sie verwenden einfach die Daten, die Sie bereits in der Systembenachrichtigungsdatenbank gespeichert haben.

Ich hoffe, dies hilft zukünftigen Designern und Entwicklern.

Viel Spaß beim Codieren! : D.

abhi
quelle
Vielen Dank, dass Sie uns Ihre Antwort mitgeteilt haben, aber wie diese Logik funktioniert, wenn alle Ihre Benachrichtigungen denselben Text haben oder wenn der Text dem Benutzer entnommen werden soll. In diesem Fall kann der Benutzer mehreren Benachrichtigungen denselben Text zuweisen.
Yogi
@Yogi können Sie wie alertbody überprüfen, notification.firedate, um die erforderliche Benachrichtigung zu erhalten. danke an abhi für eine einfache lösung. upvote 1 für u
Azik Abdullah
1
@NAZIK: Danke für dein Interesse an Diskussionen. Der Benutzer kann jedoch zwei Benachrichtigungen am selben Branddatum planen, da es sich um eine Alarmanwendung handelt. Zumindest kann es ein Testfall für einen Tester sein, und diese Lösung scheint dort zu scheitern.
Yogi
@ Yogi, weise Prüfung, warum können wir nicht prüfen, ob ([localNotification.alertBody isEqualToString: savedTitle] || [localNotification.firedate == Something]), da die beiden Benachrichtigungen mit demselben Datum unterschiedliche alertBody enthalten sollten
Azik Abdullah
Missbrauche das alertBodyoder nicht, fireDateum eine Benachrichtigung zu identifizieren. Verwenden Sie dazu das userInfoFeld als Antwort von @KingOfBliss Details ...
Severin
8

Planen und EntfernenBenachrichtigung in Kürze:

    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
quelle
1
Missbrauche das alertBodyoder nicht, fireDateum eine Benachrichtigung zu identifizieren. Verwenden Sie dazu das userInfoFeld als Antwort von @KingOfBliss Details ...
Severin
Ja, alertBody ist keine gute Option, um eine Benachrichtigung zu identifizieren. Ich habe es in userInfo
Roman Barzyczak
6

Die Lösung von iMOBDEV funktioniert perfekt, um eine bestimmte Benachrichtigung zu entfernen (z. B. nach dem Löschen des Alarms). Sie ist jedoch besonders nützlich, wenn Sie eine Benachrichtigung entfernen müssen, die bereits ausgelöst wurde und sich noch im Benachrichtigungscenter befindet.

Ein mögliches Szenario wäre: Die Benachrichtigung für einen Alarm wird ausgelöst, aber der Benutzer öffnet die App, ohne auf diese Benachrichtigung zu tippen, und plant diesen Alarm erneut. Wenn Sie sicherstellen möchten, dass nur eine Benachrichtigung für ein bestimmtes Element / einen bestimmten Alarm im Benachrichtigungscenter vorhanden ist, ist dies ein guter Ansatz. Außerdem müssen Sie nicht jedes Mal, wenn die App geöffnet wird, alle Benachrichtigungen löschen, damit diese besser zur App passen.

  • NSKeyedArchiverSpeichern Sie Databeim Erstellen einer lokalen Benachrichtigung diese wie in UserDefaults. Sie können einen Schlüssel erstellen, der dem entspricht, was Sie im userInfo-Wörterbuch der Benachrichtigung speichern. Wenn es einem Core Data-Objekt zugeordnet ist, können Sie dessen eindeutige objectID-Eigenschaft verwenden.
  • Rufen Sie es mit ab NSKeyedUnarchiver. Jetzt können Sie es mit der Methode cancelLocalNotification löschen.
  • Aktualisieren Sie den Schlüssel UserDefaultsentsprechend.

Hier ist eine Swift 3.1-Version dieser Lösung (für Ziele unter iOS 10):

Geschäft

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

Abrufen und löschen

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")
}
Sauerstoff
quelle
Hat für mich gearbeitet. Alle anderen Vorschläge nicht, da das Array leer ist.
Maksim Kniazev
Irgendeine Idee für iOS 10?
Danpe
1
@ Danpe: Schauen Sie sich den Abschnitt "Verwalten gelieferter Benachrichtigungen" hier an: developer.apple.com/reference/usernotifications/…
Rygen
arbeitete für mich mit Swift 3 mit kleinen Mods, die Xcode handhabte.
Beshio
@beshio: danke für die Heads-Ups. Ich habe die Syntax aktualisiert.
Rygen
4

Schnelle Version, falls erforderlich:

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

Swift 4-Lösung:

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

Sie können eine Zeichenfolge mit der Kategorie-ID beibehalten, wenn Sie die Benachrichtigung wie folgt planen

        localNotification.category = NotificationHelper.categoryIdentifier

und suchen Sie danach und brechen Sie bei Bedarf ab

let  app = UIApplication.sharedApplication()

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

        }
    }
pantos27
quelle
1

Das UILocalNotification-Objekt, an das Sie übergeben, cancelLocalNotification:stimmt mit jedem vorhandenen UILocalNotification-Objekt mit übereinstimmenden Eigenschaften überein.

So:

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

zeigt eine lokale Benachrichtigung an, die später storniert werden kann mit:

UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = @"foo";
[[UIApplication sharedApplication] cancelLocalNotification:notification];
jhibberd
quelle
1
Vielen Dank. Ich denke, Sie erstellen eine neue Benachrichtigung und stornieren sie dann. Es hat keine Auswirkungen auf meine zuvor geplante Benachrichtigung und wird trotzdem ausgelöst.
Yogi
Gibt es eine Eigenschaft, die mit der Eigenschaft außer alertBody übereinstimmen kann?
Shamsiddin
1

Ich benutze diese Funktion 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
  }

Inspiriert von @ KingofBliss 'Antwort

MBH
quelle
1

schnelle 3-Stil:

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

}}

für iOS 10 verwenden:

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

Für wiederholte Erinnerungen (Zum Beispiel möchten Sie, dass Ihr Alarm um 16, Sa und Mi um 16 Uhr ausgelöst wird. Dann müssen Sie 3 Alarme auslösen und repeatInterval auf NSWeekCalendarUnit setzen).

Für die einmalige Erinnerung:

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

Für wiederholte Erinnerungen:

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

Zum Filtern wird das Array angezeigt.

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

So entfernen Sie die Erinnerung, auch wenn sie nur einmal oder wiederholt wurde:

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

Ich habe die Antwort von KingofBliss ein wenig erweitert, diese etwas Swift2-ähnlicher geschrieben, unnötigen Code entfernt und einige Crash Guards hinzugefügt.

Um zu beginnen, müssen Sie beim Erstellen der Benachrichtigung sicherstellen, dass Sie die UID (oder eine benutzerdefinierte Eigenschaft) der Benachrichtigung festlegen userInfo:

notification.userInfo = ["uid": uniqueid]

Wenn Sie es dann löschen, können Sie Folgendes tun:

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
quelle
1
Aus Sicherheitsgründen Sie die Wache-Anweisung Wache let app = UIApplication.sharedApplication () else {return false} für schedualedNotif in app.scheduledLocalNotifications verwenden könnte {...} Dann brauchen Sie nicht zu Gewalt unwrap es in der for-Schleife
troligtvis