pixiv insideは移転しました! ≫ https://inside.pixiv.blog/

Firebase Cloud Messaging (FCM) を利用してお手軽に通知を送る

ピクシブ株式会社 Advent Calendar の@3日目です。今日はスマホアプリエンジニアの chocomelon がお送りします。

最近、弊社のプロジェクトではネイティブアプリのプッシュ通知に Firebase を使っています。導入方法は色々な方々が紹介しているので今さら感はありますが、弊社ではこんな感じで使っていますという事例を絡めて紹介できればと思います。

記事の内容的には Firebase で送るプッシュ通知の概要は知っていて、これから導入を検討している方や、Firebase を使ったプッシュ通知が実際どんな形で使われているか興味がある方にオススメです。

Firebase Notification と Firebase Cloud Messaging

Firebase で送る通知は、Firebase Notification を使ってGUIから送る方法と Firebase Cloud Messaging (以下FCM) を使って送る2つの方法があります。弊社では FCM を使って通知を送っています。

Firebase Notifiation は送る内容、ターゲット、タイミング等を Notifications Console GUI からの操作でき、お手軽に通知を送ることができます。

画像:Notifications Console GUI f:id:chocomelonchan:20161201104525p:plain

ただ Firebase Notification はAPIは存在せず、定期実行をしたい場合などに不便です。現状API経由で通知したい場合は、FCM しかないので FCM を使っています。

FCM には Notification Message と Data Message があります。Notification Message の場合、Android は端末がバッググラウンドの状態にある時に処理のハンドリングができず、正確な通知の開封率が計測できなかったため Data Message を使用しています。詳しくは Firebase のドキュメントを参照してください。

特定のトピックを購読しているユーザーに対して通知を送る

pixiv アプリでは、新規ユーザー向けにどの通知が刺さるかちょこちょこABテストしています。そのうちのひとつに pixiv のイラストデイリーランキングが更新されたタイミングで通知を送っているので例として紹介します。

サーバ側の処理

サーバ側ではランキングが更新されたタイミングで FCM に以下のデータを投げつけてアプリに通知を送っています。通知を受信したアプリは"data"内の値にもとづいて通知を生成します。

data.json

{
    "to": "/topics/illust_daily_ranking",
    "data": {
        "title": "pixiv",
        "body": "ランキング更新!トレンド作品をチェック!",
        "target_url": "pixiv://ranking/illusts"
    },
    "content_available": true
}

content_availableに関しては、iOS のために設定しています。content_availableは APNs でいう content-available に相当しています。iOSアプリでは、この値が true の場合、アプリがバックグラウンドにいたり、終了した状態でも通知を受け取ることができます。Android では、デフォルトでアプリがバッググラウンドの状態でも通知が届きます。

実際の送信処理は以下のようになります。さきほどの json を FCM に投げます。

curl -H "Authorization: key=XXXXXAPIKEYXXXXX" -H "Content-Type: application/json" -d @data.json https://fcm.googleapis.com/fcm/send

アプリ側の処理 (Androidの場合)

アプリ側ではトピックを購読する処理と受信したときの処理を書きます。以下はAndroidの例です。長くなるので細かい設定の話は省きます。詳しくは Firebase のドキュメントを参照ください。

トピックの購読処理

FirebaseMessaging.getInstance().subscribeToTopic("illust_daily_ranking");

受信時の処理。

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    Map<String, String> data = remoteMessage.getData();
    RemoteMessage.Notification notification = remoteMessage.getNotification();
    String title = data.get("title");
    String body = data.get("body");
    String targetUrl = data.get("target_url");
    // 略... NotificationManagerを使って通知をnotifyしたりする。
}

jsonで渡したデータはRemoteMessageのgetData()でKey-ValueのペアでMapされた形で取得できます。 取得したタイトルやメッセージbodyのデータ使って、NotificationManager経由で通知を送ります。

ユーザー個別に通知を送る

pixiv のアプリで新規ユーザー向け通知の最適化のために、ユーザーがしたアクション(ブックマークやフォロー)をもとにオススメ作品を送るという通知を試験的にしています。

これを実現するために、新規ユーザー個別の通知にユーザー毎に一意になるようなトピックを使っています。トピックの生成がおそらく上限が設定されていないので、トピックで購読させた方がトークン管理やユーザーが別の端末を使っている場合も特に気にしなくて良いです。

トピックが被って別のユーザーの通知がきてしまわないようにサーバ側で生成したトピックを受け取って購読しています。

サーバ側の処理

  • 準備
    • ユーザー毎に一意のトピックを返すAPI
  • 通知処理
    • 通知対象のユーザーをデータベースから抽出
    • 抽出したユーザーからオススメを生成
    • FCM 経由でアプリに通知

アプリ側の処理

  • サーバ側のAPIからトピックをもらい購読

まとめ

通知をお手軽に試すのに Firebase Notification は非常に良いかなと思います。ただ少しカスタマイズしたい場合などは FCM を使うと良いかと思います。ぜひみなさんも試してみてください!