Отключение уведомления локального уведомления пользователя при нажатии приложения не запускается в фоновом режиме iOS 11

У меня есть приложение, которое предупреждает пользователя каждые х минут через локальное уведомление UNNotification. Если пользователь не отвечает, на экране блокировки iOS отображается ряд баннеров, запрашивающих ответ пользователя. Чаще всего пользователь нажимает на баннер (после нажатия на кнопку "Домой") вызывает делегата центра уведомлений, когда приложение находится в фоновом режиме. Однако, случайное нажатие пользователем последнего баннера НЕ вызывает делегирование. Примечание: это НЕ вопрос о делегате, не получающем вызов БЕЗ касания пользователя: я знаю, что это невозможно сделать. Почему iOS не запускает делегат приложения время от времени, когда пользователь нажимает кнопку действия на баннере? Примечание: я отслеживаю количество ожидающих локальных уведомлений и никогда не превышаю системный лимит в 64.

Делегат приложения:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.

    UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound)
                      completionHandler:^(BOOL granted, NSError * _Nullable error) {
                          // Enable or disable features based on authorization.
                          NSUserDefaults *storage = [NSUserDefaults standardUserDefaults];
                          if(granted == YES){
                              [storage setBool:YES forKey:@"permission granted"];
                              [storage setBool:YES forKey:@"alert permission granted"];
                              [storage setBool:YES forKey:@"sound permission granted"];
                          }else{
                              NSLog(@"No permission granted");
                              [storage setBool:NO forKey:@"permission granted"];
                          };
                      }];
}

    #pragma mark UNNotificationCenter setup

    UNNotificationAction *acceptAction = [UNNotificationAction actionWithIdentifier:@"ACCEPT_IDENTIFIER" title:NSLocalizedString(@"Continue notifications", nil) options:UNNotificationActionOptionAuthenticationRequired];
    UNNotificationAction *declineAction = [UNNotificationAction actionWithIdentifier:@"DECLINE_IDENTIFIER" title:NSLocalizedString(@"Stop notifications", nil) options:UNNotificationActionOptionAuthenticationRequired];
    UNNotificationAction *doNotDisturbAction = [UNNotificationAction actionWithIdentifier:@"DO_NOT_DISTURB_IDENTIFIER" title:NSLocalizedString(@"Start Do Not Disturb", nil) options:UNNotificationActionOptionAuthenticationRequired];
    NSArray *actions = [NSArray arrayWithObjects:acceptAction, declineAction, doNotDisturbAction, nil];
   // NSArray *intentIdentifiers = [NSArray arrayWithObjects:@"none", nil];
    UNNotificationCategory *invite = [UNNotificationCategory categoryWithIdentifier:@"com.nelsoncapes.localNotification" actions:actions intentIdentifiers: @[] options:UNNotificationCategoryOptionNone];
    NSSet *categories = [NSSet setWithObjects:invite, nil];
    [center setNotificationCategories:categories];
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound)
                          completionHandler:^(BOOL granted, NSError * _Nullable error) {
                              // Enable or disable features based on authorization.
                          }];

    #pragma mark UNNotification received in background
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler{
    [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
        NSLog(@"notification settings were changed");
        NSUserDefaults *storage = [NSUserDefaults standardUserDefaults];
        [storage setBool:YES forKey:KEventLoggerEventNotificationSettingsChanged];
        [storage synchronize];

        if (settings.authorizationStatus != UNAuthorizationStatusAuthorized) {
            // Notifications not allowed
            NSLog(@"notification settings were changed");
            item.eventDescription = KEventLoggerEventNotificationsNotAllowed;

            // check settings for alert and sound
        }
       // UNNotificationSetting alertSetting = settings.alertSetting;
            if(settings.alertSetting == UNNotificationSettingEnabled){
                [storage setBool:YES forKey:@"alert permission granted"];
                item.eventDescription = KEventLoggerEventAlertsAreAllowed;
            }else{[storage setBool:NO forKey:@"alert permission granted"];
                item.eventDescription = KEventLoggerEventAlertsAreNotAllowed;
            }
            if (settings.soundSetting == UNNotificationSettingEnabled){
                [storage setBool:YES forKey:@"sound permission granted"];
                item.eventDescription = KEventLoggerEventSoundsAreAllowed;
            }else {[storage setBool:NO forKey:@"sound permission granted"];
                item.eventDescription = KEventLoggerEventSoundsAreNotAllowed;
            }

    }];
    NSLog(@"appdelegate - center didReceiveNotificationResponse");


    UNNotification *notification = response.notification;
    if([actionIdentifier isEqual:@"com.apple.UNNotificationDefaultActionIdentifier"] || [actionIdentifier isEqual:@"com.apple.UNNotificationDismissActionIdentifier"]){
    }else{


        BOOL accept = [actionIdentifier isEqual:@"ACCEPT_IDENTIFIER"];
        BOOL stop = [actionIdentifier isEqual:@"DECLINE_IDENTIFIER"];
        BOOL doNotDisturb = [actionIdentifier isEqual:@"DO_NOT_DISTURB_IDENTIFIER"];

        if (accept){NSLog(@"accept");
            [self handleAcceptActionWithNotification:notification];
        }
        else if (stop){NSLog(@"stop");
            [self handleDeclineActionWithNotification:notification];
        }
        else if(doNotDisturb) {NSLog(@"do not disturb");
            [self handleDoNotDisturbActionWithNotification:notification];
        };
    }

Контроллер просмотра:

-(UNNotificationRequest *)triggerNotifications: (NSString *)identifier : (NSTimeInterval) interval{
// Note: identifier must be unique or else each new request causes all others to be cancelled.
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.title = NSLocalizedString(@"Timer expired", nil);
content.body = NSLocalizedString(@"Touch to continue", nil);
NSUserDefaults *storage = [NSUserDefaults standardUserDefaults];
BOOL sound = [storage boolForKey:@"sound permission granted"];
if(sound){
    if([self.selectedSound isEqual:NSLocalizedString(kselectedSoundKeyDoorBell, nil)]){
        content.sound = [UNNotificationSound soundNamed:@"doorbell.caf"];
    }else if ([self.selectedSound isEqual:NSLocalizedString(kselectedSoundKeySystemDefault, nil)]){
        content.sound = [UNNotificationSound defaultSound];
    }else if ([self.selectedSound isEqual:NSLocalizedString(kselectedSoundKeyElectronicChime, nil)]){
        content.sound = [UNNotificationSound soundNamed:@"electronic_chime.caf"];
    }else{
        if([self.selectedSound isEqual:NSLocalizedString(kselectedSoundKeyComputer, nil)]){
            content.sound = [UNNotificationSound soundNamed:@"Computer.caf"];
        }
    }
}
content.categoryIdentifier = @"com.nelsoncapes.localNotification";
NSDate *today = [NSDate date];
NSDate *fireDate = [today dateByAddingTimeInterval:interval];
// first extract the various components of the date
NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger year = [calendar component:NSCalendarUnitYear fromDate:fireDate];
NSInteger month = [calendar component:NSCalendarUnitMonth fromDate:fireDate];
NSInteger day = [calendar component:NSCalendarUnitDay fromDate:fireDate];
NSInteger hour = [calendar component:NSCalendarUnitHour fromDate:fireDate];
NSInteger minute = [calendar component:NSCalendarUnitMinute fromDate:fireDate];
NSDateComponents *components = [[NSDateComponents alloc]init];
components.year = year;
components.month = month;
components.day = day;
components.hour = hour;
components.minute = minute;

// construct a calendarnotification trigger and add it to the system
UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:NO];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier: identifier content:content trigger:trigger];
[center addNotificationRequest:request withCompletionHandler:^(NSError *error){
    if(error){
    NSLog(@"error on trigger notification %@", error);
    }
}];
}

1 ответ

Я считаю, что я нашел проблему (и это в моем коде). Я дважды вызывал triggerNotification с одинаковыми компонентами даты (меня интересует только мелкая детализация, потому что я использую ее для запуска оповещения на x-й минуте). Первый вызов был, когда пользователь нажал кнопку запуска, а второй - когда applicationDidBecomeActive был вызван в делегате приложения. На самом деле, я видел дубликаты уведомлений в моей таблице. Я думаю, но не могу показать, что, когда система имеет два запроса UNNotificationRequire для тех же компонентов даты, она отвечает только на один из соответствующих баннеров оповещений. Так что, когда я нажал на последний баннер, делегат не был вызван. Я удалил второй триггер, и проблема, кажется, решена (то есть нажатие кнопки на баннере приводит к вызову моего делегата). Примечание: несмотря на то, что я дважды вызывал уведомление для одних и тех же компонентов даты, я предоставлял уникальный идентификатор в каждом запросе).

Другие вопросы по тегам