Download - New Notification API in iOS 10
Copyright © Up-frontier, Inc. All rights reserved.
アジェンダ• 新 API でローカル通知
• Media Attachment
• Notification Content Extension
• Notification Service Extension
2
Copyright © Up-frontier, Inc. All rights reserved.
アジェンダ• 新 API でローカル通知
• Media Attachment
• Notification Content Extension
• Notification Service Extension
3
Copyright © Up-frontier, Inc. All rights reserved.
ローカル通知⽅法1. コンテンツを作って
2. トリガーを設定して
3. センターにリクエスト
4
Copyright © Up-frontier, Inc. All rights reserved.
ローカル通知⽅法1. コンテンツを作って
2. トリガーを設定して
3. センターにリクエスト
5
Copyright © Up-frontier, Inc. All rights reserved.
コンテンツlet content = UNMutableNotificationContent() content.title = "Title" content.subtitle = "Subtitle" content.body = "Body" content.categoryIdentifier = "sample-category"
6
Copyright © Up-frontier, Inc. All rights reserved.
コンテンツlet content = UNMutableNotificationContent() content.title = "Title" content.subtitle = "Subtitle" content.body = "Body" content.categoryIdentifier = "sample-category"
7
Copyright © Up-frontier, Inc. All rights reserved.
コンテンツlet content = UNMutableNotificationContent() content.title = "Title" content.subtitle = "Subtitle" content.body = "Body" content.categoryIdentifier = "sample-category"
8
Action や、カスタム UI など 識別に使⽤
Copyright © Up-frontier, Inc. All rights reserved.
ローカル通知⽅法1. コンテンツを作って
2. トリガーを設定して
3. センターにリクエスト
9
Copyright © Up-frontier, Inc. All rights reserved.
トリガーUNNotificationTrigger
11
let intervalTrigger = UNTimeIntervalNotificationTrigger( timeInterval: 5, repeats: false)
Copyright © Up-frontier, Inc. All rights reserved.
リクエストlet id = "sample-\(Date().timeIntervalSince1970)"
let request = UNNotificationRequest( identifier: id, content: content, trigger: intervalTrigger
) center.add(request) { error in
if let error = error { print("Error on requesting notification: \(error)")
} print("Finish requesting notification: \(id)")
}
12
Copyright © Up-frontier, Inc. All rights reserved.
リクエストlet id = "sample-\(Date().timeIntervalSince1970)"
let request = UNNotificationRequest( identifier: id, content: content, trigger: intervalTrigger
) center.add(request) { error in
if let error = error { print("Error on requesting notification: \(error)")
} print("Finish requesting notification: \(id)")
}
13
トリガのセット
Copyright © Up-frontier, Inc. All rights reserved.
リクエストlet id = "sample-\(Date().timeIntervalSince1970)"
let request = UNNotificationRequest( identifier: id, content: content, trigger: intervalTrigger
) center.add(request) { error in
if let error = error { print("Error on requesting notification: \(error)")
} print("Finish requesting notification: \(id)")
}
14
identifier: 識別⼦、更新・削除に利⽤ contents: 通知本体
trigger: 発⽕タイミング
Copyright © Up-frontier, Inc. All rights reserved.
リクエストlet id = "sample-\(Date().timeIntervalSince1970)"
let request = UNNotificationRequest( identifier: id, content: content, trigger: intervalTrigger
) center.add(request) { error in
if let error = error { print("Error on requesting notification: \(error)")
} print("Finish requesting notification: \(id)")
}
15
Notification Centerに追加で完了
Copyright © Up-frontier, Inc. All rights reserved.
アジェンダ• 新 API でローカル通知
• Media Attachment
• Notification Content Extension
• Notification Service Extension
16
Copyright © Up-frontier, Inc. All rights reserved.
メディア1. 通知内容を作って
2. トリガーを設定して
3. センターにリクエスト
21
ここで設定する
Copyright © Up-frontier, Inc. All rights reserved.
UNNotificationAttachment guard let imageURL = R.file.sampleJpg() else {
print("Could not instantiate file URL!”) return
} let content = defaultContent do {
let attachment = try UNNotificationAttachment( identifier: "sample-cat", url: imageURL, options: nil
) content.attachments = [attachment]
} catch(let error) { print("Could not instantiate attachment: \(error)")
}
22
Copyright © Up-frontier, Inc. All rights reserved.
UNNotificationAttachment guard let imageURL = R.file.sampleJpg() else {
print("Could not instantiate file URL!”) return
} let content = defaultContent do {
let attachment = try UNNotificationAttachment( identifier: "sample-cat", url: imageURL, options: nil
) content.attachments = [attachment]
} catch(let error) { print("Could not instantiate attachment: \(error)")
}
23
画像の設定 UNNotificationAttachmentを使う
Copyright © Up-frontier, Inc. All rights reserved.
UNNotificationAttachment guard let imageURL = R.file.sampleJpg() else {
print("Could not instantiate file URL!”) return
} let content = defaultContent do {
let attachment = try UNNotificationAttachment( identifier: "sample-cat", url: imageURL, options: nil
) content.attachments = [attachment]
} catch(let error) { print("Could not instantiate attachment: \(error)")
}
24
コンテンツに指定
Copyright © Up-frontier, Inc. All rights reserved.
アジェンダ• 新 API でローカル通知
• Media Attachment
• Notification Content Extension
• Notification Service Extension
25
Copyright © Up-frontier, Inc. All rights reserved.
Notification Content Extension
• オリジナルUIの通知を作成する
26
Copyright © Up-frontier, Inc. All rights reserved.
NotificationViewControllerclass NotificationViewController : UIViewController , UNNotificationContentExtension { @IBOutlet weak var mapView: MKMapView! override func viewDidLoad() { super.viewDidLoad() } func didReceive(_ notification: UNNotification) { let content = notification.request.content if let lat = content.userInfo["latitude"] as? Double, let lon = content.userInfo["longitude"] as? Double { putPin(into: CLLocationCoordinate2D(latitude: lat, longitude: lon)) } } }
29
Copyright © Up-frontier, Inc. All rights reserved.
NotificationViewControllerclass NotificationViewController : UIViewController , UNNotificationContentExtension { @IBOutlet weak var mapView: MKMapView! override func viewDidLoad() { super.viewDidLoad() } func didReceive(_ notification: UNNotification) { let content = notification.request.content if let lat = content.userInfo["latitude"] as? Double, let lon = content.userInfo["longitude"] as? Double { putPin(into: CLLocationCoordinate2D(latitude: lat, longitude: lon)) } } }
30
MapViewを持った通知
Copyright © Up-frontier, Inc. All rights reserved.
NotificationViewControllerclass NotificationViewController : UIViewController , UNNotificationContentExtension { @IBOutlet weak var mapView: MKMapView! override func viewDidLoad() { super.viewDidLoad() } func didReceive(_ notification: UNNotification) { let content = notification.request.content if let lat = content.userInfo["latitude"] as? Double, let lon = content.userInfo["longitude"] as? Double { putPin(into: CLLocationCoordinate2D(latitude: lat, longitude: lon)) } } }
31
通知が発⽕した時の処理
Copyright © Up-frontier, Inc. All rights reserved.
NotificationViewControllerclass NotificationViewController : UIViewController , UNNotificationContentExtension { @IBOutlet weak var mapView: MKMapView! override func viewDidLoad() { super.viewDidLoad() } func didReceive(_ notification: UNNotification) { let content = notification.request.content if let lat = content.userInfo["latitude"] as? Double, let lon = content.userInfo["longitude"] as? Double { putPin(into: CLLocationCoordinate2D(latitude: lat, longitude: lon)) } } }
32
通知が発⽕した時の処理
通知内容を反映
Copyright © Up-frontier, Inc. All rights reserved.
Info.plist
<dict> <key>NSExtensionAttributes</key> <dict> <key>UNNotificationExtensionCategory</key> <array> <string>customUI</string>
</array> <key>UNNotificationExtensionInitialContentSizeRatio</key> <real>1</real> <key>UNNotificationExtensionDefaultContentHidden</key> <true/>
</dict> <key>NSExtensionMainStoryboard</key> <string>MainInterface</string> <key>NSExtensionPointIdentifier</key> <string>com.apple.usernotifications.content-extension</string>
</dict> 33
Copyright © Up-frontier, Inc. All rights reserved.
Info.plist
<dict> <key>NSExtensionAttributes</key> <dict> <key>UNNotificationExtensionCategory</key> <array> <string>customUI</string>
</array> <key>UNNotificationExtensionInitialContentSizeRatio</key> <real>1</real> <key>UNNotificationExtensionDefaultContentHidden</key> <true/>
</dict> <key>NSExtensionMainStoryboard</key> <string>MainInterface</string> <key>NSExtensionPointIdentifier</key> <string>com.apple.usernotifications.content-extension</string>
</dict> 34
categoryIdentifierと ⼀致している必要あり
Copyright © Up-frontier, Inc. All rights reserved.
Info.plist
<dict> <key>NSExtensionAttributes</key> <dict> <key>UNNotificationExtensionCategory</key> <array> <string>customUI</string>
</array> <key>UNNotificationExtensionInitialContentSizeRatio</key> <real>1</real> <key>UNNotificationExtensionDefaultContentHidden</key> <true/>
</dict> <key>NSExtensionMainStoryboard</key> <string>MainInterface</string> <key>NSExtensionPointIdentifier</key> <string>com.apple.usernotifications.content-extension</string>
</dict> 35
UIの縦横⽐
Copyright © Up-frontier, Inc. All rights reserved.
Info.plist
<dict> <key>NSExtensionAttributes</key> <dict> <key>UNNotificationExtensionCategory</key> <array> <string>customUI</string>
</array> <key>UNNotificationExtensionInitialContentSizeRatio</key> <real>1</real> <key>UNNotificationExtensionDefaultContentHidden</key> <true/>
</dict> <key>NSExtensionMainStoryboard</key> <string>MainInterface</string> <key>NSExtensionPointIdentifier</key> <string>com.apple.usernotifications.content-extension</string>
</dict> 36
デフォルトのタイトル、サブタイトル、コンテンツ
Copyright © Up-frontier, Inc. All rights reserved.
アジェンダ• 新 API でローカル通知
• Media Attachment
• Notification Content Extension
• Notification Service Extension
37
Copyright © Up-frontier, Inc. All rights reserved.
Notification Service Extension
• オリジナルUIの通知を作成する
38
Copyright © Up-frontier, Inc. All rights reserved.
NotificationServiceclass NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? var bestAttemptContent: UNMutableNotificationContent? override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) if let bestAttemptContent = bestAttemptContent {
// Modify the notification content here... bestAttemptContent.title = "\(bestAttemptContent.title) [modified]" contentHandler(bestAttemptContent) } } override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, // otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
bestAttemptContent.title = "\(bestAttemptContent.title) [Time Expired]" contentHandler(bestAttemptContent) } } }
40
Copyright © Up-frontier, Inc. All rights reserved.
NotificationServiceclass NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? var bestAttemptContent: UNMutableNotificationContent? override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) if let bestAttemptContent = bestAttemptContent {
// Modify the notification content here... bestAttemptContent.title = "\(bestAttemptContent.title) [modified]" contentHandler(bestAttemptContent) } } override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, // otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
bestAttemptContent.title = "\(bestAttemptContent.title) [Time Expired]" contentHandler(bestAttemptContent) } } }
41
通知内容を編集
Copyright © Up-frontier, Inc. All rights reserved.
NotificationServiceclass NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? var bestAttemptContent: UNMutableNotificationContent? override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) if let bestAttemptContent = bestAttemptContent {
// Modify the notification content here... bestAttemptContent.title = "\(bestAttemptContent.title) [modified]" contentHandler(bestAttemptContent) } } override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, // otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
bestAttemptContent.title = "\(bestAttemptContent.title) [Time Expired]" contentHandler(bestAttemptContent) } } }
42
処理が既定秒数(MAX30秒)を超えると呼ばれる
Copyright © Up-frontier, Inc. All rights reserved.
NotificationServiceclass NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? var bestAttemptContent: UNMutableNotificationContent? override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) if let bestAttemptContent = bestAttemptContent {
// Modify the notification content here... bestAttemptContent.title = "\(bestAttemptContent.title) [modified]" contentHandler(bestAttemptContent) } } override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, // otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
bestAttemptContent.title = "\(bestAttemptContent.title) [Time Expired]" contentHandler(bestAttemptContent) } } }
43
サーバからのリモートプッシュを変更する場合 mutable-contetの設定忘れないように
Copyright © Up-frontier, Inc. All rights reserved.
NotificationServiceclass NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? var bestAttemptContent: UNMutableNotificationContent? override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) if let bestAttemptContent = bestAttemptContent {
// Modify the notification content here... bestAttemptContent.title = "\(bestAttemptContent.title) [modified]" contentHandler(bestAttemptContent) } } override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, // otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
bestAttemptContent.title = "\(bestAttemptContent.title) [Time Expired]" contentHandler(bestAttemptContent) } } }
44
処理が終わったら速やかに呼ぶ
Copyright © Up-frontier, Inc. All rights reserved.
ありそうな使い⽅• ペイロードにサーバにあるメディアの URL
• ダウンロードして
• Media Attachment
45
Copyright © Up-frontier, Inc. All rights reserved.
リモートコンテンツ 貼り付け
if let bestAttemptContent = bestAttemptContent { guard let urlString = bestAttemptContent.userInfo["remote-url"] as? String, let remoteURL = URL(string: urlString) else { contentHandler(bestAttemptContent) return } download(remoteURL) { url, error in guard let fileURL = url else { print(error) contentHandler(bestAttemptContent) return } do { let attachment = try UNNotificationAttachment( identifier: "remote", url: fileURL ) bestAttemptContent.attachments = [attachment] contentHandler(bestAttemptContent) } catch(let e) { print(e) contentHandler(bestAttemptContent) } } }
46
Copyright © Up-frontier, Inc. All rights reserved.
リモートコンテンツ 貼り付け
if let bestAttemptContent = bestAttemptContent { guard let urlString = bestAttemptContent.userInfo["remote-url"] as? String, let remoteURL = URL(string: urlString) else { contentHandler(bestAttemptContent) return } download(remoteURL) { url, error in guard let fileURL = url else { print(error) contentHandler(bestAttemptContent) return } do { let attachment = try UNNotificationAttachment( identifier: "remote", url: fileURL ) bestAttemptContent.attachments = [attachment] contentHandler(bestAttemptContent) } catch(let e) { print(e) contentHandler(bestAttemptContent) } } }
47
画像のダウンロード 30秒超えるかも
Copyright © Up-frontier, Inc. All rights reserved.
serviceExtensionTimeWillExpireoverride func serviceExtensionTimeWillExpire() { if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { bestAttemptContent.title += " [頑張ったけれどダメだったよ]" contentHandler(bestAttemptContent) } }
48
Copyright © Up-frontier, Inc. All rights reserved.
serviceExtensionTimeWillExpireoverride func serviceExtensionTimeWillExpire() { if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { bestAttemptContent.title += " [頑張ったけれどダメだったよ]" contentHandler(bestAttemptContent) } }
49
サーバからのリモートプッシュの内容を 変更しない場合
もとのペイロードのまま表⽰されてしまうので注意