読者です 読者をやめる 読者になる 読者になる

ほげほげ(仮)

仮死状態

Firebase Cloud Messagingで通知をカスタマイズ(Android)

Android

Firebase Cloud Messaging (FCM)を試して、通知のカスタマイズについて調べてみました。

FCMとNotification

FirebaseにはFCMとは別にNotificationという似たようなのがあります。

この辺りの違いは下記の記事にまとまってます。

Firebaseによるプッシュ通知のハマりどころ - Qiita

ざっくりと言って、Web上のConsoleから通知を発行できるのがNotificationで、FCMはその基盤になっておりAPI経由で実行する感じかと思います。

概要

今回はNotificationは使いません。

というか、Notificationでは通知のカスタマイズが微妙に物足りません。ぼくは特に通知アイコンを変更できないのがツライです。

現状だとAPIを叩くしか方法はありません。

通知を受けた時の処理

通知をカスタマイズするには通知を受けた時に自分で通知を表示すればいいと思うのですが、ここの挙動がやっかいなので、軽く説明が必要になります。

ここのドキュメントに書いてる通り、FirebaseMessagingServiceを継承してonMessageReceivedをoverrideすれば通知受信時に処理が可能です。

ただし、onMessageReceivedが実行されるには、アプリの状態と通知がNotificationなのかDataなのかそれとも両方なのかで変わってきます。

onMessageReceivedは通知を受けたら必ず呼ばれるものではなく、条件で呼ばれないことがあります。あと自動で通知が表示されたりする場合もあります。

f:id:STAR_ZERO:20160529161944p:plain (https://firebase.google.com/docs/cloud-messaging/downstream から引用)

App state、Notification、Data、Both

さきほどのドキュメントの図が分かりづらいので、簡単に説明しておきます。

App stateはアプリ状態でForegroundBackgroundのいずれかです。

NotificationDataBothですが、APIの使い方で変わります。

言葉で説明しにくいのでAPIへ投げるJSONの例で簡単に。最低限の設定でやってます。

APIの仕様はここを見てください。

Notification
{
  "to" : "/topics/all",
  "notification": {
    "body": "メッセージ"
  }
}

この時、アプリの状態がForegroundの場合はonMessageReceivedが呼び出されますが、Backgroundの場合はSystem trayと記載されてる通り通知がすぐ表示されて、onMessageReceivedは呼び出されません。

Data
{
  "to" : "/topics/all",
  "data": {
    "hoge": "foo"
  }
}

この時は、アプリがForegroundBackgroundでもonMessageReceivedが実行されます。 dataに設定した値はonMessageReceived内で処理します。

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    Log.d(TAG, "Notification data: " + remoteMessage.getData().get("hoge"));
}
Both

これはJSONnotificationdataもある状態ですね。

{
  "to" : "/topics/all",
  "notification": {
    "body": "メッセージ"
  },
  "data": {
    "hoge": "foo"
  }
}

アプリがForegroundの場合はonMessageReceivedが実行されます。

Background時が少し複雑です。Notificationと同じように通知は表示されますが、onMessageReceivedが実行されません。では、dataに設定された値はどこで処理するのか?これは通知タップで起動されるActivityのintentに入ってくるのでそこで処理するようにします。

通知のカスタマイズ

少し前置きが長くなりましたが、通知のカスタマイズ方法です。

自分で通知を表示する

dataのみをJSONに含んでAPIを呼んであげれば良いです。

そうするとBackground状態でも、onMessageReceivedが呼ばれるので、NotificationCompat.Builderを使って自分で通知を表示することが可能になります。

APIで設定する

ここnotificationに設定できるキーがあります。

iconsoundを設定することである程度はカスタマイズ可能です。

{
  "to" : "/topics/all",
  "notification": {
    "title": "タイトル",
    "body": "メッセージ",
    "icon": "ic_notification"
  }
}

ただし、Foregroundの時でも通知を表示したい場合は、onMessageReceivedNotificationCompat.Builderの実装が必要になります。

まとめ

通知をちゃんとカスタマイズするには、FCMのAPI経由しかない状況です。あと、Notificationと違ってConsoleに履歴とか残らないのも問題です。(どこかにあるのかな?)

通知を発行するのがエンジニア以外だと、APIを直接投げるようなことは難しいでしょうし、そのあたりも考えないとダメですね。

Firebaseは便利は便利だと思いますが、通知だけやりたいって状況でFirebaseは微妙に合わないかもしれません。個人的はOneSignalのほうが通知に関しては簡単で便利かなと思います。

参考