Xóa một thông báo cục bộ cụ thể


92

Tôi đang phát triển một ứng dụng báo thức trên iPhone dựa trên các thông báo cục bộ.

Khi xóa báo thức, thông báo cục bộ liên quan sẽ bị hủy. Nhưng làm thế nào tôi có thể xác định chính xác đối tượng nào từ mảng thông báo cục bộ sẽ bị hủy?

Tôi biết về [[UIApplication sharedApplication] cancelLocalNotification:notification]phương pháp nhưng làm cách nào tôi có thể nhận được 'thông báo' này để hủy nó?

Câu trả lời:


218

Bạn có thể lưu một giá trị duy nhất cho khóa trong userinfo thông báo cục bộ của mình. Nhận tất cả thông báo cục bộ, lặp qua mảng và xóa thông báo cụ thể.

Mã như sau,

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

NHANH:

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

Thông báo Người dùng:

Nếu bạn sử dụng UserNotification (iOS 10+), chỉ cần làm theo các bước sau:

  1. Khi tạo nội dung Thông báo người dùng, hãy thêm một số nhận dạng duy nhất

  2. Xóa thông báo cụ thể đang chờ xử lý bằng removePendingNotificationRequests (withIdentifiers :)

  3. Xóa thông báo đã gửi cụ thể bằng removeDeliveredNotifications (withIdentifiers :)

Để biết thêm thông tin, UNUserNotificationCenter


@ kingofBliss, bạn có thể yêu cầu tôi cung cấp tại "uidtodelete" không. Vì nó không được khai báo trong trường hợp của tôi.
ishhhh

@ishhh itsjust một giá trị strig .. bạn nên khai báo nó và intialize nó với một giá trị của uid là xóa
KingofBliss

@ kingofBliss, uid luôn hiển thị trống trong NSLog. không biết làm thế nào để loại bỏ điều này. Xin hãy giúp tôi
ishhhh 7/10/11

@ishhh bạn đã lưu trữ bất kỳ giá trị nào cho uid trong từ điển userinfo khi tạo thông báo cục bộ chưa? Tôi nghĩ rằng bạn đã bỏ lỡ điều đó.
KingofBliss

@kingofBliss, "uid" đó là tên của biến của riêng bạn, bạn có thể sử dụng bất kỳ tên quan trọng nào như "notificationID" và lưu trữ tên đó trong a NSDictionaryvới giá trị là id của thực thể liên quan đến UILocalNotification. Sau đó, đặt thuộc tính notification.userInfo vào từ điển với dữ liệu tùy chỉnh của bạn. Giờ đây, khi nhận được thông báo, bạn có thể phân biệt chúng bằng id tùy chỉnh đó hoặc bất kỳ thứ gì khác mà bạn có thể cần.
IgniteCoders

23

Tùy chọn khác:

Trước hết, khi bạn tạo thông báo cục bộ, bạn có thể lưu trữ nó trong mặc định của người dùng để sử dụng trong tương lai, Đối tượng thông báo cục bộ không thể được lưu trữ trực tiếp trong mặc định của người dùng, đối tượng này cần được chuyển đổi thành đối tượng NSData trước, sau đó NSDatacó thể được lưu trữ thành User defaults. Dưới đây là mã cho điều đó:

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

Sau khi bạn đã lưu trữ và lên lịch thông báo cục bộ, Trong tương lai, yêu cầu có thể phát sinh rằng bạn cần phải hủy bất kỳ thông báo nào mà bạn đã tạo trước đó, Vì vậy, bạn có thể lấy nó từ mặc định của Người dùng.

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

Hi vọng điêu nay co ich


Cảm ơn, tôi đã thực hiện nó bằng cách đầu tiên nhưng câu trả lời của bạn cũng là correct.I sẽ thực hiện việc này vào consideration.Can bạn xin vui lòng cho cái nào là hiệu quả hơn Thanks for the help :)?
Yogi

1
@Yogi: Nếu bạn nhìn vào câu trả lời đầu tiên, bạn cần chạy vòng lặp for mọi lúc nếu bạn muốn hủy thông báo cục bộ, nhưng trong câu trả lời trên, bạn sẽ không cần chạy bất kỳ vòng lặp for nào, bạn có thể truy cập trực tiếp vào thông báo cục bộ và hủy thông báo đó thông báo địa phương và loại bỏ nó từ giá trị mặc định tài khoản, Như mỗi câu trả lời của tôi, nó là cách hiệu quả hơn
iMOBDEV

@JigneshBrahmkhatri Phương pháp của bạn có hiệu quả. Nhưng nó sẽ không thành công khi người dùng gỡ cài đặt ứng dụng và cài đặt lại.
KingofBliss

@KingofBliss, trong trường hợp đó chúng ta phải hủy tất cả các thông báo phải không? Vì vậy, tôi đoán giải pháp này là nhanh hơn. :)
Sufian

@Sufian Để hủy tất cả thông báo, có một cách nhanh hơn nhiều [[UIApplication sharedApplication] hủyAllLocalNotifications]; ;)
KingofBliss

8

Đây là những gì tôi làm.

Khi tạo thông báo, hãy làm như sau:

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

khi cố gắng xóa nó, hãy làm như sau:

 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

    }

}

Giải pháp này sẽ hoạt động với nhiều thông báo và bạn không quản lý bất kỳ mảng hoặc từ điển nào hoặc mặc định của người dùng. Bạn chỉ cần sử dụng dữ liệu bạn đã lưu vào cơ sở dữ liệu thông báo của hệ thống.

Hy vọng điều này sẽ giúp các nhà thiết kế và nhà phát triển trong tương lai.

Chúc các bạn mã hóa vui vẻ! : D


Cảm ơn bạn đã chia sẻ câu trả lời của mình nhưng cách logic này hoạt động nếu tất cả các thông báo của bạn có cùng nội dung hoặc nếu nội dung được lấy từ người dùng. Trong trường hợp đó, người dùng có thể cung cấp cùng một nội dung cho nhiều thông báo.
Yogi

@Yogi, giống như alertbody, bạn có thể kiểm tra, notification.firedate để nhận thông báo cần thiết. nhờ Abhi cho một đơn giản solution.upvote 1 cho u
Azik Abdullah

1
@NAZIK: Cảm ơn bạn đã quan tâm đến cuộc thảo luận. Nhưng người dùng vẫn có thể lên lịch cho hai thông báo vào cùng một ngày cháy vì nó là một ứng dụng báo động. Ít nhất nó có thể là một trường hợp thử nghiệm cho người thử nghiệm và giải pháp này có vẻ sẽ thất bại ở đó.
Yogi

@ Yogi, thử nghiệm khôn ngoan, tại sao không thể chúng tôi kiểm tra if ([localNotification.alertBody isEqualToString: savedTitle] || [localNotification.firedate == cái gì đó]), kể từ khi hai thông báo với cùng một ngày nên chứa khác nhau alertBody
Azik Abdullah

Không lạm dụng alertBodyhoặc fireDateđể xác định một thông báo; sử dụng các userInfolĩnh vực để thực hiện điều này, là câu trả lời bởi các chi tiết @KingOfBliss ...
SEVERIN

8

Lập lịch và xóa Thông báo nhanh chóng:

    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
Không lạm dụng alertBodyhoặc fireDateđể xác định một thông báo; sử dụng các userInfolĩnh vực để thực hiện điều này, là câu trả lời bởi các chi tiết @KingOfBliss ...
SEVERIN

Có cảnh báoBody không phải là lựa chọn tốt để xác định một thông báo. Tôi đã đổi nó thành userInfo
Roman Barzyczak

6

Giải pháp của iMOBDEV hoạt động hoàn hảo để xóa một thông báo cụ thể (ví dụ: sau khi xóa báo thức) nhưng nó đặc biệt hữu ích khi bạn cần xóa có chọn lọc bất kỳ thông báo nào đã kích hoạt và vẫn còn trên trung tâm thông báo.

Một tình huống có thể xảy ra là: thông báo báo động kích hoạt, nhưng người dùng mở ứng dụng mà không nhấn vào thông báo đó và lên lịch báo động đó lại. Nếu bạn muốn đảm bảo rằng chỉ có một thông báo có thể có trên trung tâm thông báo cho một mặt hàng / báo thức nhất định, đó là một cách tiếp cận tốt. Nó cũng cho phép bạn không phải xóa tất cả các thông báo mỗi khi ứng dụng được mở, điều đó sẽ phù hợp với ứng dụng hơn.

  • Khi tạo một thông báo cục bộ, hãy sử dụng NSKeyedArchiverđể lưu trữ nó như Datatrong UserDefaults. Bạn có thể tạo một khóa bằng với những gì bạn đang lưu trong từ điển userInfo của thông báo. Nếu nó được liên kết với một đối tượng Core Data, bạn có thể sử dụng thuộc tính objectID duy nhất của nó.
  • Lấy nó với NSKeyedUnarchiver. Bây giờ bạn có thể xóa nó bằng phương pháp hủyLocalNotification.
  • Cập nhật khóa cho UserDefaultsphù hợp.

Đây là phiên bản Swift 3.1 của giải pháp đó (dành cho các mục tiêu dưới iOS 10):

Cửa hàng

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

Lấy và xóa

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

Đã làm cho tôi. Tất cả các đề xuất khác thì không, bởi vì mảng trống.
Maksim Kniazev

Bất kỳ ý tưởng cho iOS 10?
Danpe

1
@Danpe: hãy xem phần "Quản lý thông báo đã gửi" tại đây: developer.apple.com/reference/usernotifications/…
Rygen

đã làm việc cho tôi với swift 3 với các mod nhỏ do Xcode xử lý.
beshio, 20/07/17

@beshio: cảm ơn vì đã quan tâm. Tôi đã cập nhật cú pháp của nó.
Rygen

4

Phiên bản Swift, nếu cần:

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

Giải pháp Swift 4:

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

2

Bạn có thể giữ một chuỗi với số nhận dạng danh mục khi lập lịch thông báo như vậy

        localNotification.category = NotificationHelper.categoryIdentifier

và tìm kiếm nó và hủy khi cần thiết như vậy

let  app = UIApplication.sharedApplication()

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

        }
    }

1

Đối tượng UILocalNotification mà bạn chuyển đến cancelLocalNotification:sẽ khớp với bất kỳ đối tượng UILocalNotification nào hiện có với các thuộc tính phù hợp.

Vì thế:

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

sẽ hiển thị một thông báo cục bộ mà sau này có thể bị hủy với:

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

1
Cảm ơn. Tôi nghĩ rằng bạn đang tạo một thông báo mới và sau đó hủy nó. Nó sẽ không ảnh hưởng đến thông báo đã lên lịch trước đó của tôi và nó sẽ vẫn bị kích hoạt.
Yogi

Có bất kỳ tài sản nào có thể phù hợp với tài sản ngoại trừ alertBody không?
Shamsiddin

1

Tôi sử dụng chức năng này trong 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
  }

Lấy cảm hứng từ Câu trả lời của @ KingofBliss


1

3 kiểu nhanh chóng:

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

}

để sử dụng iOS 10:

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

0

Đối với Lời nhắc Lặp lại (Ví dụ: bạn muốn báo thức của mình kích hoạt vào Chủ Nhật, Thứ Bảy và Thứ Tư lúc 4 giờ chiều, Sau đó, bạn phải thực hiện 3 lần báo thức và đặt repeatInterval thành NSWeekCalendarUnit).

Để thực hiện Lời nhắc Chỉ Một lần:

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

Để đưa ra lời nhắc lặp lại:

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

Đối với bộ lọc, bạn có mảng để hiển thị nó.

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

Để xóa Reminder ngay cả khi nó chỉ là một lần hoặc lặp lại:

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

Tôi đã mở rộng câu trả lời của KingofBliss một chút, viết câu này giống Swift2 hơn một chút, loại bỏ một số mã không cần thiết và thêm vào một số bảo vệ sự cố.

Để bắt đầu, khi tạo thông báo, bạn cần đảm bảo rằng bạn đặt uid (hoặc thực sự là bất kỳ thuộc tính tùy chỉnh nào) của thông báo userInfo:

notification.userInfo = ["uid": uniqueid]

Sau đó, khi xóa nó, bạn có thể thực hiện:

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
Để đảm bảo an toàn, bạn có thể sử dụng lệnh bảo vệ bảo vệ let app = UIApplication.sharedApplication () else {return false} cho SchedualedNotif trong app.schedisedLocalNotifications {...} Sau đó, bạn không cần phải mở nó ra trong vòng lặp
troligtvis
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.