Firebase Messaging - Data only messages are not received if iOS device is restarted

Viewed 122

I am building a Flutter app with Firebase Messaging. I am using AwesomeNotifications plugin to display the notifications.

My notifications is a data only notification, because adding the notification property triggers the default SDK notification as well causing duplicate notifications.

The issue is, if I restarted my iOS device, I no longer receive the data only notification. If I send the same notification with the notification property added, the SDK generated notification get displayed. However if I reopen the app after the restart, the notifications will continue to recieve.

In Android, no issues at all.

I have tested this with iOS 15.3.1 running in iPhone 6s.

Below is my JSON code.

"message": {
                    "token": recieverFcm,
                    "data": {
                        "name": senderName,
                        "body": "Image Sent",
                        "chatRoomId": chatRoomId,
                        "sender_profile_pic": senderProfilePic,
                        "senderUid": senderUid,
                        "data_type": messageType,
                        "image_link": message,
                        "click_action": "OPEN_CHAT_ROOM"
                    },
                    "android": {
                        "priority": "high"
                    },
                    "apns": {
                        "payload": {
                            "aps": {
                                "category": "OPEN_CHAT_ROOM",
                                "sound": "enable",
                                "content-available": 1,
                            }
                        }
                    }
                }

main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  NotificationController _notificationController = NotificationController();

  //Initialize firebase
  await Firebase.initializeApp();
  await _notificationController.startNotificationService();

  //Listen for the Token change
  FirebaseMessaging.instance.onTokenRefresh.listen((String token) {
    print("New token: $token");
  });

//Apply MultiProvider
  runApp(MultiProvider(
    providers: [
      //provider lists
    ],
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    NotificationController _notificationController = NotificationController();
    _notificationController.startAwesomeNotificationlistener();

    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        textTheme: GoogleFonts.poppinsTextTheme(),
        primaryColor: primaryColor,
        backgroundColor: Colors.white,
        scaffoldBackgroundColor: Colors.white,
        accentColor: darkColor,
        appBarTheme: AppBarTheme(
            backgroundColor: Colors.white,
            elevation: 0,
            iconTheme: IconThemeData(color: Colors.black),
            titleTextStyle: GoogleFonts.poppins(
                fontSize: 16, color: darkColor, fontWeight: FontWeight.w500)),
        textSelectionTheme: TextSelectionThemeData(cursorColor: darkColor),
        outlinedButtonTheme: OutlinedButtonThemeData(style: outlineButtonStyle),
        elevatedButtonTheme:
            ElevatedButtonThemeData(style: elevatedButtonStyle),
      ),
      routes: {
        //Routes go here
      },
      home: LoadingScreen3(),
    );
  }
}

notification_controller.dart

class NotificationController {
  ///Start notification service
  Future<void> startNotificationService() async {
    NotificationService _notificationService = NotificationService();

    await _notificationService.initializFirebaseeNotifications();
  }

  ///Display a new notification in foreground
  Future<void> displayNotification({
    required String groupKey,
    required String channelKey,
    required String title,
    required String body,
    required String summary,
    required NotificationLayout layout,
    required bool displayOnBackground,
    required bool displayOnForeground,
    required String messageType,
    String? clickAction,
    String? chatRoomId,
    String? chatMessageFrom,
  }) async {
    NotificationService _notificationService = NotificationService();
    await _notificationService.createAwesomeNotification(
        groupKey: groupKey,
        channelKey: channelKey,
        title: title,
        body: body,
        summary: summary,
        layout: layout,
        displayOnBackground: displayOnBackground,
        displayOnForeground: displayOnForeground,
        messageType: messageType,
        clickAction: clickAction,
        chatRoomId: chatRoomId,
        chatMessageFrom: chatMessageFrom);
  }

  //Start awesome notification listener
  void startAwesomeNotificationlistener() {
    NotificationService _notificationService = NotificationService();
    _notificationService.startAwesomeNotificationListener();
  }
}

notification_service.dart

class NotificationService with ChangeNotifier {
  FirebaseMessaging _messaging = FirebaseMessaging.instance;

  ///Start initializing the notification service
  Future<void> initializFirebaseeNotifications() async {
    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

    //Request permission for firebase messaging
    NotificationSettings settings = await _messaging.requestPermission(
      alert: true,
      announcement: false,
      badge: true,
      carPlay: false,
      criticalAlert: false,
      provisional: false,
      sound: true,
    );

    if (settings.authorizationStatus == AuthorizationStatus.authorized) {
      print('User granted permission');

      FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
        RemoteNotification? notification = message.notification;
        AndroidNotification? android = message.notification?.android;
        developer.log("REMOTE MESSAGE LISTENER");
        print("REMOTE MESSAGE LISTENER");
        if (message.data["data_type"] == "TEXT") {
          await createAwesomeNotification(
              groupKey: message.data["senderUid"],
              channelKey: 'basic_channel',
              title: message.data["name"],
              body: message.data["body"],
              summary: message.data["body"],
              layout: NotificationLayout.Messaging,
              displayOnBackground: true,
              displayOnForeground: true,
              messageType: message.data["data_type"],
              clickAction: message.data["click_action"],
              chatRoomId: message.data["chatRoomId"],
              chatMessageFrom: message.data["senderUid"]);
        } else if (message.data["data_type"] == "IMAGE") {
          await createAwesomeNotification(
            groupKey: message.data["senderUid"],
            channelKey: 'basic_channel',
            title: message.data["name"],
            body: Emojis.art_framed_picture + " " + message.data["body"],
            summary: message.data["body"],
            layout: NotificationLayout.Messaging,
            displayOnBackground: true,
            displayOnForeground: true,
            messageType: message.data["data_type"],
            clickAction: message.data["click_action"],
            chatRoomId: message.data["chatRoomId"],
            chatMessageFrom: message.data["senderUid"],
          );
        }
      });
    } else {
      print('User declined or has not accepted permission');
    }

    /// Update the iOS foreground notification presentation options to allow
    /// heads up notifications.
    await FirebaseMessaging.instance
        .setForegroundNotificationPresentationOptions(
      alert: true,
      badge: true,
      sound: true,
    );

    FirebaseMessaging.instance
        .getInitialMessage()
        .then((RemoteMessage? message) {
      developer.log("REMOTE MESSAGE");
      if (message != null) {
        developer.log(message.data.toString());
      }
    });

    // For handling notification when the app is in background
    // but not terminated
    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      print("onMessageOpenedApp executed");
    });

    await initializeAwesomeNotifications();
  }

  //Initialize the notification display plugin
  Future<void> initializeAwesomeNotifications() async {
    AwesomeNotifications().initialize('resource://drawable/logo', [
      NotificationChannel(
          channelGroupKey: 'basic_tests',
          channelKey: 'basic_channel',
          channelName: 'Basic notifications',
          channelDescription: 'Notification channel for basic tests',
          defaultColor: Color(0xFF9D50DD),
          ledColor: Colors.white,
          importance: NotificationImportance.High),
    ]);
  }

//Create and display notification
  Future createAwesomeNotification({
    required String groupKey,
    required String channelKey,
    required String title,
    required String body,
    required String summary,
    required NotificationLayout layout,
    required bool displayOnBackground,
    required bool displayOnForeground,
    required String messageType,
    String? clickAction,
    String? chatRoomId,
    String? chatMessageFrom,
  }) async {
    await AwesomeNotifications().createNotification(
      content: NotificationContent(
          id: UniqueKey().hashCode,
          groupKey: groupKey,
          channelKey: channelKey,
          title: title,
          body: body,
          summary: summary,
          notificationLayout: layout,
          displayOnBackground: displayOnBackground,
          displayOnForeground: displayOnForeground,
          payload: {
            "messageType": messageType,
            "clickAction": clickAction ?? "",
            "chatRoomId": chatRoomId ?? "",
            "chatMessageFrom": chatMessageFrom ?? ""
          }),
    );
  }

  //Start Awesome notification listener
  void startAwesomeNotificationListener() {
    AwesomeNotifications()
        .actionStream
        .listen((ReceivedNotification receivedNotification) {
      developer.log("Notification clicked");
      developer.log(receivedNotification.body ?? "no data");
    });
  }
}

// Declared as global, outside of any class
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  // If you're going to use other Firebase services in the background, such as Firestore,
  // make sure you call `initializeApp` before using other Firebase services.
  await Firebase.initializeApp();
  NotificationController _notificationController = NotificationController();
  developer.log("background listener called");
  print("Handling a background message: ${message.data}");
  RemoteNotification? notification = message.notification;
  AndroidNotification? android = message.notification?.android;

// Use this method to automatically convert the push data, in case you gonna use our data standard
  //AwesomeNotifications().createNotificationFromJsonData(message.data);
  if (message.data['data_type'].toString().toUpperCase() == "TEXT") {
    print("Handling a background message: ${message.data['data_type']}");
    await _notificationController.displayNotification(
        groupKey: message.data["senderUid"],
        channelKey: 'basic_channel',
        title: message.data["name"],
        body: message.data["body"],
        summary: message.data["body"], // Anything you want here
        layout: NotificationLayout.Messaging,
        displayOnForeground: true,
        displayOnBackground: true,
        messageType: message.data["data_type"],
        clickAction: message.data["click_action"],
        chatRoomId: message.data["chatRoomId"],
        chatMessageFrom: message.data["senderUid"]);
  } else if (message.data['data_type'].toString().toUpperCase() == "IMAGE") {
    Future.delayed(Duration(seconds: 2));
    await _notificationController.displayNotification(
        groupKey: message.data["senderUid"],
        channelKey: 'basic_channel',
        title: message.data["name"],
        body: Emojis.art_framed_picture + " " + message.data["body"],
        summary: message.data["body"], // Anything you want here
        layout: NotificationLayout.Messaging,
        displayOnBackground: true,
        displayOnForeground: true,
        messageType: message.data["data_type"],
        clickAction: message.data["click_action"],
        chatRoomId: message.data["chatRoomId"],
        chatMessageFrom: message.data["senderUid"]);
  }
}

How can I fix this issue and continue to receive the data only message even after iOS device restart?

0 Answers
Related