IOS 10.2. UserNotifications issues for simple alert and icon

Before writing this post, I did a lot of research on the UserNotification Framework that replaced UILocalNotification in iOS 10. I also followed this guide to find out all about this new feature: http://useyourloaf.com/blog/local-notifications- with-ios-10 / .

Today I encounter such problems in order to implement such trivial notifications, and since this is a recent new feature, I could not find any solutions (especially in the C lens)! Currently, I have 2 different notifications, one Alert and one update icon .

Warning issue

Before updating my phone from iOS 10.1 to 10.2, I made a warning about Appdelegate, which starts immediately when the user closes the application manually:

-(void)applicationWillTerminate:(UIApplication *)application { NSLog(@"applicationWillTerminate"); // Notification terminate [self registerTerminateNotification]; } // Notification Background terminate -(void) registerTerminateNotification { // the center UNUserNotificationCenter * notifCenter = [UNUserNotificationCenter currentNotificationCenter]; // Content UNMutableNotificationContent *content = [UNMutableNotificationContent new]; content.title = @"Stop"; content.body = @"Application closed"; content.sound = [UNNotificationSound defaultSound]; // Trigger UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1 repeats:NO]; // Identifier NSString *identifier = @"LocalNotificationTerminate"; // création de la requête UNNotificationRequest *terminateRequest = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger]; // Ajout de la requête au center [notifCenter addNotificationRequest:terminateRequest withCompletionHandler:^(NSError * _Nullable error) { if (error != nil) { NSLog(@"Error %@: %@",identifier,error); } }]; } 

Prior to iOS 10.2, it worked perfectly when I closed the application manually, a warning appeared. But since I upgraded to iOS 10.2, nothing appears without any reason, I can’t change anything, and I don’t see what is missing.

Icon Problem

I also tried (only on iOS 10.2 this time) to implement the icons on my application icon, which worked fine until I tried to remove it. Here is the function:

 +(void) incrementBadgeIcon { // only increment if application is in background if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground){ NSLog(@"increment badge"); // notif center UNUserNotificationCenter *notifCenter = [UNUserNotificationCenter currentNotificationCenter]; // Content UNMutableNotificationContent *content = [UNMutableNotificationContent new]; content.badge = [NSNumber numberWithInt:1]; // Trigger UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1 repeats:NO]; // Identifier NSString *identifier = @"LocalNotificationIncrementBadge"; // request UNNotificationRequest *incrementBadgeRequest = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger]; // Ajout de la requête au center [notifCenter addNotificationRequest:incrementBadgeRequest withCompletionHandler:^(NSError * _Nullable error) { if (error != nil) { NSLog(@"Error %@: %@",identifier,error); } }]; } } 

Until it increments the icon number, as the name implies, but it just sets the icon number to 1. The documentation says that if you set content.badge to 0, it will remove it, but that will not work. I tried with other numbers, when I manually change it to "2", "3", etc ... it changes, but if I set it to 0, this will not work.

In addition, several functions were mentioned in the previous tutorial as getPendingNotificationRequests: completeHandler: and getDeliveredNotificationRequests: completeHandler:. I noticed that when I call these functions immediately after calling incrementBadgeIcon, if content.badge is set to "1", "2", etc., It appears in the list of pending notifications. However, when I set it to 0, it does not appear anywhere. I am not getting errors, no warnings in Xcode, and my application icon still remains.

Does anyone know how I can fix these two warnings?

thanks in advance

PS: I also tried using removeAllPendingNotificationRequests and removeAllDeliveredNotifications for both without success.

+5
source share
3 answers

Well, then I finally managed to activate these two warnings. As if posting this question on stackoverflow helped me open my mind on this issue that has been holding me back for the past few days (also these are very simple answers that are pretty shameful).

Here are my decisions if someone comes to this post.

Warning issue

For the warning that should appear when the application is closed, for example, when the application was killed by the user, when in the background, the code fragment is "correct" in general. The fact is that when appDelegate starts the applicationWillTerminate: function, the system has already started to cancel / unmount all the memory of your application. Therefore, if your application has a lot of loaded views and a lot of free data, the thread adding a notification to the center has enough time to complete this task. But if the application has only a little memory left, the notification is never added to the notification center queue.

 - (void)applicationWillTerminate:(UIApplication *)application { NSLog(@"applicationWillTerminate"); // Notification terminate [Utils closePollenNotification]; // Pause the termination thread [NSThread sleepForTimeInterval:0.1f]; } 

So, in my case, I added a simple sleep to applicationWillTerminate right after creating a notification that gives enough time to register it. (Note: I don't know if this is good practice, but it worked for me).

Icon Problem

Obviously, after a better understanding of Apple's documentation, setting content.badge to 0 does not delete the previous icon set. It simply tells the notification not to refresh the icon. To remove it, I just had to call the sharedApplication function:

 //Reset badge icon +(void) resetBadgeIcon { NSLog(@"reset badge"); // remove basge [UIApplication sharedApplication].applicationIconBadgeNumber = 0; } 

So simple.

Hope this helps someone.

+3
source

Regarding the warning:

Perhaps your application is still in the foreground when a local notification occurs, so you need to implement the delegate method so that the notification does nothing. For example, defining this method in your selector will allow the notification to display a warning, make a sound, and refresh the icon:

 func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { completionHandler([.alert,.badge,.sound]) } 

Regarding the icon:

I noticed that creating a UNMutableNotificationContent object and specifying only the icon value (as an NSNumber object) works for all icon values ​​except 0 (i.e. you cannot clear the icon this way). I have not found any documentation about why 0 will behave differently than any other value, especially since the .badge property is defined as NSNumber? , so the structure should be able to distinguish between nil (no change) and 0 (clear the icon).

I filed a radar .

As a job, I found that setting the title property in a UNMutableNotificationContent object with the icon icon NSNumber(value: 0) makes fire. If the title property is missing, it does not fire.

Adding the title property still does not present a warning to the user ( Update: this is no longer the case in iOS 11! ), So this is a way to quietly update the icon value to 0 without having to call the UIApplication object (via UIApplication.shared.applicationIconBadgeNumber = 0 ).

Here is all the code in my sample project; there MARK in the ViewController code shows where inserting the title property solves the problem:

 // // AppDelegate.swift // userNotificationZeroBadgeTest // // Created by Jeff Vautin on 1/3/17. // Copyright © 2017 Jeff Vautin. All rights reserved. // import UIKit import UserNotifications @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .sound]) { (success, error) -> Void in print("Badge auth: \(success)") } // For handling Foreground notifications, this needs to be assigned before finishing this method let vc = window?.rootViewController as! ViewController let center = UNUserNotificationCenter.current() center.delegate = vc return true } } // // ViewController.swift // userNotificationZeroBadgeTest // // Created by Jeff Vautin on 1/3/17. // Copyright © 2017 Jeff Vautin. All rights reserved. // import UIKit import UserNotifications class ViewController: UIViewController, UNUserNotificationCenterDelegate { @IBAction func start(_ sender: Any) { // Reset badge directly (this always works) UIApplication.shared.applicationIconBadgeNumber = 0 let center = UNUserNotificationCenter.current() // Schedule badge value of 1 in 5 seconds let notificationBadgeOneContent = UNMutableNotificationContent() notificationBadgeOneContent.badge = NSNumber(value: 1) let notificationBadgeOneTrigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 1*5, repeats: false) let notificationBadgeOneRequest = UNNotificationRequest.init(identifier: "1", content: notificationBadgeOneContent, trigger: notificationBadgeOneTrigger) center.add(notificationBadgeOneRequest) // Schedule badge value of 2 in 10 seconds let notificationBadgeTwoContent = UNMutableNotificationContent() notificationBadgeTwoContent.badge = NSNumber(value: 2) let notificationBadgeTwoTrigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 2*5, repeats: false) let notificationBadgeTwoRequest = UNNotificationRequest.init(identifier: "2", content: notificationBadgeTwoContent, trigger: notificationBadgeTwoTrigger) center.add(notificationBadgeTwoRequest) // Schedule badge value of 3 in 15 seconds let notificationBadgeThreeContent = UNMutableNotificationContent() notificationBadgeThreeContent.badge = NSNumber(value: 3) let notificationBadgeThreeTrigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 3*5, repeats: false) let notificationBadgeThreeRequest = UNNotificationRequest.init(identifier: "3", content: notificationBadgeThreeContent, trigger: notificationBadgeThreeTrigger) center.add(notificationBadgeThreeRequest) // Schedule badge value of 4 in 20 seconds let notificationBadgeFourContent = UNMutableNotificationContent() notificationBadgeFourContent.badge = NSNumber(value: 4) let notificationBadgeFourTrigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 4*5, repeats: false) let notificationBadgeFourRequest = UNNotificationRequest.init(identifier: "4", content: notificationBadgeFourContent, trigger: notificationBadgeFourTrigger) center.add(notificationBadgeFourRequest) // Schedule badge value of 0 in 25 seconds let notificationBadgeZeroContent = UNMutableNotificationContent() // MARK: Uncommenting this line setting title property will cause notification to fire properly. //notificationBadgeZeroContent.title = "Zero!" notificationBadgeZeroContent.badge = NSNumber(value: 0) let notificationBadgeZeroTrigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 5*5, repeats: false) let notificationBadgeZeroRequest = UNNotificationRequest.init(identifier: "0", content: notificationBadgeZeroContent, trigger: notificationBadgeZeroTrigger) center.add(notificationBadgeZeroRequest) } @IBAction func listNotifications(_ sender: Any) { let center = UNUserNotificationCenter.current() center.getDeliveredNotifications() { (notificationArray) -> Void in print("Delivered notifications: \(notificationArray)") } center.getPendingNotificationRequests() { (notificationArray) -> Void in print("Pending notifications: \(notificationArray)") } } // MARK: UNUserNotificationCenterDelegate func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { print("Received notification: \(notification)") completionHandler([.alert,.badge,.sound]) } } 
+3
source

This fix for the problem with the OP icon describes (but not the problem with the warning).

Step 1: Send a notification using the icon = negative 1

In your UNMutableNotificationContent, set content.badge = @-1 instead of 0. This has 2 advantages:

  • unlike 0, -1 actually clears the icon (if you also do step 2)
  • Unlike [UIApplication sharedApplication].applicationIconBadgeNumber = 0 it will not clear notifications from your application in the notification center.

Step 2: Implement UNUserNotificationCenterDelegate

You will need to implement UNUserNotificationCenterDelegate and do the following:

  • Add the willPresentNotification method to your delegate and call completionHandler(UNNotificationPresentationOptionBadge) in the body. Note. I check the request identifier and call UNNotificationPresentationOptionNone by default, unless it is specifically a notification designed to clear the icon.
  • Remember to save the delegate instance somewhere with a strong pointer. The notification center does not support a strong pointer.

After these 2 changes, you can clear the icon again with a local notification.

+1
source

Source: https://habr.com/ru/post/1261462/


All Articles