iOS10のリッチ通知で動画を動的に配信すると音が出ない件

[このブログ](http://bhind.site/info/2744/)のコピーです。

## 概要
iOS10からリッチ通知機能のひとつとして[メディア添付](http://qiita.com/himara2/items/dcfcc30b550c3304d86a)ができるようになりました。
そこで実際に動画や音声を動的（main bundleに入れずに通知時にダウンロードする方法）でやってみたところ思わぬ制限がありました。
iOS開発では当たり前なのかもしれませんが、ドキュメントにも見つけられなかったのでまとめました。

## 環境
- macOS Sierra 10.12.3
- Xcode 8.2.1
- iOS 10

## やったこと
カスタムペイロード（キーは決め打ち）にメディアのURLを入れてリモートPushし、通知を受信したタイミングでダウンロード、再生までをやりました。

## コード
実は意外とめんどい。
まずはNotification Service Extensionを作成するためにProvisioning Profileを作成します。（アプリ側とは別に）
作成したらXcodeのメニュー[File]-[New]-[Target]から[Notification Service Extension]を選択し[Next]、new targetのなんやかんやを設定し、[Finish]（さっきのProvisioning Profileとか）

```swift:NotificationServiceExtension.swift
import UserNotifications

class NotificationService: UNNotificationServiceExtension {

    let IMAGE_URL_KEY = "image_url"
    let MOVIE_URL_KEY = "movie_url"
    
    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 imageUrl: String = request.content.userInfo[self.MOVIE_URL_KEY] as! String? {
            let session = URLSession(configuration: URLSessionConfiguration.default)
            let task = session.dataTask(with: URL(string: imageUrl)!, completionHandler: {[weak self](data, response, error) in
                do {
                    if let writePath = NSURL(fileURLWithPath:  NSTemporaryDirectory())
                        .appendingPathComponent("tmp.mp4") {
                        try data?.write(to: writePath)
                        let identifier = "XXXX"
                        if let bestAttemptContent = self?.bestAttemptContent {
                            let attachment = try UNNotificationAttachment(identifier: identifier, url: writePath, options: nil)
                            bestAttemptContent.attachments = [attachment]
                            contentHandler(bestAttemptContent)
                            return
                        }
                    } else {
                        if let bestAttemptContent = self?.bestAttemptContent {
                            bestAttemptContent.title = "\(bestAttemptContent.title) [URL不正]"
                            contentHandler(bestAttemptContent)
                        }
                    }
                } catch let error as NSError {
                    NSLog(error.localizedDescription)
                    if let bestAttemptContent = self?.bestAttemptContent {
                        bestAttemptContent.title = "\(bestAttemptContent.title) [ダウンロード失敗]"
                        contentHandler(bestAttemptContent)
                    }
                }
            })
            task.resume()
        } else {
            if let bestAttemptContent = bestAttemptContent {
                bestAttemptContent.title = "\(bestAttemptContent.title) [image_url取得失敗]"
                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 {
            contentHandler(bestAttemptContent)
        }
    }

}
```

## 結果
mutable-contentを1、カスタムペイロードとして、movie_urlにmp4ファイルを指定してPush通知すると動画が再生できます… **音声が無ければ** 
確認してみたところ…
- ダウンロードした音なし動画→再生可能
- ダウンロードした音あり動画→ **再生不可**
- ダウンロードした音声→ **再生不可**
- main bundleに置いた音なし動画→再生可能
- main bundleに置いた音あり動画→再生可能
- main bundleに置いた音声→再生可能
となりました。
[Soundペイロードの件](http://qiita.com/bhind13/items/2db6b9d26f67e1abc7c5)があったので、もしかすると音声はLibrary/Sounds配下に置けばダウンロードでも再生できるのかな…と思ったけど試してません。

## ハマったこと・課題など
- エラーが起きても通知処理自体は何食わぬ顔で処理されるので最初、動画形式が悪いのかとか全然ちがうところを調べてたorz
- エラーがExtensionが異常終了みたいな出方しかしないし。

## github
なし

## 参考
- http://qiita.com/himara2/items/dcfcc30b550c3304d86a
- http://qiita.com/eKushida/items/634ad3726868c8f5e61d