FirebaseでPush Notification - 3件目


##はじめに

Parseのサービス終了がアナウンスされ，幾月・・・・．

Google I/O 2016でFirebaseのリニューアルが発表されました．そこでは，Parseによって失われようとしている機能が提供されようとしています．そこで，Parseで運用しているPush Notificationを置き換えることができるかを検討してみました．すでに数本の人柱が立っており，私に書けることなど少ないかとも思えますが，私がドツボにはまったところだけをまとめると，これらにはないコンテンツになりそうなので，まとめることにしましょう．

1. [Google I/O 2016 で「Firebase」の新バージョンが発表！プッシュ通知機能を iOS アプリで使ってみた](http://dev.classmethod.jp/smartphone/firebase-notification-ios/)
1. [Firebaseによるプッシュ通知のハマりどころ](http://qiita.com/mituoh/items/2dc87618edf234afd8f0)
1. [【iOS】Firebase の Notifications でプッシュ通知を送る](http://qiita.com/koogawa/items/ca8cce019b4ff7ce2576)

##やりたいこと
サーバが自動的かつ定期的に，ユーザの設定に応じてコンテンツを通知する．

##Push Notificationの鍵を登録する
わかりにくい．

<img width="488" alt="Firebase01.png" src="https://qiita-image-store.s3.amazonaws.com/0/3341/77b7757f-ab60-4c60-b0ea-302fdb819a23.png">

ここから，設定を選び，

<img width="786" alt="Firebase02.png" src="https://qiita-image-store.s3.amazonaws.com/0/3341/fa27f0c8-bd28-820a-85bc-fe40b9b32d83.png">

上のクラウドメッセージングのタブを開くと，APNSの証明書の鍵を登録できる．

<img width="1040" alt="Firebase03.png" src="https://qiita-image-store.s3.amazonaws.com/0/3341/2b1cdd3b-59c7-aeee-bad6-0f50fef48127.png">

鍵はパスワード付きも使える．

##Firebase Notificationの二つの送り方
Firebaseは，端末から，他の端末に通知を送ることもできる．今回は，Downstreamつまり，PushNotificationについて調べていく．Push Notificationを発行するには，以下の二つの方法があるようだ．

1. WebConsolle
2. HTTP Server Connection

##WebConsole
WebConsoleは，FirebaseのWebインタフェースから，GUIで通知を送信する．通知先は，下の3つから選べる．

1. ユーザセグメント〜バージョンなどによって条件づけたデバイス群
2. トピック
3. 特定のデバイス〜デバイスIDを指定して送信する 

自動的に送信することを考えているので，これはどうでもいい．

##HTTP Server Connection
APIのように，指定されたendpointにJSONを投げつけることで，Push Notificationを発行できる．これが欲しかった機能．これについて深堀してみる．

APNSには，バックグラウンド用のデータとアラート用の二つがある．発行時に，priorityを指定しないと，バックグラウンド用のAPNSになってしまう．バックグラウンド用のAPNSはアラートが表示されない．また，API経由での送信は素直に全員に送信できない．WebConsoleの場合，ユーザセグメントの条件を空にすると，自動的に全員に送ることになるが，APIには，それが用意されていない．全ユーザにひとつの共通トピックを購読してもらうことで，これを回避できる．たとえば，`/topic/all`のようなトピックを作り，そのトピックに向けて通知すれば，ユーザ全員が通知を受け取れるという算段だ．

##トピックの作成・購読
これもわかりにくい・・・・・．
トピックは，どうやらクライアントから設定して作成するようだ．
サンプルコードを参考にトピックを設定するコードを書くとこうなる．

```
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
    
    FIRApp.configure()
    
    let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
    application.registerUserNotificationSettings(settings)
    application.registerForRemoteNotifications()
    
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.tokenRefreshNotificaiton), name: kFIRInstanceIDTokenRefreshNotification, object: nil)
    if let refreshedToken = FIRInstanceID.instanceID().token() {
        print("InstanceID token: \(refreshedToken)")
        connectToFcm()
    }
    return true
}

func tokenRefreshNotificaiton(notification: NSNotification) {
    if let refreshedToken = FIRInstanceID.instanceID().token() {
        print("InstanceID token: \(refreshedToken)")
        connectToFcm()
    }
}

func connectToFcm() {
    FIRMessaging.messaging().connectWithCompletion { (error) in
        if error != nil {
            print("Unable to connect with FCM. \(error)")
        } else {
            print("Connected to FCM.")
            FIRMessaging.messaging().subscribeToTopic("/topics/foo")
        }
    }
}
```

メッセージサービスに接続し，`subscribeToTopic`でトピックを指定して，購読を開始するようだ．
トピックは，すでにあるものから選ぶというより，自由にこのAPIを使って設定するというスタイルのようだ．

##トピックの確認方法
作成したトピックは，1〜2日後くらいに，WebConsoleで確認できるようになる．

![topic.png](https://qiita-image-store.s3.amazonaws.com/0/3341/db9c84f1-63ca-2058-2a5d-824418190ba4.png)


##ペイロードのサンプル
アラート形式で，送るときのJSONはこんな感じ．

```
{
  "to": "/topics/foo",
  "priority": "high",
  "notification": {
    "title": "title 2016-05-25 08:26:13 +0900",
    "body": "2016-05-25 08:26:13 +0900"
  }
}
```

curlで送るとこんな感じでしょうかね．

```
curl --header "Authorization: key=[Your API Key]" \
     --header Content-Type:"application/json" \
     https://fcm.googleapis.com/fcm/send \
     -d "{\"to\": \"/topics/foo\",\"priority\":\"high\",\"notification\": {\"title\": \"title\"}}"
```

私は実験用に[rubyのコード](https://gist.github.com/sonsongithub/ed210c4d94a97b5177213184e1adecb1)を書いてました．

##通知の遅延
立て続けに，HTTP Server Connectionから通知を送り続けると，遅延が発生するようだ．
特に，開発中などに立て続けに通知を送ったりするときは注意する必要がある．
私は数分間隔で送り続ける実験をしてみたが，大体，すぐに届く．
まれに10分程度遅延することもある．