user icon

AndroidのPush通知のバック/フォアグラウンド処理でページ移動

前回はflutter_local_notificationsでフォアグラウンド通知を試しましたが、今回は続いてバックグラウンド処理やクリックでのページ移動をしてみます。

dartファイル編集

lib/fcm.dart を新規作成

Firebase Cloud Messagingの処理用ファイルを追加します。
主な機能は以下の4つ。
  • globalで使用するAndroidNotificationChannel FlutterLocalNotificationsPlugin GlobalKey 用の変数を定義します。
  • iniFCM()で初期化及び、通知ウィンドウタップ時に処理する関数onDidReceiveNotificationResponseを指定・作成します。
  • バック/フォアグラウンド時の処理をするdispMessage()を作成します。
  • class MessageViewはタップ時、バックグラウンドから復帰時に移動するページです(簡易的にテキストのみにしています)。
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

// Params
late AndroidNotificationChannel channel;
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;

final navigatorKey = GlobalKey<NavigatorState>(); // NavigatorKeyをグローバルに定義

// 初期化
Future<void> initFCM() async{
  final fcmToken = await FirebaseMessaging.instance.getToken(); // FCMトークンの取得
  print('FCM Token: $fcmToken');

  // local notificaitons
  channel = AndroidNotificationChannel(
    'high_importance_channel', // id
    'High Importance Notifications', // title
    description: 'This channel is used for important notifications.', // description
    importance: Importance.max,
  );

  // init
  flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
  // request permission Android 13
  await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<
    AndroidFlutterLocalNotificationsPlugin>()?.requestNotificationsPermission();
  // create channel
  await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<
    AndroidFlutterLocalNotificationsPlugin>()?.createNotificationChannel(channel);

  // onTap
  const AndroidInitializationSettings initializationSettingsAndroid =
    AndroidInitializationSettings('launch_background');
  const InitializationSettings initializationSettings =
    InitializationSettings(android: initializationSettingsAndroid);
  await flutterLocalNotificationsPlugin.initialize(initializationSettings,
    onDidReceiveNotificationResponse: onDidReceiveNotificationResponse
  );

  // フォアグラウンド
  FirebaseMessaging.onMessage.listen((RemoteMessage message) {
    dispMessage('Fore', message);
  });

  // バックグラウンド
  FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
    dispMessage('Back', message);
  });
}

// 通知表示
void dispMessage(String mode, RemoteMessage message){
  print('$mode Message notification: ${message.notification?.title} / ${message.notification?.body}');
  print('$mode Message data: ${message.data}');

  //
  if(mode == 'Fore'){
    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,
            channelDescription: channel.description,
            icon: 'launch_background',
          ),
        ),
        payload: '/message',
      );
    }
  }else if(mode == 'Back'){
    final Map<String, RemoteMessage> args = {'message': message};
    navigatorKey.currentState?.pushNamed('/message', arguments: args);
  }
}

// タップ時
void onDidReceiveNotificationResponse(NotificationResponse details) {
  print('Message pressed');
  //
  final String? payload = details.payload;
  if(payload is String){
    final Map<String, NotificationResponse> args = {'details': details};
    navigatorKey.currentState?.pushNamed(payload, arguments: args);
  }
}


//
class MessageView extends StatelessWidget{
  const MessageView({super.key});

  @override
  Widget build(BuildContext context) {
    //
    String text = '';
    final Map<String, dynamic>? args = ModalRoute.of(context)?.settings.arguments as Map<String, dynamic>?;
    if(args is Map<String, dynamic>){
      for(var key in args.keys){
        if(key == 'details'){
          final NotificationResponse details = args[key];
          print('NotificaitonResponse.id: ${details.id}');
          text = 'Accept details';
        }else if(key == 'message'){
          final RemoteMessage message = args[key];
          print('RemoteMessage title = ${message.notification?.title}');
          text = 'Accept message';
        }
      }
    }
    //
    return Text('Message Page\n$text');
  }
}

lib/main.dart

importを以下のように変更(test202502はflutter create時のプロジェクト名に変更)。
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:test202502/firebase_options.dart';
import './fcm.dart';
main()を以下のように変更。
void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); // Firebaseの初期化
  await initFCM();
  // run
  runApp(const MyApp());
}
class MyAppのbuild()のhomeを消して、routesとnavigatorKeyを追加。
      //home: const MyHomePage(title: 'Flutter Demo Home Page'),
      routes: {
        '/': (context) => MyHomePage(title: 'Flutter Demo Home Page'),
        '/message': (context) => MessageView(),
      },
      navigatorKey: navigatorKey,

ビルド

前回のプロジェクト同様、android/app/build.gradle.kts を編集したらビルド&プレイ。
画面が表示されたら、〇等をタップしてホーム画面に戻ります。
通知を受けると音が鳴るので、上部バーをスライド表示させると、通知が来ています。
通知をタップすると、内部でonMessageOpenedAppが動作して、dispMessage()を実行。
/messageページに、messageを渡して移動します。
移動すると、引数にmessageを受け取ったので、Message Page Accept messageと表示されます。
◁を押して元の画面に戻します。
今度はこの画面を表示した状態で通知を受け取って、表示されたウィンドウをタップしてみます。
ウィンドウのdetailsを引数として受け取ったので、今度はMessage Page Accept detailsと表示されます。
Facebooktwitterlinkedintumblrmail

タグ:

コメントは受け付けていません。