当应用程序在后台 iOS 11 中时,UNNotification 本地通知用户点击不会触发委托

Posted

技术标签:

【中文标题】当应用程序在后台 iOS 11 中时,UNNotification 本地通知用户点击不会触发委托【英文标题】:UNNotification local notification user tap does not trigger delegate when app in background iOS 11 【发布时间】:2018-06-02 16:29:44 【问题描述】:

我有一个应用程序通过 UNNotification 本地通知每隔 x 分钟提醒用户一次。如果用户没有响应,ios 锁定屏幕会显示一系列横幅,要求用户响应。大多数情况下,当应用程序处于后台时,用户点击横幅(点击主页按钮后)会触发 UNNotification 中心委托。但是,有时用户点击最新横幅不会触发委托。注意:这不是关于代表在没有用户点击的情况下未接听电话的问题:我知道这是不可能的。当用户点击横幅中的操作按钮时,为什么 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);
    
];

【问题讨论】:

也许您的应用程序不再运行。您应该检查didFinishLaunching 中的options 以确定它是否是通过通知点击启动的。 Paulw11:这是可能的,但我无法让 iOS 在应用程序委托中调用 applicationWillTerminate 以测试这种可能性(当我从 xcode 停止应用程序时不会调用)。 不,那是硬杀。 applicationWillTerminate 在该实例中未被调用 【参考方案1】:

我相信我发现了问题(并且在我的代码中)。我使用相同的日期组件调用了 triggerNotification 两次(我只对分钟粒度感兴趣,因为我使用它在第 x 分钟触发警报)。第一次调用是在用户按下开始按钮时,第二次调用是在应用程序委托中调用 applicationDidBecomeActive 时。事实上,我确实在我的表格中看到了重复的通知。我认为,但不能表明,当系统有两个 UNNotificationRequests 等待相同的日期组件时,它只响应相应的警报横幅之一。所以,当我点击最新的横幅时,没有叫到代表。我删除了第二个触发器,问题似乎得到了解决(即,点击横幅中的按钮会导致呼叫我的代表)。注意:即使我为相同的日期组件触发了两次通知,但我确实在每个请求中提供了一个唯一标识符。

【讨论】:

以上是关于当应用程序在后台 iOS 11 中时,UNNotification 本地通知用户点击不会触发委托的主要内容,如果未能解决你的问题,请参考以下文章

当应用程序在前台 iOS 中时,未在通知托盘(顶部)中获取推送通知

当键盘出现在 iOS 中时启用滚动内容

当应用程序处于后台 FCM 中时更新 Web 应用程序用户界面

当应用程序在 iOS 11.4.1 中处于后台时,静默通知不起作用

蓝牙设备连接时 iOS Core 蓝牙通知应用

当图像在模态div中时,IOS长按没有“保存图像”选项