Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

firebase_messaging onBackgroundMessage local_notifications

I'm trying to stop default notification from firebase_message when app is closed or on background.

I want to show a custom Notification when app is closed or on background using local_notifications plugin, which works as expected, the problem resides when message is sent, app shows the same notification twice, 1 by default notification and the other with the custom notification.

I can not achieve to stop default notification. Can anyone point out my mistake here?

Initial code is from firebase messaging example removing unnecessary snippets and adding custom notification.

Also attached an image of the current (bad behaviour)

enter image description here

As stated before, same notification shown twice, want to get rid of the first one showed on the image.

Here's my code:

// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'utils/utils.dart';

Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  print('_firebaseMessagingBackgroundHandler');

  Future onDidReceiveLocalNotification(
      int? id, String? title, String? body, String? payload) async {
    print('onDidReceiveLocalNotification');
  }

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

  var flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

  final initializationSettingsAndroid =
      AndroidInitializationSettings('icon_app');
  final initializationSettingsIOS = IOSInitializationSettings(
      onDidReceiveLocalNotification: onDidReceiveLocalNotification);
  final initializationSettingsMacOS = MacOSInitializationSettings();

  await flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation<
          AndroidFlutterLocalNotificationsPlugin>()
      ?.createNotificationChannel(channel);
  final initializationSettings = InitializationSettings(
      android: initializationSettingsAndroid,
      iOS: initializationSettingsIOS,
      macOS: initializationSettingsMacOS);
  await flutterLocalNotificationsPlugin.initialize(
    initializationSettings,
    onSelectNotification: onSelectNotification,
  );

  ///Not able to stop default notification
  ///there fore when custom notification is called
  ///result is 2 notifications displayed.
  NotificationDetails _notificationDetails;
  _notificationDetails = await customNotification(message: message);
  flutterLocalNotificationsPlugin.show(
    message.notification.hashCode,
    message.notification!.title,
    message.notification!.body,
    _notificationDetails,
    payload: '',
  );

  // await Firebase.initializeApp();
  print('Handling a background message ${message.messageId}');
}

Future<NotificationDetails> customNotification(
    {required RemoteMessage message}) async {
  print('notificationDetailsBigImage');
  final utils = Utils();

  final bigPicturePath = await utils.downloadAndSaveFile(
      url: 'https://picsum.photos/536/354', fileName: 'bigPicture');
  final bigPictureStyleInformation = BigPictureStyleInformation(
    FilePathAndroidBitmap(bigPicturePath),
    hideExpandedLargeIcon: true,
  );
  final androidPlatformChannelSpecifics = AndroidNotificationDetails(
    'big text channel name',
    'big text channel name',
    'big text channel description',
    styleInformation: bigPictureStyleInformation,
    icon: 'icon_app',
    color: const Color.fromARGB(255, 255, 0, 0),
    ledColor: const Color.fromARGB(255, 255, 0, 0),
    ledOnMs: 1000,
    ledOffMs: 500,
  );
  return NotificationDetails(android: androidPlatformChannelSpecifics);
}

Future<void> onDidReceiveLocalNotification(
    int? id, String? title, String? body, String? payload) async {
  print('onDidReceiveLocalNotification');
}

Future<void> onSelectNotification(String? payload) async {
  print('onSelectNotification');
}

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

  await Firebase.initializeApp();
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

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

  runApp(MessagingExampleApp());
}

/// Entry point for the example application.
class MessagingExampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Messaging Example App',
      theme: ThemeData.dark(),
      routes: {
        '/': (context) => Application(),
      },
    );
  }
}

/// Renders the example application.
class Application extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _Application();
}

class _Application extends State<Application> {
  late String _token;

  @override
  void initState() {
    super.initState();
    FirebaseMessaging.instance.getInitialMessage().then((message) {
      print('instance');
      if (message != null) {
        print('do stuff');
      }
    });

    FirebaseMessaging.onMessage.listen((message) {
      print('onMessage');
    });

    FirebaseMessaging.onMessageOpenedApp.listen((message) {
      print('A new onMessageOpenedApp event was published!');
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold();
  }
}
like image 540
yaguarete Avatar asked Dec 22 '22 15:12

yaguarete


1 Answers

Ok, this was a mistake from my side. After reading FCM docs, it seems there are two types of FCM Push: Notifications and Data.

Notifications have a default behaviour which is the displaying the current default Push notification. While setting a Data Message push, will not trigger default behaviour leaving you to decide what to do.

Example of Notification payload

"token"=> "...."    
"data" => ["notificationDisplay" => "bigImage"],
            "notification" => [ //<-- this will trigger a Push notification
               "title" => $title,
               "body" => $message,
             ],
            ...

Example of Data Message payload

"token"=> "...."    
"data" => ["notificationDisplay" => "bigImage"],
// without notification on payload will trigger 
//Data Message, as expected you will need to declare 
//all fields you logic expects on data structure.        
           

In other words two prevent default default push, will need to send a data message and add corresponding logic.

like image 53
yaguarete Avatar answered Mar 25 '23 00:03

yaguarete