Видаліть певне місцеве сповіщення


92

Я розробляю додаток для сигналізації iPhone на основі місцевих сповіщень.

Після видалення будильника відповідне місцеве сповіщення має бути скасовано. Але як я можу точно визначити, який об’єкт із масиву локальних сповіщень буде скасовано?

Я знаю [[UIApplication sharedApplication] cancelLocalNotification:notification]спосіб, але як я можу отримати це "сповіщення", щоб скасувати його?

Відповіді:


218

Ви можете зберегти унікальне значення ключа в інформації про місцеве сповіщення. Отримати всі локальні сповіщення, прокрутити масив і видалити конкретне сповіщення.

Код наступним чином,

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

Повідомлення користувача:

Якщо ви використовуєте UserNotification (iOS 10+), просто виконайте такі дії:

  1. Створюючи вміст UserNotification, додайте унікальний ідентифікатор

  2. Видаліть конкретне очікуване сповіщення за допомогою removePendingNotificationRequests (withIdentifiers :)

  3. Видаліть конкретне доставлене сповіщення за допомогою removeDeliveredNotifications (withIdentifiers :)

Для отримання додаткової інформації UNUserNotificationCenter


@ kingofBliss, можете, будь ласка, сказати мені, щоб я дав там на "uidtodelete". тому що це не заявлено в моєму випадку.
ishhhh

@ishhh це просто значення strig .. вам слід оголосити його та інціалізувати зі значенням uid для видалення
KingofBliss

@ kingofBliss, uid завжди показує нуль у NSLog.dont знає, як від цього позбутися. Будь ласка, допоможіть мені
ishhhh

@ishhh Ви зберігали будь-яке значення uid у словнику userinfo при створенні локального сповіщення? Я думаю, ви це пропустили.
KingofBliss

@kingofBliss, "uid" - це ім'я вашої власної змінної, ви можете використовувати будь-яке значуще ім'я, наприклад "messageID", і зберігати це в а NSDictionaryзі значенням ідентифікатора сутності, пов'язаної з UILocalNotification. Потім встановіть для властивості notification.userInfo словник зі своїми користувацькими даними. Тепер, коли ви отримуєте сповіщення, ви можете відрізнити їх за допомогою власного ідентифікатора або чогось іншого, що вам потрібно.
IgniteCoders

23

Інший варіант:

Перш за все, коли ви створюєте локальне сповіщення, ви можете зберігати його за замовчуванням для подальшого використання. Об’єкт локального сповіщення не можна зберігати безпосередньо в налаштуваннях за замовчуванням. Цей об’єкт потрібно спочатку перетворити на об’єкт NSData, а потім NSDataможна зберегти в User defaults. Нижче наведено код для цього:

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

Після того, як ви зберегли та запланували локальне сповіщення, у майбутньому може виникнути вимога скасувати будь-яке повідомлення, яке ви створили раніше, щоб ви могли отримати його за замовчуванням користувача.

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

Сподіваюся, це допомагає


Дякую, я реалізував це спочатку, але ваша відповідь також правильна. Я врахую це. Чи можете ви сказати, будь ласка, який з них є більш ефективним? Дякую за допомогу :)
Йог,

1
@Yogi: Якщо ви подивитесь на першу відповідь, вам потрібно кожного разу запускати цикл for, якщо ви хочете скасувати локальне сповіщення, але у наведеній вище відповіді вам не потрібно буде запускати цикл for, ви можете безпосередньо отримати доступ до локального сповіщення та скасувати це локальне сповіщення та вилучіть його із налаштувань користувача за замовчуванням. Відповідно до моєї відповіді, це більш ефективний спосіб
iMOBDEV

@JigneshBrahmkhatri Ваш метод ефективний. Але це не вдасться, коли користувач видалить програму та перевстановить її.
KingofBliss

@KingofBliss, у такому випадку ми повинні скасувати всі сповіщення, так? Тож я думаю, це рішення швидше. :)
Суфіан

@Sufian Для скасування всіх сповіщень існує набагато швидший спосіб [[UIApplication sharedApplication] cancelAllLocalNotifications]; ;)
KingofBliss

8

Ось що я роблю.

Створюючи сповіщення, зробіть наступне:

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

при спробі видалити це зробити:

 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

    }

}

Це рішення має працювати для кількох сповіщень, а також не керувати масивами, словниками та типовими налаштуваннями користувача. Ви просто використовуєте дані, які ви вже зберегли в базі даних системних сповіщень.

Сподіваюся, це допоможе майбутнім дизайнерам та розробникам.

Щасливого кодування хлопці! : D


Дякуємо, що поділилися своєю відповіддю, але як працює ця логіка, якщо всі ваші сповіщення мають одне тіло або якщо тіло потрібно взяти у користувача. У такому випадку користувач може надіслати одне і те саме кільком повідомленням.
Йог

@Yogi, як alertbody, ви можете перевірити, notification.firedate, щоб отримати необхідне сповіщення. спасибі abhi за просте рішення.
підтримати

1
@NAZIK: Дякуємо за інтерес до обговорення. Але все-таки користувач може запланувати два повідомлення на одну дату пожежі, оскільки це програма для сигналізації. Принаймні, це може бути тестом для тестувальника, і, схоже, це рішення там не вдається.
Йог

@ Йогі, мудре тестування, чому ми не можемо перевірити, чи ([localNotification.alertBody isEqualToString: savedTitle] || [localNotification.firedate == something]), оскільки два повідомлення з тією ж датою повинні містити різні боди оповіщення
Абдулла

Не зловживайте повідомленням alertBodyабо fireDateдля ідентифікації повідомлення; використовуйте userInfoполе для цього, як відповідь @KingOfBliss детально ...
severin

8

Планування та видалення Повідомлення швидко:

    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
Не зловживайте повідомленням alertBodyабо fireDateдля ідентифікації повідомлення; використовуйте userInfoполе для цього, як відповідь @KingOfBliss детально ...
severin

Так alertBody не є хорошим варіантом для ідентифікації повідомлення. Я змінив його на userInfo
Роман Баржичак

6

iMOBDEV в рішенні відмінно працює , щоб видалити повідомлення конкретних (наприклад , після видалення сигналу тривоги) , але це особливо корисно , коли вам потрібно вибірково видалити будь-яке повідомлення , що вже звільнені і по - , як і раніше в центрі повідомлень.

Можливий сценарій: сповіщення про спрацьовування будильника спрацьовує, але користувач відкриває програму, не натискаючи на це сповіщення, і знову планує цю тривогу. Якщо ви хочете переконатися, що лише одне сповіщення може бути в центрі сповіщень для даного елемента / сигналу, це хороший підхід. Це також дозволяє вам не очищати всі сповіщення кожного разу, коли додаток відкривається, якщо це краще підходить для програми.

  • Створюючи локальне сповіщення, використовуйте, NSKeyedArchiverщоб зберегти його як Dataу UserDefaults. Ви можете створити ключ, рівний тому, що ви зберігаєте у словнику userInfo сповіщення. Якщо він пов'язаний з об'єктом Core Data, ви можете використовувати його унікальну властивість objectID.
  • Отримайте його за допомогою NSKeyedUnarchiver. Тепер ви можете видалити його за допомогою методу cancelLocalNotification.
  • Відповідно оновіть ключ UserDefaults.

Ось версія цього рішення Swift 3.1 (для цілей нижче iOS 10):

Зберігати

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

Отримати та видалити

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

Працював у мене. Усі інші пропозиції ні, тому що масив порожній.
Максим Князєв

Будь-яка ідея для iOS 10?
Данпе

1
@Danpe: подивіться на розділ "Керування доставленими сповіщеннями" тут: developer.apple.com/reference/usernotifications/…
Райген

працював у мене зі швидким 3 з незначними модами, з якими обробляв Xcode.
beshio

@beshio: дякую за голови. Я оновив його синтаксис.
Rygen

4

Швидка версія, якщо потрібно:

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

Рішення Swift 4:

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

2

Ви можете зберегти рядок з ідентифікатором категорії, коли плануєте сповіщення таким чином

        localNotification.category = NotificationHelper.categoryIdentifier

і шукайте його та скасовуйте, коли це потрібно

let  app = UIApplication.sharedApplication()

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

        }
    }

1

Об'єкт UILocalNotification, до якого ви переходите cancelLocalNotification:, відповідатиме будь-якому існуючому об'єкту UILocalNotification з відповідними властивостями.

Так:

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

подасть місцеве сповіщення, яке згодом можна скасувати за допомогою:

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

1
Дякую. Я думаю, ви створюєте нове сповіщення, а потім скасовуєте його. Це не вплине на моє попередньо заплановане сповіщення, і воно все одно буде звільнено.
Йог

Чи існує якась властивість, яка може відповідати властивості, крім alertBody?
Шамсіддін,

1

Я використовую цю функцію в 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
  }

Натхненно з відповіді @ KingofBliss


1

швидкий 3-стиль:

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

}

для iOS 10:

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

0

Для повторних нагадувань (Наприклад, ви хочете, щоб будильник спрацьовував у НД, Сб та Ср о 16:00, Потім потрібно зробити 3 сигнали тривоги та встановити repeatInterval на NSWeekCalendarUnit).

Для створення нагадування лише один раз:

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

Для повторного нагадування:

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

Для фільтрування ви будете відображати масив.

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

Щоб видалити нагадування, навіть якщо воно було лише один раз або повторене:

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

Я трохи розширив відповідь KingofBliss, написав це трохи більше, схоже на Swift2, видалив непотрібний код і додав деякі захисні програми.

Для початку, створюючи сповіщення, потрібно переконатися, що ви встановили uid (або будь-яке власне властивість) сповіщень userInfo:

notification.userInfo = ["uid": uniqueid]

Потім, видаляючи його, ви можете зробити:

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
З міркувань безпеки ви можете скористатися захисною заявою guard let app = UIApplication.sharedApplication () else {return false} для schedualedNotif у app.scheduledLocalNotifications {...} Тоді вам не потрібно змушувати розгортати його у циклі for
troligtvis
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.