what's new in user notifications framework - wwdc16. meetup @wantedly with...
TRANSCRIPT
What’s New in User Notifications Framework
Masayuki Ono WWDC16. Meetup @Wantedly with
Notifications Sessions, WWDC 2016
Session 707: Introduction to Notifications
Session 708: Advanced Notifications
(Session 724: What's New in the Apple Push Notification Service)
tvOS: Session 206: What's New in tvOS watchOS: Session 211: Quick Interaction Techniques for watchOS
User Notifications frameworkSingle Notification API (UserNotifications Framework)
• Across platforms (iOS, watchOS, tvOS) • For local and remote notifications
Local notifications improvement
Notification management
In-app presentation option
Notification Extensions • Media attachments • Custom UI
User Notifications frameworkSingle Notification API (UserNotifications Framework)
• Across platforms (iOS, watchOS, tvOS)• For local and remote notifications
Local notifications improvement
Notification management
In-app presentation option
Notification Extensions • Media attachments • Custom UI
- Existing support for forwarded notifications - Local Notifications on the watch
- Support to badge app icons
Single Notification API across platforms
iOS Notifications API HistoryAPI Feature Image
iOS 7UIKit
(registerForRemoteNotificationTypes:, etc.)
- Visual alert - App icon badging - Sound and vibration - Background/Silent
notification (iOS 7)
iOS 8/9UIKit
(registerUserNotificationSettings:, registerForRemoteNotifications, etc.)
- Notification Actions (iOS 8) - Text Input Action(iOS 9)
iOS 10 UserNotifications(UI)
- Local notifications improvement
- Notification management - In-app presentation option - Notification Extensions
Local Notifications Remote Notifications
Different APIs & callbacks
UserNotifications Framework
Local Notifications
UNTimeIntervalNotificationTrigger
UNCalendarNotificationTrigger
UNLocationNotificationTrigger
Local Notifications
// Create content let content = UNMutableNotificationContent() content.title = "title" content.body = "body" content.sound = UNNotificationSound.default() // Create trigger let trigger = UNTimeIntervalNotificationTrigger(timeInterval:5, repeats: false) let identifier = "time_interval_\(NSDate())" // Create request with content and trigger let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger) // Add to notification center let center = UNUserNotificationCenter.current() center.add(request) { error in print("error: \(error)") }
Notification Handling
extension AppDelegate: UNUserNotificationCenterDelegate { // Called when the application is opened by notification func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void) { completionHandler() } // Called when the application is in foreground func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) { } }
Notification Handling
extension AppDelegate: UNUserNotificationCenterDelegate { // Called when the application is opened by notification func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void) { completionHandler() } // Called when the application is in foreground func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) { } }
Notification Handling
extension AppDelegate: UNUserNotificationCenterDelegate { // Called when the application is opened by notification func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void) { completionHandler() } // Called when the application is in foreground func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) { } }
Notification Handlingextension AppDelegate: UNUserNotificationCenterDelegate { // Called when the application is in foreground func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) { if let trigger = notification.request.trigger { switch trigger { case let n as UNPushNotificationTrigger: print("UNPushNotificationTrigger: \(n)") case let n as UNTimeIntervalNotificationTrigger: print("UNTimeIntervalNotificationTrigger: \(n)") case let n as UNCalendarNotificationTrigger: print("UNCalendarNotificationTrigger: \(n)") case let n as UNLocationNotificationTrigger: print("UNLocationNotificationTrigger: \(n)") default: assert(false) break } } }
Trigger
In-app presentation option
extension AppDelegate: UNUserNotificationCenterDelegate { // Called when the application is in foreground func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) { } }
In-app presentation option
extension AppDelegate: UNUserNotificationCenterDelegate { // Called when the application is in foreground func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) { completionHandler([.badge, .alert, .sound]) } }
Notification management
Access • Pending Notifications • Delivered Notifications
Remove Notifications
Update and promote Notifications
Remove delivered notification by identifier
Local Notifications Identifier • Set on Notification Request
let center = UNUserNotificationCenter.current() center.removeDeliveredNotifications(withIdentifiers: [“SOME_IDENTIFIER"])
Remote Notifications Identifier • HTTP/2 request header: apns-collapse-id
Notification Actions
(iOS 8) Button with customizable title
(iOS 9) Text input action
Notification Actions
Notification Actions
// Configure categories let center = UNUserNotificationCenter.current() center.delegate = self let action = UNNotificationAction(identifier: "reply", title: "Reply", options: []) let category = UNNotificationCategory(identifier: "message”, actions: [action], minimalActions: [action], intentIdentifiers: [], options: []) center.setNotificationCategories([category])
// Specify category let content = UNMutableNotificationContent() content.title = "title" content.body = "body" content.sound = UNNotificationSound.default() content.categoryIdentifier = "message"
// Configure categories let center = UNUserNotificationCenter.current() center.delegate = self let action = UNNotificationAction(identifier: "reply", title: "Reply", options: []) let category = UNNotificationCategory(identifier: "message”, actions: [action], minimalActions: [action], intentIdentifiers: [], options: [.customDismissAction]) center.setNotificationCategories([category])
// Specify category let content = UNMutableNotificationContent() content.title = "title" content.body = "body" content.sound = UNNotificationSound.default() content.categoryIdentifier = "message"
Notification Actions
Notification Actions Handling
// iOS 8/9 func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, completionHandler: () -> Void) { completionHandler() }
// iOS 10: func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void) { let identifier = response.actionIdentifier completionHandler() }
Notification Service Extension
Notification Content Extension
Notification Service ExtensionNon UI iOS Extension Augment or Replace the content of visible Remote Notifications
Extension
Notification Service ExtensionEnd-to-end encryption Media Attachments
Extension
Media Attachments
{ aps: { alert: { ... }, mutable-content: 1 } my-attachment: “https://example.com/photo.jpg” }
Notification Service Extensionclass NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? var bestAttemptContent: UNMutableNotificationContent? // Called when the notification recieved override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler:(UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) if let bestAttemptContent = bestAttemptContent { // Modify content bestAttemptContent.title = "\(bestAttemptContent.title) [modified]" contentHandler(bestAttemptContent) } } // Called when the extension time will expire override func serviceExtensionTimeWillExpire() { if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { contentHandler(bestAttemptContent) } } }
Notification Service Extensionclass NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? var bestAttemptContent: UNMutableNotificationContent? // Called when the notification recieved override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler:(UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) if let bestAttemptContent = bestAttemptContent { // Modify content bestAttemptContent.title = "\(bestAttemptContent.title) [modified]" contentHandler(bestAttemptContent) } } // Called when the extension time will expire override func serviceExtensionTimeWillExpire() { if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { contentHandler(bestAttemptContent) } } }
Notification Content Extension
Notification Content Extensionclass NotificationViewController: UIViewController, UNNotificationContentExtension { @IBOutlet var label: UILabel! override func viewDidLoad() { super.viewDidLoad() } func didReceive(_ notification: UNNotification) { self.label.text = notification.request.content.body } }
84% of devices are using iOS 9. (May 9, 2016)
https://developer.apple.com/support/app-store/
Problem: Fragmentation
iOS Notifications API HistoryAPI Feature Image
iOS 7UIKit
(registerForRemoteNotificationTypes:, etc.)
- Visual alert - App icon badging - Sound and vibration - Background/Silent
notification (iOS 7)
iOS 8/9UIKit
(registerUserNotificationSettings:, registerForRemoteNotifications, etc.)
- Notification Actions (iOS 8) - Text Input Action(iOS 9)
iOS 10 UserNotifications(UI)
- Local notifications improvement
- Notification management - In-app presentation option - Notification Extensions
How to support multiple iOS versions?
Ignore new UserNotifications APIs • No code changes are required?
Wrapper LIbraries • https://github.com/square/SuperDelegate
APNs Payload Format
{ "aps": { "alert": { "title": “Introduction to Notifications", "subtitle": “Session 707", "body": "Woah! These new notifications look amazing! Don’t you agree?" }, "badge": 1 } }
iOS 10Title
SubtitleBody
LinksWWDC
• Session 707: Introduction to Notifications
• Session 708: Advanced Notifications
• Session 724: What's New in the Apple Push Notification Service
• Session 206: What's New in tvOS (tvOS)
• Session 211: Quick Interaction Techniques for watchOS (watchOS)
Reference
• UserNotificaitons
• UserNotificationsUI
• UNNotificationServiceExtension
• UNNotificationContentExtension
Articles
• iOS User Notifications framework | | Developers.IO