Flutter アプリ(iOS・Android)で、Firebase Cloud Messaging のpush通知を受け取った際やタップした際に実行したい処理を定義します。
アプリで Firebase Cloud Messaging の通知を受け取るために、firebase_messagingを利用している他、機能の実装に直接関係はありませんが状態管理にRiverpodを利用しています。
アプリの状態の定義
状態 | 説明 |
---|---|
フォアグラウンド | アプリが開いている状態で、表示または使用されている。 |
バックグラウンド | アプリは開いているが、バックグラウンドで実行されている(最小化されている)。通常、この状態はユーザーがデバイスのホームボタンを押した場合、アプリ スイッチャーを使用して別のアプリに切り替えた場合、アプリを別のタブ(ウェブ)で開いた場合に発生します。 |
終了状態 | デバイスがロックされているか、アプリケーションが実行されていない状態。 |
(https://firebase.google.com/docs/cloud-messaging/flutter/receive?hl=ja より引用)
フォアグラウンド状態でpush通知を受け取った時
onMessage
を使います。
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print("Android onMessage: ${message.notification}");
});
push通知をタップしてバックグラウンド状態からフォアグラウンド状態に変化した時
onMessageOpenedApp
を使います。
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print("onMessageOpenedApp: ${message.notification}");
});
push通知が来た後に、push通知のタップ以外で開いた場合には実行されないので注意。こういったケースでは、initState()
やuseState()
で、アプリの状態監視を行い実行するようにします。
final lifecycleState = useAppLifecycleState(); // require flutter_hooks
if (lifecycleState == AppLifecycleState.resumed) {
// アプリが他の状態からフォアグラウンド状態になった時に実行する
}
push通知をタップして終了状態からフォアグラウンド状態に変化した時
getInitialMessage()
を使います。
final messaging = FirebaseMessaging.instance;
messaging.getInitialMessage().then((message) {
print("getInitialMessage: ${message.notification}");
});
バックグラウンド状態でpush通知を受け取った時
以下の条件を踏まえた上でonBackgroundMessage
を使います。(https://firebase.google.com/docs/cloud-messaging/flutter/receive?hl=ja#apple_platforms_and_android より引用)
- 匿名関数は使用できません。
FirebaseMessaging.onBackgroundMessage((message) {
// NG: 匿名関数
print("onBackgroundMessage: ${message.notification}");
}
関数を定義してから渡す必要があります。
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
- トップレベル関数にする必要があります(初期化を必要とするクラスメソッドなどは使用できません)。
呼び出すクラス内で関数を宣言できない。そのため、MVVMを使って通知周りの処理を行う場合、ViewModelなどの中でProviderの参照ができません。
@Riverpod(keepAlive: true)
class FcmViewModel extends _$FcmViewModel {
late RepositoryInterface _repository;
@override
FutureOr<String?> build() async {
_repository = ref.read(repositoryProvider);
return null;
}
Future<void> initializeNotification() async {
...
// NG: 呼び出す関数がトップレベル関数ではない
FirebaseMessaging.onBackgroundMessage(
_firebaseMessagingBackgroundHandler);
}
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
print("Handling a background message: ${message.messageId}");
}
}
- Flutter バージョン 3.3.0 以降を使用している場合、関数宣言のすぐ上でメッセージ ハンドラに
@pragma('vm:entry-point')
アノテーションを付ける必要があります
これら3点を踏まえると、onBackgroundMessage
を使用する場合は、以下のようになります。
// バックグラウンド・終了状態で通知を受け取った時に実行する関数
// トップレベル関数として定義する
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
print("Handling a background message: ${message.messageId}");
}
@Riverpod(keepAlive: true)
class FcmViewModel extends _$FcmViewModel {
late RepositoryInterface _repository;
@override
FutureOr<String?> build() async {
_repository = ref.read(repositoryProvider);
return null;
}
Future<void> initializeNotification() async {
...
FirebaseMessaging.onBackgroundMessage(
_firebaseMessagingBackgroundHandler);
}
}
iOSの場合は、これに加えてpayload
に"content-available": 1
を指定してpush通知を送信する必要があります。
apns > payload > aps
の入れ子構造にする必要があります。
{
"message":{
"token": "push_notification_token",
"notification":{
"title": "テスト",
"body": "テスト通知です"
},
"apns": {
"payload": {
"aps": {
"content-available": 1
}
}
}
}
}
Firebaseコンソールからの通知送信ではpayloadが指定できないため、iOSではFirebaseコンソールからの通知送信を受け取った際の、onBackgroundMessage
によるバックグラウンド処理が実行できません。Firebase Admin SDKを使って通知を送信する必要があります。
フォアグラウンド状態でpush通知をタップした時
Android
Androidの場合、フォアグラウンド状態でのpush通知は、flutter_local_notification
というパッケージを使って表示させる必要があります。その初期化処理で、フォアグラウンド状態でpush通知をタップした時に実行する処理を指定します。
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()!
.requestNotificationsPermission();
flutterLocalNotificationsPlugin.initialize(
const InitializationSettings(
android: AndroidInitializationSettings('@drawable/android_notification_icon'),
),
// Androidで、フォアグラウンド状態でpush通知をタップした時の処理
onDidReceiveNotificationResponse: (NotificationResponse response) async {
if (response.payload != null) {
print('Notification tapped with payload: ${response.payload}');
}
}
);
flutterLocalNotificationsPlugin.initialize
のonDidReceiveNotificationResponse
で指定できます。
iOS
onMessageOpenedApp
に指定した処理が実行されます。バックグラウンドからフォアグラウンドに変わった場合と処理を分けたい場合は、アプリの状態監視を行って、処理を場合分けをします。