そういえば1ヶ月ほどブログの更新止めちゃってました。お久しぶりです。
WWDC2016の発表を現地…ではなくweb上で色々情報をキャッチアップしてて、その中で 「UserNotifications Framework」 が気になったのでざっくり触ってみました。
今回は、通知(ローカル通知)にattachmentで任意の画像や動画を付けられるようなのでそれを試してみました。

実行環境

  • Xcode8 beta (Swift 3.0 preview-1)

情報としては、Apple Developerで公開されている情報を基にしています。
また、まだBeta段階ですので、今後変わる可能性はあります。スクリーンショットは掲載しておりません。

通知に画像を付けてみる

例えば、Project内に追加した、 “img.png” という画像を通知に付加してみます。

contentを作成する

まず、通知の内容を決める、contentを作成します。
contentは、UNMutableNotificationContentという型になっています。ちなみに、UNNotificationContentは基本的には直接インスタンスを作ることはせず、
このUNMutableNotificationContentを使います。

let content = UNMutableNotificationContent()
content.title = "SampleNotification"
content.body = "!!!"
content.badge = 1
content.sound = UNNotificationSound.default()

こんな感じで、title、body,badge,soundを必要に応じてセットします。

attachmentを作成する

次に、先ほど作ったcontentに登録するattachmentを作成します。
作成したあとは、content.attachmentsに代入します。
attachmentの型は、UNNotificationAttachmentです。

// attachmentの追加
let attachmentIdentifier = "SampleAttachment"
if let
    url = Bundle.main().urlForResource("img", withExtension: "png"),
    attachment = try? UNNotificationAttachment(identifier: attachmentIdentifier, url: url, options: nil)
{
    content.attachments = [attachment]
}

ここでは、try?を使って、UNNotificationAttachmentのイニシャライザの返すエラーを流していますが、必要があればtryでキャッチすると良いでしょう。
また、地味にSwift3.0からは、NSURL→ URL 、NSBundle→ Bundle に変わっているので注意です。
ちなみに、ここで指定できるのはfileURLとなっているので、ダウンロードして表示…ということはできないようです。

triggerを指定する

通知を発火する条件(trigger)を作成します。

let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3, repeats: false)

ここでは 3 秒後に発火するようにします。

NotificationCenterにaddする

ここまできたら、UNNotificationRequest型のrequestを追加し、UNUserNotificationCenterにrequestを追加します。

let requestIdentifier = "SampleNotificationRequest"
let request = UNNotificationRequest(identifier: requestIdentifier,
                                    content: content,
                                    trigger: trigger)

// 通知の登録
UNUserNotificationCenter.current().add(request) { _ in
}

実行してみる

実行してみると、3秒後に通知が発火し、通知バナーに設定したcontentが表示されます。
画像は右側にサムネイルとして小さく表示されます。
通知バナーを下にスワイプするか、長押しすることで、画像を大きく見ることができます。
(まだbetaなので、スクショは貼らないでおきます。)

また、 動画 を指定することもでき、動画の場合は

  • 通知に表示するサムネイルの画像を動画のどの部分を使うかの指定
  • 通知を長押し大きく表示した状態で、動画を再生

が可能です。

attachmentのオプション

オプションは4つあり、UNNotificationAttachmentのイニシャライザに、optionsとして[String: AnyObject]型で渡して指定することができます。
もちろんnilでも問題ありません。

  • UNNotificationAttachmentOptionsTypeHintKey
    →attachmentのタイプを指定することができます。指定しない場合は、URLで渡すfileURLのextensionから判断します。

  • UNNotificationAttachmentOptionsThumbnailHiddenKey
    →通知バナーに出るサムネイルを非表示にするかどうか指定できます。指定しない場合はhidden=NOとなります。

  • UNNotificationAttachmentOptionsThumbnailClippingRectKey
    →attachmentのサムネイルのクリップ領域を指定できます

  • UNNotificationAttachmentOptionsThumbnailTimeKey
    →動画のどの部分をサムネイルにするか、時間を指定します。

さいごに

ここまでをまとめたソースを以下に貼り付けます。
そのまま実行できるようにしてあります。

import Foundation
import UIKit
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        let options: UNAuthorizationOptions = [.alert, .badge, .sound]
        // 通知を許可するかどうかのアラートを出す
        UNUserNotificationCenter.current().requestAuthorization(options) { granted, error in
            if granted {
                // ...
            }
        }

        //デリゲートの登録
        UNUserNotificationCenter.current().delegate = self

        // 通知用のcontentの作成
        let content = UNMutableNotificationContent()
        content.title = "Sample Notification"
        content.body = "!!!"
        content.badge = 1
        content.sound = UNNotificationSound.default()

        // attachmentの追加
        let attachmentIdentifier = "SampleAttachment"
        if let
            url = Bundle.main().urlForResource("img", withExtension: "png"),
            attachment = try? UNNotificationAttachment(identifier: attachmentIdentifier, url: url, options: nil)
        {
            content.attachments = [attachment]
        }

        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3, repeats: false)
        let requestIdentifier = "SampleNotificationRequest"
        let request = UNNotificationRequest(identifier: requestIdentifier,
                                            content: content,
                                            trigger: trigger)

        // 通知の登録
        UNUserNotificationCenter.current().add(request) { _ in
        }
        return true
    }
}

// MARK: - UNUserNotificationCenterDelegate
extension AppDelegate: UNUserNotificationCenterDelegate {
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) {
        // フォアグラウンドでも通知バナーを出す
        completionHandler([.alert, .sound, .badge])
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void) {
        completionHandler()
    }
}

余談

Advanced Notifications見ててExtension試してみたくなった…。
(おそらく)、サーバーから受け取るpayloadに関してextensionをかますことができて

  • payloadから通知を発行するときのカスタムServiceExtensionの作成
  • カスタムなNotification UIの作成

ができるようなので、iOS10標準のカレンダーアプリやマップ、メッセージアプリのような事もできそうだし、
カスタムServiceExtensionならwebから画像をダウンロードしてローカルに保存してからattachmentに指定できそう?だし、やれる幅は広がりそう。。 FireBaseあたり登録して、試してみたいところ。