Search code examples
flutterfirebasefirebase-cloud-messaging

Flutter firebase receiving notification when closed or in background - How to show dialog with message


`I'm developing a Flutter app that utilizes Firebase push notifications, and I'm relatively new to mobile development.

I'm facing challenges with implementing a feature where, upon receiving a message, the app should display a popup modal with the message text. The popup modal successfully displays when the app is in the foreground.

However, I encounter two issues:

When I set up background messaging and use FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);, I encounter errors during app execution. The specific error is _TypeError (Null check operator used on a null value).

Additionally, I would like the app to receive messages when it's in the background or the screen is locked. When the user unlocks the screen and navigates to the app, I want the popup modal to display the received data from the notification.


Solution

  • I guess you may not have been able to update the updated notification classes. So I'll show you the API I use for notifications and let you know where you should call it. Here is the class I use for notification;

             import 'dart:developer';
             
             import 'package:app_settings/app_settings.dart';
             import 'package:firebase_messaging/firebase_messaging.dart';
             import 'package:flutter/foundation.dart';
             import 'package:flutter/material.dart';
             import 'package:flutter_local_notifications/flutter_local_notifications.dart';
             import 'package:hive/hive.dart';
             
             import '../app_utils/common.dart';
             
             class PushNotificationsManager {
               PushNotificationsManager._();
             
               factory PushNotificationsManager() => _instance;
             
               static final PushNotificationsManager _instance =
               PushNotificationsManager._();
             
               //initialising firebase message plugin
               late final FirebaseMessaging _messaging = FirebaseMessaging.instance;
               late final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
               FlutterLocalNotificationsPlugin();
             
               AndroidNotificationChannel createNotificationChannel() {
                 return const AndroidNotificationChannel(
                   'High Importance Channel',
                   'High Importance Notifications',
                   importance: Importance.high,
                 );
               }
             
               AndroidNotificationDetails createNotificationDetails(
                   AndroidNotificationChannel channel) {
                 return AndroidNotificationDetails(
                   channel.id.toString(),
                   channel.name.toString(),
                   channelDescription: channel.description.toString(),
                   importance: Importance.high,
                   groupKey: channel.groupId,
                   priority: Priority.high,
                 );
               }
             
               // function to request notifications permissions
               void requestNotificationPermission() async {
                 NotificationSettings settings = await _messaging.requestPermission(
                     alert: true,
                     announcement: true,
                     badge: true,
                     carPlay: true,
                     criticalAlert: true,
                     provisional: true,
                     sound: true);
             
                 if (settings.authorizationStatus == AuthorizationStatus.authorized) {
                   debugPrint('user granted permission');
                 } else if (settings.authorizationStatus ==
                     AuthorizationStatus.provisional) {
                   debugPrint('user granted provisional permission');
                 } else {
                   AppSettings.openAppSettings(type: AppSettingsType.notification);
                   debugPrint('user denied permission');
                 }
               }
             
               //function to initialise flutter local notification plugin to show notifications for android when app is active
               void initLocalNotifications(
                   BuildContext context, RemoteMessage message) async {
                 var androidInitializationSettings =
                 const AndroidInitializationSettings('@mipmap/launcher_icon');
                 var iosInitializationSettings = const DarwinInitializationSettings();
             
                 var initializationSetting = InitializationSettings(
                     android: androidInitializationSettings, iOS: iosInitializationSettings);
             
                 await _flutterLocalNotificationsPlugin.initialize(
                   initializationSetting,
                   onDidReceiveNotificationResponse: (payload) {
                     handleMessage(message);
                   },
                 );
               }
             
               void firebaseInit(BuildContext context) {
                 FirebaseMessaging.onMessage.listen((message) {
                   initLocalNotifications(context, message);
                   showNotification(message);
                 });
               }
             
               // function to show visible notification when app is active
               Future<void> showNotification(RemoteMessage message) async {
                 const DarwinNotificationDetails darwinNotificationDetails =
                 DarwinNotificationDetails(
                     presentAlert: true, presentBadge: true, presentSound: true);
             
                 NotificationDetails notificationDetailsPlatformSpecific =
                 NotificationDetails(
                     android: createNotificationDetails(createNotificationChannel()),
                     iOS: darwinNotificationDetails);
             
                 showDefaultNotification(message.notification!.title ?? "",
                     message.notification!.body!, notificationDetailsPlatformSpecific);
               }
             
               void showDefaultNotification(String title, String body,
                   NotificationDetails notificationDetailsPlatformSpecific) {
                 Future.delayed(Duration.zero, () async {
                   await _flutterLocalNotificationsPlugin.show(
                     0,
                     title.toString(),
                     body,
                     notificationDetailsPlatformSpecific,
                   );
                 });
               }
             
               //function to get device token on which we will send the notifications
               Future<String> getDeviceToken() async {
                 String? deviceId = await _messaging.getToken();
                 Common.deviceToken.value = deviceId!;
                 return deviceId;
               }
             
               void isTokenRefresh() async {
                 _messaging.onTokenRefresh.listen((event) {
                   event.toString();
                   log('refresh');
                 });
               }
             
               //handle tap on notification when app is in background or terminated
               Future<void> setupInteractMessage(context) async {
                 // when app is terminated
                 RemoteMessage? initialMessage =
                 await FirebaseMessaging.instance.getInitialMessage();
                 if (initialMessage != null) {
                   handleMessage(initialMessage);
                 }
                 //when app ins background
                 FirebaseMessaging.onMessageOpenedApp.listen((event) {
                   handleMessage(event);
                 });
                 FirebaseMessaging.onBackgroundMessage(_handleBackgroundMessage);
               }
             
               Future<void> _handleBackgroundMessage(RemoteMessage message) async {
                 handleMessage(message);
               }
             
               void handleMessage(RemoteMessage message) {
                 if (message.notification!.body!.contains("")) {}
               }
             }
    

    Now You can use it in MyApp class

    class MyApp extends StatefulWidget {
       const MyApp({super.key});
    
      @override
      State<MyApp> createState() => _MyAppState();
      }
    
     class _MyAppState extends State<MyApp> {
     @override
     void initState() {
       PushNotificationsManager().requestNotificationPermission();
       PushNotificationsManager().firebaseInit(context);
       PushNotificationsManager().setupInteractMessage(context);
       //notificationServices.isTokenRefresh();
       PushNotificationsManager().getDeviceToken().then((value) {
      debugPrint('device token');
      debugPrint(value);
    });   
    super.initState();
    }