iOS 10などで使えるようになるUserNotificationsフレームワークへの所感

[WWDC16. Meetup @Wantedly with 日本経済新聞社](http://wantedly.connpass.com/event/33967/)にて久々に発表しました(　´･‿･｀)

<iframe src="//www.slideshare.net/slideshow/embed_code/key/1Omlqnlkdpip0V" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/mono0926/whats-new-in-user-notifications-framework-wwdc16-meetup-wantedly-with" title="What&#x27;s New in User Notifications Framework - WWDC16. Meetup @Wantedly with 日本経済新聞社" target="_blank">What&#x27;s New in User Notifications Framework - WWDC16. Meetup @Wantedly with 日本経済新聞社</a> </strong> from <strong><a href="//www.slideshare.net/mono0926" target="_blank">将之 小野</a></strong> </div>

|自己紹介|ちょっと遠目から|
|---|---|
|![DSC05591.JPG](https://qiita-image-store.s3.amazonaws.com/0/19398/ac3b033d-15ee-cbe3-1df6-6582c159bc1d.jpeg)|![DSC05598.JPG](https://qiita-image-store.s3.amazonaws.com/0/19398/5260c084-2abe-8442-3511-876e1065f300.jpeg)|


10分間のLTの割に盛り込みすぎて~~予定通り~~、全て話し切れ無かったので、フォローアップ記事です。

スライド31ページ目まででUserNotificationsをほぼ網羅的に紹介してそこで時間切れでしたが、32ページ目から実際にプロダクト上で実装するにあたっての検討事項や悩ましいところについて用意していました。
そのあたりについてざっと記事にします。
(今回はあえて口頭の説明込みじゃないと分かりにくいかな、みたいなスライドにしているので31ページまでも記事化したいなと思いつつけっこう大変なので迷い中です🤔)

では、以下32ページ目以降の内容を記事化したものです:

# iOSバージョン差異による実装の複雑化

2016年5月9日時点でのiOSバージョンのシェアはこのようになっています。
![fragmentation.png](https://qiita-image-store.s3.amazonaws.com/0/19398/21f6239d-7b1d-2059-1c23-476f968e8093.png)
(最新のデータはこちら参照: [App Store - Support - Apple Developer](https://developer.apple.com/support/app-store/))

直感的に、最新バージョンがリリースして半年以上経過した状態でも大体のアプリでは2世代以上はサポートしないと良くないかなという感じが読み取れると思います。

一方、通知周りのAPIは、〜iOS 7・iOS 8/9・iOS 10〜でざっくり次のような違いがあります。
(iOS 8では、ローカル通知許可確認が追加された影響でそれと統合される形でリモート通知用のAPIに変更が生じました。)

||API|機能|イメージ|
|---|---|---|---|
|〜iOS 7 | UIKit(registerForRemoteNotificationTypes:など) | 通知, バッジ, 音, バイブレーション, バックグラウンド・サイレント通知 (iOS 7) |![iOS7.png](https://qiita-image-store.s3.amazonaws.com/0/19398/dc78d9aa-01a9-290e-da2d-58670bac81fc.png) |
|iOS 8/9 | UIKit (registerUserNotificationSettings:,registerForRemoteNotificationsなど) | アクション選択(iOS 8)・テキスト入力(iOS 9) |<img width="986" alt="ios8.png" src="https://qiita-image-store.s3.amazonaws.com/0/19398/e0b1c3e5-e4c3-3aca-ab2f-632bc7a8a600.png"> |
|iOS 10 |          __UserNotificationsフレームワーク__ | ローカル通知改善, メディアアタッチメント, 通知管理, アプリ内通知, App Extensions(Service・Content) |<img width="678" alt="Screen Shot 2016-07-01 at 2.59.08 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/19398/6ea00e96-31be-3931-1dc0-fc5f47ea0903.png"> |

UsersNotificationsフレームワークで、iOS・tvOS・macOSの各プラットフォームの通知関連の処理がほぼ全て集約されてAPIも使いやすく刷新された、ということは素晴らしいのですが、現実的には以前のバージョンのサポートも同時にしなければいけないことが多く、その場合逆に複雑化してしまいます。
通知周りで細かい制御しようとするとただでさえ複雑なのに、混在するとけっこう厄介かなと思います。

## 以前のAPIでiOS 10上で通知は動くか？

そこで、iOS 10でもiOS 8/9と同じやり方で通知が届くのか試してみたところ、届くことが確認出来ました。(Xcode 8 beta1・iOS 10 beta1実機の組み合わせで確認)
まだβなので安心しない方が良いとは思いますが、正式リリースが近くなったらテストして問題無く動くか確認し、さらに新フレームワークの機能が必要で無ければ何も対応しない、という選択肢も充分ありなのではとも感じました。

iOS 8でAPIに変更が生じたタイミングでは、既存コードのまま新しいSDKでビルドするとiOS 8端末にプッシュ通知が届かなくなってしまう、という問題があって、少し騒ぎになりました。今回は大丈夫そう、という感触です。

もちろんきちんと対応してiOS 10ユーザーのUX向上だったり、新機能を使うことでAppStoreでフィーチャーされやすくなるということを狙うのも良いと思いますし、僕自身も新機能を活用したアプリにたくさん触れたいと思っていますが。

## ライブラリに頼る

また、delegate系の処理を使いやすくバージョン間の揺れなど埋めつつ統一的にラップするようなライブラリもあり、その1つである[SuperDelegate](https://github.com/square/SuperDelegate)はiOS 10対応も予定されているので、混在の辛さはこういうのに頼る、という選択肢もありかもしれません。
(あるいはこのライブラリが需要に合わなければ、同様の方針でより良いものを自ら作るなど。)

> 1.0 – Will be released when iOS 10 is near release.

# iOS 10の通知APIの活用のために必要なこと

次に、ちょっと対応手こずるかなと思った点について述べます。

## リモート通知の`identifier`の利用

スライド17-18の、通知管理についてのところで、その管理は`identifier`ベースで行い、リモート通知の場合は`apns-collapse-id`というHTTP/2 request headerに値を設定する、と述べました。
これまでサーバーでのプッシュ通知ハンドリングは、バイナリAPIというWeb標準ではない独特のものでしたが、HTTP/2ベースの新しいAPIが登場し、その利用が必要です。
(参考: [APNs Provider API](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/APNsProviderAPI.html))

HTTP/2ベースの新しいAPIは、2015年のWWDCで発表されて、同年12月から実際に使えるようになりました。
(参考: [Apple Push Notification Service Update - News and Updates - Apple Developer](https://developer.apple.com/news/?id=12172015b))

おそらくですが、ほとんどのプッシュ通知サービスはこの新しいAPIに対応していないはずです。
(参考にAmazon SNSの情報: [AWS Developer Forums: Will SNS offer the new APNS features ...](https://forums.aws.amazon.com/thread.jspa?messageID=669465))

なので、これを利用するためには現状、自前のハンドリングが必要になってくるはずです。
HTTP/2ということで自前で扱いやすいはずですが、[Firebase](https://www.firebase.com)や[Amazon SNS](https://aws.amazon.com/sns/)などを使うと便利なことも多いですし、移行コストなどもあるのでけっこう悩ましいところかと思います。
せっかく自前ハンドリングに移行したと思ったら、その後すぐプッシュ通知系サービスが対応しちゃった、などもあり得そうですし。

個人的には、どうしても必要ということで無ければしばらく待ちが賢明かなあという印象です。

## APNs ペイロードの変更

iOS 10からこのように、`title`・`subtitle`・`body`が指定出来るようになります。

![Screen Shot 2016-07-01 at 3.30.43 PM.png](https://qiita-image-store.s3.amazonaws.com/0/19398/f661396e-f18e-3288-79e3-2accf381e5f2.png "title・subtitle・body")

ペイロード例:

```json
{
   "aps": {
       "alert": {
           "title": “Introduction to Notifications",
           "subtitle": “Session 707",
           "body": "Woah! These new notifications look
 amazing! Don’t you agree?"
       },
       "badge": 1
   }
}
```

初め、iOS 10で`alert`の入れ子表示対応になったかと勘違いしてたのですが、こちらのTweetを見て違うと気づきました。

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">APNs Payloadの title, body はすでにiOS 8.2からあったようですね <a href="https://twitter.com/hashtag/WWDC16%E5%85%B1%E6%9C%89%E4%BC%9A?src=hash">#WWDC16共有会</a> / “The Remote Notification Payload” <a href="https://t.co/551fSdygdd">https://t.co/551fSdygdd</a></p>&mdash; Kosuke 8/20はiosdc.jp (@koogawa) <a href="https://twitter.com/koogawa/status/747976414813523968">June 29, 2016</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

確かに、リモート通知文言の国際化をクライアントサイドで行う時に使う`alert`に`title-loc-key`などを入れ子にして設定することなどが以前から可能でしたしね。
(参考: [The Remote Notification Payload](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html))
リモート通知文言の国際化は、サーバーサイドで行うことが主流な気がしていて、僕もそうしていて普段使っていないので頭から抜けかけていました。

まとめるとこんな感じです:

- iOS 10から増えたのは`alert`の子要素の`subtitle`のみ
- iOS 8.2からこっそり`alert `の子要素の`title`が増えている
  - 上からバナーが出る時には出ずに、通知一覧などで表示される、など中途半端な対応だった
- `alert`の子要素の`body`に設定したもの = `alert`に単純に文字列指定したもの

というわけで気を付けるべきはこの程度ですね:

- iOS 10向けにalertを細かく出したい時は、`body`に一番知らせたいことを入れて、`title`はiOS 8.2以降でも通知種類によっては見え、`subtitle`はiOS 9以前では表示されないことを念頭に
  - これに従いたく無い場合、手間増えるが、OSごとにペイロード内容を変えることでより最適な表示も可能(普通ここまで手間かけたくないと思いますが)
- `alert`に単純に文字列指定だとiOS 10含めて全てのバージョンで現状維持になるだけ

iOS 10からというよりiOS 8.2から気を付けたり活用すべきことだったのかなと思いますが、今回目立つ形で発表があって、またiOS 8.2からの`title`のような中途半端な扱いでは無くなったので、実際にはiOS 10から`alert`の細かい表示が活用され出すのかなと思いました。

というわけで、初めはこのあたり処理分けなど手間になるかも？と思ったのですが、上に書いたちょっとしたことを頭に入れておく程度で大丈夫そうです(　´･‿･｀)

---

この記事はスライドで話しきれなかったということで、懸念点など中心の内容になってしまいましたが、`UserNotifications`フレームワーク自体は自由度など一段と上がってとても良く出来ていると感じています。
iOS 10が正式リリースされてシェアも増えた頃には、`UserNotifications`フレームワークを活用した使いやすいアプリがたくさん登場してほしいところです(　´･‿･｀)

## 関連リンク

- スライド: [What's New in User Notifications Framework - WWDC16. Meetup @Wantedly…](http://www.slideshare.net/mono0926/whats-new-in-user-notifications-framework-wwdc16-meetup-wantedly-with)
- サンプルコード: [mono0926/wwdc2016-sample](https://github.com/mono0926/wwdc2016-sample)

(NDA的にセーフと解釈している範囲で書いているつもりですがアウトの指摘などあれば調整します)