Navigate to another screen when I click on Firebase push notification either in foreground or background in Flutter

Viewed 1444

I use Firebase messaging in my Flutter app , I want to navigate to another screen when I click on the notification even my app is in foreground or background , I used many functions and it doesn't trigger the click event and I can't find anything can solve my problem .

When I click on the notification when app is in foreground or background , nothing happened because it navigate to the same page . And when I click on the notification when app is terminated , it opens on Splash screen and go to the home not the screen that I want .

I added this intent-filter in my Manifest

  <intent-filter>
                <action android:name="FLUTTER_NOTIFICATION_CLICK" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

And I added this to the Json object

"click_action": "FLUTTER_NOTIFICATION_CLICK",

And here is how can I get background FCM in the main.dart

const AndroidNotificationChannel channel = AndroidNotificationChannel(
    'high_importance', // id
    'High Importance Notifications', // title
    importance: Importance.high,
    playSound: true);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();


Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  SessionManager sessionManager = SessionManager();

  await Firebase.initializeApp();
  //final sound = 'sound.mp3';
  print('A bg message just showed up :  ${message.messageId}');

  final android = AndroidInitializationSettings('@mipmap/ic_launcher');
  final ios = IOSInitializationSettings(
    requestSoundPermission: false,
    requestBadgePermission: false,
    requestAlertPermission: false,);
  final settings = InitializationSettings(android: android,iOS: ios);
  flutterLocalNotificationsPlugin.initialize(settings,);
  if(message.data['title'].toString().toLowerCase()=="new request") {
    sessionManager.getBadge().then((badge) {
      if (badge != null) {
        int x = badge + 1;
        sessionManager.saveBadge(x);
        print("notification number is " + x.toString());
      }
      else {
        sessionManager.saveBadge(1);
      }
    });

  }

  flutterLocalNotificationsPlugin.show(
      message.data.hashCode,
      message.data['title'],
      message.data['body'],
      NotificationDetails(
        android: AndroidNotificationDetails(
          channel.id,
          channel.name,
          importance: Importance.high,
          priority: Priority.high,
         // sound: RawResourceAndroidNotificationSound(sound.split('.').first),
          playSound: true,
          icon: '@mipmap/ic_launcher',
        ),

      ));
  /*NotificationApi.showNotification(
      title: message.data['title'],
      body: message.data['body'],
      payload: "",
      id:  int.parse(channel.id));*/

}


Future<void>  main() async{
  WidgetsFlutterBinding.ensureInitialized();

  await Firebase.initializeApp();
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  await flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation<
      AndroidFlutterLocalNotificationsPlugin>()
      ?.createNotificationChannel(channel);

  await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
    alert: true,
    badge: true,
    sound: true,

  );
  


  runApp(MyApps());
  // configLoading();

}


class MyApps extends StatefulWidget {
  const MyApps({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    return MyApp();
  }
}


class MyApp extends State<MyApps> {
  static  ValueNotifier<int> strikeNotifier = ValueNotifier(0);

  Color _primaryColor =  Color(0xff0d8b75);


  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return ScreenUtilInit(
      builder: () => MaterialApp(
        debugShowCheckedModeBanner: false,
        home: SplashScreen(),
      ),
      designSize: const Size(1080, 2280),
    );
  }


  void showNotification(String title, String body) async {
    await _demoNotification(title, body);
  }

  Future<void> _demoNotification(String title, String body) async {
    var androidPlatformChannelSpecifics = AndroidNotificationDetails(
        'channel_I', 'channel name',
        showProgress: true,
        priority: Priority.high,
        playSound: true,
        ticker: 'test ticker');

    var iOSChannelSpecifics = IOSNotificationDetails();
    var platformChannelSpecifics = NotificationDetails(
        android: androidPlatformChannelSpecifics, iOS: iOSChannelSpecifics);
    await flutterLocalNotificationsPlugin
        .show(0, title, body, platformChannelSpecifics, payload: 'test');
  }

  @override
  void initState() {
    super.initState();

       FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) {
  if (message != null) {
    Navigator.push(context, MaterialPageRoute(builder: (context)=>DoneAndPaiedPagess(0)));

  }
});

    getToken().then((value) {
      if(value!=null) {
        AppConstants.firebaseToken = value;
      }
    });


    FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
    new FlutterLocalNotificationsPlugin();
    var initializationSettingsAndroid =  AndroidInitializationSettings('@mipmap/ic_launcher');
    var initializationSettingsIOS =  IOSInitializationSettings();
    var initializationSettings =  InitializationSettings(android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
    flutterLocalNotificationsPlugin.initialize(initializationSettings,
      );



    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      var data = message.data;
      //  AndroidNotification? android = message.notification?.android;/


      if (data != null ) {
        if(data['title'].toString().toLowerCase()=="new request") {
          SessionManager sessionManager = SessionManager(context);
          sessionManager.getBadge().then((badge) {
            if (badge != null) {
              setState(() {
                int x = badge + 1;
                strikeNotifier.value = x;
                sessionManager.saveBadge(x);
              });
            }
            else {
              strikeNotifier.value = 1;
              sessionManager.saveBadge(1);
            }
          });
        }
        print("entered");
        flutterLocalNotificationsPlugin.show(
            data.hashCode,
            data['title'],
            data['body'],
            NotificationDetails(
              android: AndroidNotificationDetails(
                channel.id,
                channel.name,
                playSound: true,
                icon: '@mipmap/ic_launcher',
              ),
            ));

      }
    });
   FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
  Navigator.push(context, MaterialPageRoute(builder: (context)=>DoneAndPaiedPagess(0)));

});
   
  }

  Future<String?> getToken() async{
    String? token = await FirebaseMessaging.instance.getToken();
    print("token is "+token!);
    return token;

  }
}

In yaml

 firebase_core: ^1.12.0
  firebase_messaging: ^11.2.6
dependency_overrides:
  firebase_messaging_platform_interface: 3.1.6

Edit : from multiple solutions , I tried the most common solution that I used onMessageOpenedApp in initState but it doesn't enter in it

FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      Navigator.push(context, MaterialPageRoute(builder: (context)=>DoneAndPaiedPagess(0)));
    });
3 Answers

In your code, you are using the flutter_local_notifications plugin and you are creating local notification when you get a push notification from firebase messaging.

Since the notification is not created by firebase messaging so, you are not getting on tap callback in getInitialMessage and onMessageOpenedApp.

In order to get on tap callback on local notifications, you can pass a callback function while initializing flutter_local_notifications

flutterLocalNotificationsPlugin.initialize(initializationSettings,
    onSelectNotification: onSelectNotification);

void selectNotification(String payload) async {
    if (payload != null) {
      debugPrint('notification payload: $payload');
// Here you can check notification payload and redirect user to the respective screen
      await Navigator.push(
         context,
         MaterialPageRoute<void>(builder: (context) => SecondScreen(payload)),
      );
    }
}

For more, you can check flutter_local_notifications documentation

Use onMessageOpenedApp stream to listen when a notification is opened in the foreground or background. When the application is terminated, use getInitialMessage to get a pending notification.

On your home widget within initState, check the getInitialMessage value :

// get the remote message when your app opened from push notification while in background state
RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage();

// check if it is exists
if (initialMessage != null) {
    // check the data property within RemoteMessage and do navigate based on it
}

Check the firebase flutter documentation here https://firebase.flutter.dev/docs/messaging/notifications/#handling-interaction.

Related