おじさんのための2018年スマホPUSH通知事情 (+GCM終了のお知らせ)

# はじめに

ネイティブを中心に長いことスマホアプリの開発を行っているのですが、
先日、人生四度目の「PUSH通知」の実装を行うことになりました。

＃本記事の「PUSH通知」はRemote Push Notificationを指しています。

やるたびに新しい情報があるけど
やる機会はあまりないPUSH通知なので概要をまとめます。

有能な若者に「その情報古いよ..」「やれやれ、いまどきのおじさんは..」と
愛想を尽かされないようがんばっていきたい人向けの資料です。

# 古い常識まとめ
### 2011年以前の常識: AndroidといえばC2DMでのPUSH通知

https://developers.google.com/android/c2dm/

いくらなんでも古すぎる情報ですが
Android初期の頃にCloud to Device Messagingというものがあり、
2012年に廃止されGoogle Clound Messagingに移行しました。
現在ではFirebase Clound Messagingが推奨されています。

### 2015年以前の常識: AndroidといえばGCMでのPUSH通知

https://developers.google.com/cloud-messaging/

<img width="909" alt="スクリーンショット 2018-04-03 23.30.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/19692/c59da869-0ea3-c582-8ba4-ec20df87830b.png">

上記のGCM公式ページの通り、
2018年4月(3日)現在ではFirebase Cloud Messagingが"強く"推奨されています。
**※ 上記は2018年4月3日のスクリーンショット。最新版は後述の「おまけ」参照**

未だにFCM未対応のサードパーティ製PUSH通知サービスは多く残っていますが、
新規にサービスを立ち上げる際はFCMを選択するのが良いです。

### 2016年以前の常識: iOSのPUSH通知は証明書(p12)周りが大変

cerファイルを用意して、
開発版と本番用のp12証明書を用意して、
1年後に有効期限が切れるので日付をカレンダーに書いて、
1年経ったらドキドキしながら証明書更新..
というのはもう昔のことです。

2016年10月のWWDC 2016でPUSH通知が証明書でなく認証キー(p8)で可能になることが発表されました。
https://developer.apple.com/videos/play/wwdc2016/724/

<img width="728" alt="スクリーンショット 2018-04-04 0.22.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/19692/ad9e79fa-f105-7be6-ba06-12883dc9d060.png">

Apple DeveloperのCertificates, Identifiers & ProfilesにKeyの項目が追加されています。
https://developer.apple.com/account/ios/certificate/

<img width="1005" alt="スクリーンショット 2018-04-03 23.17.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/19692/dd98aa91-0800-3db0-f07b-f04453076480.png">


認証キーは証明書ファイルとは異なり、ダウンロードは1度しか出来ませんが、
複数のアプリで使用できサーバ証明書が不要です。

PUSH通知のためにApple Developerで設定が必要なのはAppIDとAuthKeyのみになりました。

参考: FCMでのAPNsの設定
https://firebase.google.com/docs/cloud-messaging/ios/certs?hl=ja

# 2018年に技術選定するなら

よほどのことがない限り上記の「FCM」「認証キー(p8)」に対応した
PUSH通知サービスを選ぶのが良いとというのが個人の感想です。
＃ 両方に対応しているの本当に数少ないですが..

特に証明書ファイル(p12)から認証キー(p8)の変更は設定がだいぶ楽なので通知の世界が変わります。
両方に対応したサービスで代表的なものは以下となります。

Firebase
https://firebase.google.com/docs/cloud-messaging/

Visual Studio App Center
https://docs.microsoft.com/en-us/appcenter/push/

# FCM実装上の注意点(公式)

公式ドキュメントにある最新バージョンの注意点を挙げます。

### Androidでは受信したメッセージの処理時間を10秒以内にする

> メッセージは受信から10秒以内に処理されるようにします。
>10秒経過すると、Androidでは実行が保証されず、いつでもプロセスが終了される可能性があります。
> メッセージの処理にもう少し時間が必要な場合は、Firebase Job Dispatcherを使用してください。

https://firebase.google.com/docs/cloud-messaging/android/receive?hl=ja

### Android8.0以降ではFCMの優先度がアプリ状態に影響を及ぼす

>  特定の状況下では、バックグラウンドアプリは一時的なホワイトリストに数分間入れられます。 アプリがこのホワイトリストに存在する間は、アプリは制限なくサービスを起動でき、アプリのバックグラウンドサービスは実行が許可されます。
> 
>  アプリは、ユーザーに表示される次のようなタスクを処理しているときにホワイトリストに入れられます。
> 
> ・高い優先度の Firebase Cloud Messaging（FCM）メッセージの処理。
> ・SMS/MMS メッセージなどのブロードキャストの受信。
> ・通知からの PendingIntent の実行。

https://developer.android.com/about/versions/oreo/background.html?hl=ja#services

### iOS10以降ではUNUserNotificationCenterDelegate, MessagingDelegateを実装する

> iOS10以降が搭載されている端末の場合、アプリを運用開始する前に、表示通知を受信する UNUserNotificationCenter オブジェクトとデータメッセージを受信する FIRMessagingオブジェクトにデリゲートオブジェクトを割り当てる必要があります。

https://firebase.google.com/docs/cloud-messaging/ios/client?hl=ja

上記の変数名が少し古いので、公式サンプルコードを見たほうがわかりやすいです。
https://github.com/firebase/quickstart-ios/blob/master/messaging/MessagingExampleSwift/AppDelegate.swift#L40-L55

# FCM実装上の注意点(個人的)

個人の体験に基づいた注意点を挙げます。

### サーバ側のコード実装方法

https://firebase.google.com/docs/cloud-messaging/server?hl=ja

2018年4月現在、最新のHTTP v1 APIを使用します。
『送信リクエストを承認する』ではOAuth2.0トークンを取得方法、
『送信リクエストを構築する』で上記トークンを使用したcurlでたたく方法が紹介されています。


```
curl -X POST -H "Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA" -H "Content-Type: application/json" -d '{
  "notification": {
    "title": "FCM Message",
    "body": "This is a Firebase Cloud Messaging Topic Message!",
  },
  "condition": "'dogs' in topics || 'cats' in topics"
}' "https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1"
```

### iOSで実装直後はPUSH通知が届かない(？)

iOSでFCM実装直後ではログが正常なのにPUSH通知が表示されませんでした。
半日後同じコードで動作させるとPUSH通知が届いたので、
実装直後からPUSH通知が届くようになるまでブランクが有るのかもしれないです。(定かではない)


# まとめ
2018年にPUSH通知やるならFCM,認証キー(p8)に対応したPUSH通知を使うと良いです。

# おまけ

ちょうど記事作成中の2018年4月11日(現地時間4月10日)、FirebaseからGCM終了のお知らせメールが届きました。

GCMは2019年の4月11日に廃止予定とのこと。
以下公式GCMページではタイトルで非推奨が主張されるようになりました。

https://developers.google.com/cloud-messaging/

<img width="888" alt="スクリーンショット 2018-04-11 19.39.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/19692/14111dc5-5bc6-cfec-c0f1-6f3b27ed7b0a.png">

ぼんやり訳

> 2018年4月10日、GoogleではGCMを非推奨にしました。GCMサーバーとクライアントAPIを非推奨とし、2019年4月11日に削除予定です。
> GCMアプリケーションは信頼性と拡張性の高いGCMインフラストラクチャと多くの新機能を継承するFirebase Cloud Messaging（FCM）に移行してください。 
> 詳細は、移行ガイドを参照してください。

参考: The Firebase Blog "Time to Upgrade from GCM to FCM"
https://firebase.googleblog.com/2018/04/time-to-upgrade-from-gcm-to-fcm.html