FlutterのAndroidアプリでプッシュ通知を受けてバナーを表示する

FlutterのAndroidアプリで、プッシュ通知を受けてバナー表示しようとしたのですが、色々困ったので情報をまとめておきます。

# FCMの準備
Firebase Cloud Messagingでプッシュ通知を実現します。
FCMの設定は色々な人が記事上げていると思うのでそちらを参考にしてください。

# プッシュ通知トークンを取得する

```dart:
// これでトークンが取得できる
var token = await FirebaseMessaging.instance.getToken();
```

[Flutter で Firebase Cloud Messaging クライアント アプリを設定する](https://firebase.google.com/docs/cloud-messaging/flutter/client?hl=ja)には下記記載がありましたが、これで取得できるタイミングはよくわかりませんでした。
```dart:
FirebaseMessaging.instance.onTokenRefresh
    .listen((fcmToken) {
      // TODO: If necessary send token to application server.

      // Note: This callback is fired at each app startup and whenever a new
      // token is generated.
    })
    .onError((err) {
      // Error getting token.
    });
```


# プッシュ通知権限を要求する
Android13からAndroidでもプッシュ通知権限の要求が必要になりました。
[Flutter アプリでメッセージを受信する](https://firebase.google.com/docs/cloud-messaging/flutter/receive?authuser=0&hl=ja)に記載しておいて欲しいですね。

プッシュ通知権限要求のパッケージ[notification\_permissions](https://pub.dev/packages/notification_permissions)があるのですが、Android13対応がされていません。(ここでちょっと詰まりました)

issueを見ればわかりますが、誰かが対応ブランチを作ってくれているのでそれを利用します。(なんでマージされてないの？？)

pubspec.yamlに下記を追加します
```:pubspec.yaml
  notification_permissions:
    git:
      url: https://github.com/bshvets8/flutter_notification_permissions.git
      ref: feature/android-13-support
```

AndroidManifest.xmlにuses-permissionを追加します。

```:AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
```

参考:[通知に関する実行時の権限](https://developer.android.com/about/versions/13/changes/notification-permission?hl=ja)


後はパッケージサンプル説明の通り、権限要求のコードを呼び出せば大丈夫です。

```dart:
      PermissionStatus permissionStatus =
          await NotificationPermissions.requestNotificationPermissions();
```

# フォアグラウンドでプッシュ通知を受けてバナーを表示する

LINEとかでよく見るバナー通知を表示するためには、通知チャネルを作成して、重要度を高にしないとダメなようです。

```dart:
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
  FlutterLocalNotificationsPlugin();

const AndroidNotificationChannel channel = AndroidNotificationChannel(
    'channel_id',
    'high importance channel',
    importance: Importance.max,
  );


await flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin>()
        ?.createNotificationChannel(channel);

```

次にフォアグラウンドでバナーを表示するためには、[flutter\_local\_notifications ](https://pub.dev/packages/flutter_local_notifications)を使って、ローカルプッシュ通知の呼び出しが必要とのことです。
参考:[Flutter×Firebase(CloudMessaging)で、フォアグラウンド/バックグラウンドで通知をしてみる - Qiita](https://qiita.com/kazutxt/items/158843fe3fcfe5d28186)

```dart:
// 通知アイコンの設定が必要なため事前に設定しておく
var initializationSettingsAndroid =
        const AndroidInitializationSettings('@mipmap/ic_launcher');
    var initializationSettings =
        InitializationSettings(android: initializationSettingsAndroid);
    await flutterLocalNotificationsPlugin.initialize(initializationSettings);

// flutter_local_notificationsでバナー表示
FirebaseMessaging.onMessage.listen((message){
  RemoteNotification? notification = message.notification;
  AndroidNotification? android = message.notification?.android;

  if (notification != null && android != null) {
    flutterLocalNotificationsPlugin.show(
      notification.hashCode,
      notification.title,
      notification.body,
      NotificationDetails(
        android: AndroidNotificationDetails(
          channel.id,
          channel.name,
        ),
      ),
    );
  }
});


```

参考:[Notifications | FlutterFire](https://firebase.flutter.dev/docs/messaging/notifications/#foreground-notifications)

# バックグランドでプッシュ通知を受けてバナー表示する

```dart:
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {

  print("Handling a background message: ${message.messageId}");
}

void main() {
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  runApp(MyApp());
}
```

イベントハンドラはログ出力するコードしかありませんが、これでバナー表示されます。

ただし、重要度高の通知チャネルで処理する必要があるため、
プッシュ通知送信時に通知チャネルを指定するか、AndroidManifest.xmlにデフォルト通知チャネルの指定を追加するかのどちらが必要です。

```:AndroidManifest.xml
<application
    <meta-data
                android:name="com.google.firebase.messaging.default_notification_channel_id"
                android:value="channel_id" />
```


参考:[Cloud Messaging | FlutterFire](https://firebase.flutter.dev/docs/messaging/usage/)

以上！