【Firebase Notifications】アプリがバックグランドでもPUSH通知を表示する方法

## [onMessageReceived()](https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService.html#onMessageReceived(com.google.firebase.messaging.RemoteMessage))が呼び出されない問題

FireBaseコンソールのNotificationsからメッセージを送信すると、アプリがバックグランドの場合、[FirebaseMessagingService](https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService)を継承したクラスの[onMessageReceived()](https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService.html#onMessageReceived(com.google.firebase.messaging.RemoteMessage))が呼び出されずに、自動的にステータスバーに通知が表示されます。

この仕様はFCMの[ドキュメント](https://firebase.google.com/docs/cloud-messaging/android/receive#backgrounded)にも記載されています。
>アプリがバックグラウンドで動作しているとき、Android ではシステムトレイに通知メッセージが送られます。ユーザーが通知をタップすると、デフォルトでアプリ ランチャーが開きます。
通知とデータ ペイロードの両方を含むメッセージ（および Notifications コンソールから送信されたすべてのメッセージ）がここに含まれます。通知は端末の通知領域（システムトレイ）に配信され、データ ペイロードはランチャー アクティビティのインテントの追加部分で配信されます。

それでも、アプリがフォアグラウンドじゃない場合でもバナー状のPUSH通知を表示したいことがあると思います。

## バックグランドでもPUSH通知を表示する方法

実はアプリがバックグランドにいる状態でも[FirebaseMessagingService](https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService)を継承したクラスは呼び出されます。
ただ、[onMessageReceived()](https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService.html#onMessageReceived(com.google.firebase.messaging.RemoteMessage))に到達しないだけなのです。

[onMessageReceived()](https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService.html#onMessageReceived(com.google.firebase.messaging.RemoteMessage))より前に呼び出されるのが、```handleIntent(Intent intent)```です。
引数の```intent```にはPUSH通知のメッセージ内容が格納されています。
ちなみに、アプリがフォアグラウンドの場合でも、同様に```handleIntent()```は呼び出されます。

FireBaseコンソールでメッセージ作成時にカスタムデータを下記の様に設定して送信します。
<img width="915" alt="スクリーンショット 2017-11-16 0.38.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/88858/9115bec2-8840-20df-5a24-f281fb1da05b.png">

デバッグモードでIntentの中身を見てみると以下のようになっています。

```
Bundle[{google.c.a.udt=0, google.sent_time=1510755428922, gcm.notification.e=1, google.c.a.c_id=xxxxxxxxxx, google.c.a.ts=xxxxxxxx, gcm.notification.sound=default, gcm.n.e=1, url=https://xxxx/yyyyy/zzzz, body=ボディ, from=xxxxxxxxx, gcm.notification.sound2=default, title=タイトル, google.message_id=0:xxxxxxxxxxxxx, gcm.notification.body=android---, google.c.a.e=1, collapse_key=jp.co.xxxxxxxxxx}]
```

```body```、 ```title```、```url```にFireBaseコンソールでメッセージ作成時に設定したカスタムデータが入ってきてますね。

あとはこの値を取得して、通常通りPUSH通知を表示します。
全体的な実装はこうなります。

```java
public class MyFirebaseMessagingService extends FirebaseMessagingService {

    @Override
    public void handleIntent(Intent intent) {
        if (intent.getExtras() == null) return;

        Map<String, String> data = new HashMap<>();
        data.put("body", intent.getExtras().getString("body"));
        data.put("title", intent.getExtras().getString("title"));
        data.put("url", intent.getExtras().getString("url"));
        sendNotification(data);
    }

    private void sendNotification(Map<String, String> data) {

        String title = data.get("title");
        String message = data.get("body");
        String url = data.get("url");

        Intent intent = new Intent(this, HomeActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
                PendingIntent.FLAG_ONE_SHOT);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setContentTitle(title)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentText(message)
                .setAutoCancel(true)
                .setPriority(1 /* Notification.PRIORITY_HIGH */)
                .setFullScreenIntent(null, true)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0, notificationBuilder.build());

    }
```

## おわりに

これが正しい方法かはわかりませんが、一応問題なく動いています。
他に良い方法があれば教えてください！