UNNotification не работает под iOS 10.3.3

Я много искал, чтобы попытаться найти конкретное решение этой проблемы. У меня есть приложение, которое использует прежнюю систему UILocalNotification для отправки локальных уведомлений, и это все еще прекрасно работает под iOS 10.3.3. Тем не менее, я попытался преобразовать это в новую систему UNNotification, потому что прежняя система устарела. Независимо от того, пытаюсь ли я использовать UNCalendarNotificationTrigger или UNTimeIntervalNotificationTrigger, делегат не получает вызов. Вот код для запуска viewcontroller.

if (isItTime){
    NSCalendar *currentCalendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
    [currentCalendar setTimeZone:[NSTimeZone localTimeZone]];
    NSDateComponents *components = [currentCalendar components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitTimeZone fromDate:[now dateByAddingTimeInterval:30]];
   // components.second = 0;
    NSLog(@"trigger components: %@", components);
    UNCalendarNotificationTrigger* trigger = [UNCalendarNotificationTrigger
                                             triggerWithDateMatchingComponents:components repeats:NO];
    UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"invite" content:content trigger:trigger];
    [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
        if (error != nil) {
            NSLog(@"Something went wrong: %@",error);
        }
    }];
    [self.currentLocalNotificationRequests addObject:request];
    return  request;
}else{
    return nil;
}

А вот код для делегата (appdelegate) didFinishLaunching:

- (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.
                          NSLog(@"_prefix:set($class $method $line)");
                          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"];
                          };
                      }];

Код приложения для получения уведомлений:

    - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler{
    NSLog(@"appdelegate - center didReceiveNotificationResponse");
    NSString *actionIdentifier = response.actionIdentifier;
    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];
        };
    }
    completionHandler();
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
    NSLog(@"appdelegate willPresentNotification");
    UNNotificationRequest * request = notification.request;
    NSString * actionIdentifier = request.identifier;
    if([actionIdentifier isEqualToString:UNNotificationDismissActionIdentifier] || [actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier]){
    }else{
        if([actionIdentifier isEqualToString:@"invite"]){
            NSLog(@"app delegate notification received while in foreground");
        }
    }
    completionHandler(UNNotificationPresentationOptionAlert + UNNotificationPresentationOptionSound);

}

Вот NSLog запускающего кода:

<NSDateComponents: 0x146d51c0>
TimeZone: America/Chicago (CDT) offset -18000 (Daylight)
Calendar Year: 2017
Month: 10
Leap month: no
Day: 29
Hour: 14
Minute: 3
Second: 4

Очень ясно, что методы appdelegate не вызываются системой (я поместил приложение в фоновом режиме до времени уведомления, поэтому должен был быть вызван метод didReceiveNotification.

Если кто-то может помочь, я был бы признателен!

Также этот код в viewDidLoad:

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(receiveNotificationFromAppDelegate:)
                                                 name:kAppDelegateNotification
                                               object:nil];

    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(applicationBecameActive) name:UIApplicationDidBecomeActiveNotification object:nil];
    self.currentLocalNotificationRequests = [[NSMutableArray alloc]init];
/*
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkDndIndicator) name:UIApplicationDidBecomeActiveNotification object:nil];
 */
    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.
                              NSLog(@"request granted");
                          }];

И код для запуска процесса запуска:

    -(UNNotificationRequest *)startLocalNotification:(NSDate *)fireDate :
(NSMutableDictionary *)userInfo{
    NSUserDefaults *storage = [NSUserDefaults standardUserDefaults];
    UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
    [center removeAllPendingNotificationRequests];
    UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
    content.title = NSLocalizedString(@"TimeChime Alert", nil);
    content.body = NSLocalizedString(@"Click to Stop or Change Timer",nil);
    content.categoryIdentifier = @"com.nelsoncapes.localNotification";

2 ответа

Оказывается, эта проблема неясна, но ее легко исправить. К сожалению, я не очень тщательно следовал первому правилу кодирования: RTFD.

Документация Apple для идентификатора UNNotificationRequest> гласит:

"Если вы используете тот же идентификатор при планировании нового уведомления, система удаляет ранее запланированное уведомление с этим идентификатором и заменяет его новым".

Мой код использовал один и тот же идентификатор для каждого запроса UNNotificationRequest. Хотя дата уведомления в календаре для каждого запроса была разной, система сохраняла только последний запрос. В моем случае, курок сработал бы через 1 час, и я ожидал, что он сработает через 15 минут. Вот почему я никогда не видел уведомления на устройстве и почему я никогда не видел точку останова в методе didReceiveNotificationResponse делегата.

Исправить это очень легко. Просто введите уникальный идентификатор в следующем коде. После этого код работает.

UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"invite" content:content trigger:trigger];

Замените @"пригласить" уникальным идентификатором для каждого запроса.

Я не получал свое уведомление, потому что я не указал необходимые компоненты даты для передачи в мой UNCalendarNotificationTrigger.

Это не работает:

      NSDateComponents *dateComponents = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour) fromDate:[[NSDate date] dateByAddingTimeInterval:5]];

Это работает:

      NSDateComponents *dateComponents = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitNanosecond) fromDate:[[NSDate date] dateByAddingTimeInterval:5]];
Другие вопросы по тегам