iOS 12: news in notifications

The WWDC conference was held, and there are still a lot of reports that are worth seeing. There were key themes to which Apple paid particular attention. Core ML, Siri Shortcuts and, of course, changes in Notifications.



Since not everyone has enough free time to wade through the wilds of documentation, which, as is usually the case at the beta testing stage, leaves much to be desired, I prepared a review of new features and supported the material with practical implementation. Read, be aware and embed in your applications.


Let's start with an overview of the features that Apple has added.


Notification grouping


To implement anything you do not need. iOS 12 automatically groups messages for you. But there are nuances that relate to customization, localization and grouping, but not based on the application identifier, but, for example, depending on the name of the user who sent the notification.


In addition, if you test the grouping of notifications, pay attention - they will begin to pack up only if all the notifications cannot fit on the screen at a time. For example, on the screen of the iPhone 8 for this you need to place 5 or more notifications.



In order not to overload this material, I brought the information into a separate article .


Changes to the NSExtensionContext API


The next item is new features for notifications and, in particular, the NSExtensionContext class. He is responsible for interacting with widgets, Siri, playing media content. We are more interested in notifications. Two methods and one variable were added:


var notificationActions: [UNNotificationAction] { get set } 

The variable allows you to interchange the set of available actions during the interaction with the notification:


 func dismissNotificationContentExtension() func performNotificationDefaultAction() 

Methods open the application or hide the notification.


To demonstrate the possibilities we will write a small application.


First, let's add local notifications to the application:


 let actions = [ UNNotificationAction(identifier: "like-action", title: "Like", options: []), UNNotificationAction(identifier: "open-app", title: "Open App", options: []), UNNotificationAction(identifier: "dismiss", title: "Dismiss", options: []), ] let simpleCategory = UNNotificationCategory(identifier: "category-simple", actions: actions, intentIdentifiers: [], options: []) UNUserNotificationCenter.current().setNotificationCategories([simpleCategory]) 


The second method will send a local notification after a specified period of time so that we can minimize the application or block the phone:


 UNUserNotificationCenter.current().getNotificationSettings { (settings) in guard settings.authorizationStatus == .authorized else { return } let content = UNMutableNotificationContent() content.title = "Cat Title" content.subtitle = "Cat Subtitle" content.body = "Cat Body" content.sound = .default content.categoryIdentifier = "category-simple" let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3, repeats: false) let uuid = UUID().uuidString let request = UNNotificationRequest(identifier: uuid, content: content, trigger: trigger) UNUserNotificationCenter.current().add(request, withCompletionHandler: { (error) in }) } 


Next, you need to add to the application a new target Notification Content Extension . It allows you to customize the display options for notifications and processing actions.



This will create a plist file, ViewController and Storyboard:



In the plist file we are interested in the following keys:



In the storyboard, we create a UIImageView, a UILabel to display the notification header, and a UIButton to interact with the application.



In the View Controller, we create methods to open the application and hide the notification:


 func openApp() { extensionContext?.performNotificationDefaultAction() } func dismissNotification() { extensionContext?.dismissNotificationContentExtension() } 

Implement the methods of the protocol UNNotificationContentExtension .


The first will allow you to display the required text:


 func didReceive(_ notification: UNNotification) { self.notificationTitleLabel.text = notification.request.content.body } 

The second is needed to process actions from UNNotificationAction . In the same method, substitution of actions is performed by assigning extensionContext? .NotificationActions :


 func didReceive(_ response: UNNotificationResponse, completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -> Void) { switch response.actionIdentifier { case "like-action": let actions = [ UNNotificationAction(identifier: "1-star", title: "★", options: []), UNNotificationAction(identifier: "2-star", title: "★ ★", options: []), UNNotificationAction(identifier: "3-star", title: "★ ★ ★", options: []), ] extensionContext?.notificationActions = actions case "open-app": openApp() default: dismissNotification() } } 

Processing heart strokes is performed as usual via IBAction :


 @IBAction func defaultButtonTapped(_ sender: UIButton) { openApp() } 


Run the application and see what we did:



Interaction with notification settings


The following innovation allows you to add a new menu item to the notification settings. When you tap on it, a method call will be made that you can implement in the application. For example, a user can directly get into your application from the system settings and include only those notifications that he really wants to receive. What needs to be done to implement?


First, when authorizing notifications, we add one more parameter - providesAppNotificationSettings :


 UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .sound, .providesAppNotificationSettings]) 

Second, we implement the userNotificationCenter method (_: openSettingsFor :) of the UNUserNotificationCenterDelegate protocol:


 extension AppDelegate: UNUserNotificationCenterDelegate { func userNotificationCenter(_ center: UNUserNotificationCenter, openSettingsFor notification: UNNotification?) { openSettings() } func openSettings() { let storyboard = UIStoryboard(name: "Settings", bundle: nil) let settings = storyboard.instantiateViewController(withIdentifier: "Settings") window?.rootViewController = settings } } 


Provisional Notifications


The user does not always understand whether he wants to receive notifications from your application. Therefore, when you first start the application, it is difficult for him to make such a choice. With high probability he will refuse your offer. For these situations, Apple suggests using Provisional Authorization. When requesting authorization to send notifications, one more parameter is added - provisional . authorizationStatus for such notifications also comes in an application with the provisional status.


 UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .provisional]) 

The user will not receive an authorization request when the application starts. However, in order not to disturb him, the application is placed in the so-called jail . For notifications, sounds, badges are disabled; they are displayed only in Notification Center. They will not appear on a locked screen or as banners.


When a user receives a notification, two additional buttons appear. One will completely block notifications or offer to switch to settings, and the second will translate your notifications into authorized status:



Critical alerts


Last modified adds another type of notification - Critical Alerts . These notifications completely ignore the settings of your phone, the sound turned off or the "do not disturb" mode. Apple recommends using them in medical applications (for example, the user of the device sharply jumped sugar levels), as well as to ensure the safety of users at home or in public places.


The authorization request contains a special sign:



A new item is added in the settings, and an additional icon appears on the notification screen:



To send critical notifications, you will have to go through the validation process of your application on the Apple website .


To use notifications, use the criticalAlert parameter:


 UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .criticalAlert]) 

And form the contents of the notification:


 let content = UNMutableNotificationContent() content.title = "WARNING" content.body = "Storm alert" content.categoryIdentifier = "storm-alert" content.sound = UNNotificationSound.defaultCriticalSound(withAudioVolume: 1.0) 

For Critical Alerts, you can specify the volume at which the notification will be triggered regardless of the user's settings.


I hope this material will simplify the process of introducing new notifications into your application. If it was not possible to sort out any implementation stages, I suggest reading the code on github or asking a question in the comments.


You can also see an article from e-Legion on notifications for iOS 10 or a report from the WWDC - What's new in User Notifications. We can discuss innovations at MBLT DEV 2018 in Moscow on September 28.


Have a nice day and cats all ^ _ ^


UPD: The second part of the article about the grouping of notifications is already on Habré.

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


All Articles