Usuń określone powiadomienie lokalne

92

Rozwijam aplikację alarmową na iPhone'a w oparciu o lokalne powiadomienia.

Po usunięciu alarmu powiązane powiadomienie lokalne powinno zostać anulowane. Ale jak mogę dokładnie określić, który obiekt z tablicy lokalnych powiadomień ma zostać anulowany?

Znam [[UIApplication sharedApplication] cancelLocalNotification:notification]metodę, ale jak mogę otrzymać to „powiadomienie”, aby je anulować?

Jog
źródło

Odpowiedzi:

217

Możesz zapisać unikalną wartość klucza w informacjach o użytkowniku lokalnego powiadomienia. Uzyskaj wszystkie powiadomienia lokalne, przejrzyj tablicę i usuń określone powiadomienie.

Kod w następujący sposób,

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

SZYBKI:

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

Powiadomienie użytkownika:

Jeśli używasz UserNotification (iOS 10+), po prostu wykonaj następujące kroki:

  1. Podczas tworzenia treści UserNotification dodaj unikalny identyfikator

  2. Usuń konkretne oczekujące powiadomienie za pomocą removePendingNotificationRequests (withIdentifiers :)

  3. Usuń określone dostarczone powiadomienie za pomocą removeDeliveredNotifications (withIdentifiers :)

Aby uzyskać więcej informacji, UNUserNotificationCenter

KingofBliss
źródło
@ kingofBliss, czy możesz mi powiedzieć, żebym dał tam na „uidtodelete”. ponieważ jest to niezadeklarowane w moim przypadku.
ishhhh
@ishhh to tylko wartość strig ... powinieneś ją zadeklarować i zainicjować z wartością uid do usunięcia
KingofBliss
@ kingofBliss, uid zawsze pokazuje null w NSLog. nie wiem, jak się tego pozbyć.Prosimy o pomoc
ishhhh
@ishhh czy podczas tworzenia lokalnego powiadomienia zapisałeś jakąś wartość dla uid w słowniku informacji o użytkowniku? Myślę, że to przegapiłeś.
KingofBliss
@kingofBliss, „uid” to nazwa Twojej własnej zmiennej, możesz użyć dowolnej znaczącej nazwy, takiej jak „notificationID”, i zapisać ją w a NSDictionaryz wartością identyfikatora jednostki związanej z UILocalNotification. Następnie ustaw właściwość notification.userInfo na słownik z danymi niestandardowymi. Teraz, gdy otrzymasz powiadomienia, możesz je odróżnić za pomocą tego niestandardowego identyfikatora lub czegokolwiek innego, czego potrzebujesz.
IgniteCoders
23

Inna opcja:

Po pierwsze, kiedy tworzysz lokalne powiadomienie, możesz zapisać je w ustawieniach domyślnych użytkownika do przyszłego użytku.Lokalny obiekt powiadomienia nie może być przechowywany bezpośrednio w ustawieniach domyślnych użytkownika.Ten obiekt musi najpierw zostać przekonwertowany na obiekt NSData, a następnie NSDatamoże być przechowywany w User defaults. Poniżej znajduje się kod:

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

Po zapisaniu i zaplanowaniu powiadomienia lokalnego, w przyszłości może zaistnieć potrzeba anulowania dowolnego powiadomienia, które utworzyłeś wcześniej, aby móc je odzyskać z ustawień domyślnych użytkownika.

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

Mam nadzieję że to pomoże

iMOBDEV
źródło
Dzięki, I wprowadziły go przez pierwszy sposób, ale odpowiedź jest również correct.I weźmie to pod consideration.Can Proszę powiedzieć, który z nich jest bardziej efektywne dzięki za pomoc :)?
Yogi
1
@Yogi: Jeśli spojrzysz na pierwszą odpowiedź, musisz uruchomić pętlę za każdym razem, jeśli chcesz anulować lokalne powiadomienie, ale w powyższej odpowiedzi nie będziesz musiał uruchamiać żadnej pętli for, możesz bezpośrednio uzyskać dostęp do lokalnego powiadomienia i anulować to lokalne powiadomienie i usuń je z domyślnych ustawień użytkownika, Jak na moją odpowiedź, jest to bardziej wydajny sposób
iMOBDEV
@JigneshBrahmkhatri Twoja metoda jest skuteczna. Ale zakończy się niepowodzeniem, gdy użytkownik odinstaluje aplikację i ponownie ją zainstaluje.
KingofBliss
@KingofBliss, w takim razie musimy anulować wszystkie powiadomienia, prawda? Więc myślę, że to rozwiązanie jest szybsze. :)
Sufian
@Sufian Aby anulować wszystkie powiadomienia, istnieje znacznie szybszy sposób [[UIApplication sharedApplication] cancelAllLocalNotifications]; ;)
KingofBliss
8

Oto co robię.

Tworząc powiadomienie, wykonaj następujące czynności:

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

próbując go usunąć, wykonaj następujące czynności:

 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

    }

}

To rozwiązanie powinno działać w przypadku wielu powiadomień, a Ty nie zarządzasz żadnymi tablicami, słownikami ani domyślnymi ustawieniami użytkownika. Po prostu używasz danych, które już zapisałeś w bazie danych powiadomień systemu.

Mam nadzieję, że pomoże to przyszłym projektantom i programistom.

Miłego kodowania! :RE

abhi
źródło
Dziękujemy za udostępnienie odpowiedzi, ale jak działa ta logika, jeśli wszystkie Twoje powiadomienia mają tę samą treść lub jeśli treść ma zostać pobrana od użytkownika. W takim przypadku użytkownik może nadać tę samą treść wielu powiadomieniom.
Yogi
@Yogi, podobnie jak alertbody, możesz sprawdzić, powiadomienie.firedate, aby uzyskać wymagane powiadomienie. dzięki abhi za proste rozwiązanie. głosowanie 1 na u
Nazik
1
@NAZIK: Dziękuję za zainteresowanie dyskusją. Mimo to użytkownik może zaplanować dwa powiadomienia na tę samą datę pożaru, ponieważ jest to aplikacja alarmowa. Przynajmniej może to być przypadek testowy dla testera i wygląda na to, że to rozwiązanie zawodzi.
Yogi
@ Yogi, mądre testowanie, dlaczego nie możemy sprawdzić, czy ([localNotification.alertBody isEqualToString: saveTitle] || [localNotification.firedate == coś]), ponieważ dwa powiadomienia z tą samą datą powinny zawierać różne alertBody
Nazik
Nie nadużywaj alertBodyani fireDatedo identyfikowania powiadomienia; użyj userInfopola do zrobienia tego, jako odpowiedź przez @KingOfBliss szczegóły ...
severin
8

Planowanie i usuwanie powiadomień w szybkim:

    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
źródło
1
Nie nadużywaj alertBodyani fireDatedo identyfikowania powiadomienia; użyj userInfopola do zrobienia tego, jako odpowiedź przez @KingOfBliss szczegóły ...
severin
Tak alertBody nie jest dobrą opcją do identyfikowania powiadomienia. Zmieniłem to na userInfo
Roman Barzyczak
6

iMOBDEV za rozwiązanie działa idealnie, aby usunąć powiadomienie specyficzny (np po skasowaniu alarmu), ale to specjalnie przydatna, gdy trzeba, aby selektywnie usunąć powiadomienie, że został już zwolniony i jest nadal w centrum powiadomień.

Możliwy scenariusz to: powiadomienie o pożarze alarmu, ale użytkownik otwiera aplikację bez dotykania tego powiadomienia i ponownie planuje ten alarm. Jeśli chcesz mieć pewność, że w centrum powiadomień dla danego elementu / alarmu może znajdować się tylko jedno powiadomienie, jest to dobre podejście. Dzięki temu nie musisz usuwać wszystkich powiadomień za każdym razem, gdy aplikacja jest otwierana, jeśli to lepiej pasuje do aplikacji.

  • Po utworzeniu powiadomienia lokalnego użyj, NSKeyedArchiveraby zapisać je Dataw formacie UserDefaults. Możesz utworzyć klucz równy temu, który zapisujesz w słowniku userInfo powiadomienia. Jeśli jest powiązany z obiektem Core Data, możesz użyć jego unikalnej właściwości objectID.
  • Odzyskaj to za pomocą NSKeyedUnarchiver. Teraz możesz go usunąć za pomocą metody cancelLocalNotification.
  • Zaktualizuj klucz UserDefaultsodpowiednio.

Oto wersja Swift 3.1 tego rozwiązania (dla celów poniżej iOS 10):

Sklep

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

Pobierz i usuń

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
źródło
Pracował dla mnie. Wszystkie inne sugestie nie, ponieważ tablica jest pusta.
Maksim Kniazev
Masz pomysł na iOS 10?
Danpe
1
@Danpe: zajrzyj do sekcji „Zarządzanie dostarczonymi powiadomieniami” tutaj: developer.apple.com/reference/usernotifications/…
Rygen
pracował dla mnie ze swift 3 z pomniejszymi modami, które obsługiwał Xcode.
beshio
@beshio: dzięki za ostrzeżenie. Zaktualizowałem jego składnię.
Rygen
5

Rozwiązanie Swift 4:

UNUserNotificationCenter.current().getPendingNotificationRequests { (requests) in
  for request in requests {
    if request.identifier == "identifier" {
      UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: ["identifier"])
    }
  }
}   
Nupur Sharma
źródło
4

Wersja Swift, w razie potrzeby:

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
źródło
2

Możesz zachować ciąg z identyfikatorem kategorii podczas planowania powiadomienia w ten sposób

        localNotification.category = NotificationHelper.categoryIdentifier

i wyszukaj go i anuluj w razie potrzeby

let  app = UIApplication.sharedApplication()

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

        }
    }
pantos27
źródło
2

szybki 3 styl:

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

}

do użytku na iOS 10:

    let center = UNUserNotificationCenter.current()
    center.removePendingNotificationRequests(withIdentifiers: [uidtodelete])
ingconti
źródło
1

Obiekt UILocalNotification, do którego przekazujesz, cancelLocalNotification:będzie pasował do dowolnego istniejącego obiektu UILocalNotification z pasującymi właściwościami.

Więc:

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

przedstawi lokalne powiadomienie, które można później anulować za pomocą:

UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = @"foo";
[[UIApplication sharedApplication] cancelLocalNotification:notification];
jhibberd
źródło
1
Dzięki. Myślę, że tworzysz nowe powiadomienie, a następnie je anulujesz. Nie będzie to miało żadnego wpływu na moje wcześniej zaplanowane powiadomienie i nadal będzie uruchamiane.
Yogi,
Czy istnieje właściwość, która może być zgodna z inną właściwością niż alertBody?
Shamsiddin
1

Używam tej funkcji w 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
  }

Zainspirowany odpowiedzią @ KingofBliss

MBH
źródło
0

W przypadku powtarzających się przypomnień (na przykład chcesz, aby alarm był uruchamiany w niedziele, sobotę i środę o 16:00, a następnie musisz ustawić 3 alarmy i ustawić parametr RepeInterval na NSWeekCalendarUnit).

Aby zrobić jednorazowe przypomnienie:

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

Aby dokonać ponownego przypomnienia:

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

Do filtrowania macierz, aby ją wyświetlić.

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

Aby usunąć przypomnienie, nawet jeśli było to tylko raz lub powtórzone:

- (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
źródło
0

Rozwinąłem nieco odpowiedź KingofBliss, napisałem to trochę bardziej w stylu Swift2, usunąłem trochę niepotrzebnego kodu i dodałem kilka zabezpieczeń.

Aby rozpocząć, podczas tworzenia powiadomienia musisz upewnić się, że ustawiłeś uid (lub naprawdę dowolną niestandardową właściwość) powiadomienia userInfo:

notification.userInfo = ["uid": uniqueid]

Następnie podczas usuwania możesz zrobić:

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
źródło
1
Ze względów bezpieczeństwa możesz użyć guard-statement guard let app = UIApplication.sharedApplication () else {return false} for scheduleualedNotif in app.scheduledLocalNotifications {...} Wtedy nie musisz wymuszać rozpakowywania go w pętli for
troligtvis