flutter: FCM count number of notifications

3,489

This is how I do it:

//define a global variable
ValueNotifier<int> notificationCounterValueNotifer =
    ValueNotifier(0); 

You can read about ValueNotifier here.

Then when you receive a new notification, increase that value by 1:

 _fcm.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
        notificationCounterValueNotifer.value++;
        notificationCounterValueNotifer.notifyListeners(); // notify listeners here so ValueListenableBuilder will build the widget.
        

        // final snackbar = SnackBar(
        //   content: Text(message['notification']['title']),
        //   action: SnackBarAction(
        //     label: 'Go',
        //     onPressed: () => null,
        //   ),
        // );

        // Scaffold.of(context).showSnackBar(snackbar);
        showDialog(
          context: context,
          builder: (context) => AlertDialog(
                content: ListTile(
                  title: Text(message['notification']['title']),
                  subtitle: Text(message['notification']['body']),
                ),
                actions: <Widget>[
                  FlatButton(
                    color: Colors.amber,
                    child: Text('Ok'),
                    onPressed: () => Navigator.of(context).pop(),
                  ),
                ],
              ),
        );
      },
);

In order to notify listeners, you have to add ChangeNotifer as a mixin to your class:

class _MessageHandlerState extends State<MessageHandler> with ChangeNotifier

You can choose a ValueListenableBuilder to build widgets whenever the value changes. so to update the badge, we use this widget:

 ValueListenableBuilder(
              builder: (BuildContext context, int newNotificationCounterValue, Widget child) {
                // This builder will only get called when the notificationCounterValueNotifer is updated.
                return Text(newNotificationCounterValue.toString()); //return your badge here
              },
              valueListenable: notificationCounterValueNotifer,
);

You can store the value in a database document and assign it at the start of your app so your notificationCounterValueNotifer value is not 0.

If you want, you can set it to 0 again when you navigate to a notificationScreen.

There might be better ways to do this but this is how I do it.

Update: You need to return ValueListenableBuilder from myAppBarIcon:

Widget myAppBarIcon() {
    //you have to return the widget from builder method.
    //you can add logics inside your builder method. for example, if you don't want to show a badge when the value is 0.
    return ValueListenableBuilder(
      builder: (BuildContext context, int newNotificationCounterValue,
          Widget child) { 
        //returns an empty container if the value is 0 and returns the Stack otherwise
        return  newNotificationCounterValue == 0? Container(): Stack(
          children: [
            Icon(
              Icons.notifications,
              color: Colors.white,
              size: 30,
            ),
            Container(
              width: 30,
              height: 30,
              alignment: Alignment.topRight,
              margin: EdgeInsets.only(top: 2),
              child: Container(
                width: 15,
                height: 15,
                decoration: BoxDecoration(
                    shape: BoxShape.circle,
                    color: Color(0xffc32c37),
                    border: Border.all(color: Colors.white, width: 1)),
                child: Padding(
                  padding: const EdgeInsets.all(0.0),
                  child: Text(
                    newNotificationCounterValue.toString(),
                  ),
                ),
              ),
            ),
          ],
        );
      },
      valueListenable: notificationCounterValueNotifer,
    );
}
Share:
3,489
Admin
Author by

Admin

Updated on December 24, 2022

Comments

  • Admin
    Admin over 1 year

    I'm trying to create notification badge inside application (in home screen) on this code and I'm using Firebase Cloud Messaging with android app in flutter language, problem is I can't figure out how to count the number of received notification so

    Any suggested way to count the number of received notifications from Firebase Cloud Messaging to android app?

    PS: i have updated code now for the answer below and i'm still getting errors

    // import 'package:flutter/foundation.dart';
    // import 'package:flappy_search_bar/flappy_search_bar.dart';
    import 'dart:developer';
    
    import 'package:flutter/material.dart';
    import 'package:flutter/rendering.dart';
    import 'package:mycafe/main.dart';
    import 'Custom_Text.dart';
    import 'Pasta.dart';
    import 'Burger.dart';
    import 'Pizza.dart';
    import 'AboutUs.dart';
    import 'dart:async';
    import 'ui/home/HomeScreen.dart';
    import 'dart:math';
    import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:firebase_auth/firebase_auth.dart';
    import 'ContactUs.dart';
    import 'package:flutter/services.dart';
    import 'package:mycafe/model/User.dart';
    import 'package:mycafe/ui/home/HomeScreen.dart';
    import 'package:mycafe/ui/services/Authenticate.dart';
    import 'package:mycafe/ui/utils/helper.dart';
    import 'package:shared_preferences/shared_preferences.dart';
    import 'dart:async';
    import 'dart:io';
    import 'package:flushbar/flushbar.dart';
    import 'package:flushbar/flushbar_helper.dart';
    // import 'package:flutter/material.dart';
    
    import 'package:firebase_messaging/firebase_messaging.dart';
    import 'package:cloud_firestore/cloud_firestore.dart';
    
    import 'constants.dart' as Constants;
    import 'ui/auth/AuthScreen.dart';
    import 'ui/onBoarding/OnBoardingScreen.dart';
    
    import 'package:flutter/cupertino.dart';
    
    import 'package:mycafe/ui/auth/AuthScreen.dart';
    
    var bannerItems = ["Burger", "cheesechilly", "Noodles", "Pizza"];
    var bannerImages = [
      "images/burger.jpg",
      "images/cheesechilly.jpg",
      "images/noodles.jpg",
      "images/pizza.jpg"
    ];
    
    ValueNotifier<int> notificationCounterValueNotifer = ValueNotifier(0);
    
    class Notify extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'FlutterBase',
          home: Scaffold(
            body: MessageHandler(),
          ),
        );
      }
    }
    
    class MessageHandler extends StatefulWidget {
      @override
      _MessageHandlerState createState() => _MessageHandlerState();
    }
    
    class _MessageHandlerState extends State<MessageHandler> with ChangeNotifier {
      final Firestore _db = Firestore.instance;
      final FirebaseMessaging _fcm = FirebaseMessaging();
    
      StreamSubscription iosSubscription;
    
      @override
      void initState() {
        super.initState();
        if (Platform.isIOS) {
          iosSubscription = _fcm.onIosSettingsRegistered.listen((data) {
            print(data);
            _saveDeviceToken();
          });
    
          _fcm.requestNotificationPermissions(IosNotificationSettings());
        } else {
          _saveDeviceToken();
        }
    
    // void _incrementCounter() {
        _fcm.configure(
          onMessage: (Map<String, dynamic> message) async {
            print("onMessage: $message");
    
            // RaisedButton(
            //   child: Text(message['notification']['title']),
            //   onPressed: () {
            //     Flushbar(
            //       flushbarPosition: FlushbarPosition.TOP,
            //       icon: Icon(
            //         Icons.notifications_active,
            //         color: Colors.white,
            //       ),
            //       mainButton: FlatButton(
            //         onPressed: () {
            //           Navigator.pop(context);
            //           //  Flush.showGoodFlushbar(context, 'login successful!');
            //         },
            //         // child: Text(
            //         //   "ADD",
            //         //   style: TextStyle(color: Colors.amber),
            //         // ),
            //       ),
            //       // duration: Duration(seconds: 7))
            //     ).show(context);
            //   },
            // );
            notificationCounterValueNotifer.value++;
            notificationCounterValueNotifer
                .notifyListeners(); // notify listeners here so ValueListenableBuilder will build the widget.
            final snackbar = SnackBar(
              content: Text(message['notification']['title']),
              action: SnackBarAction(
                label: 'Go',
                onPressed: () => null,
              ),
            );
    
            Scaffold.of(context).showSnackBar(snackbar);
            // showDialog(
            //   context: context,
            //   builder: (context) => AlertDialog(
            //     content: ListTile(
            //       title: Text(message['notification']['title']),
            //       subtitle: Text(message['notification']['body']),
            //     ),
            //     actions: <Widget>[
            //       FlatButton(
            //         color: Colors.amber,
            //         child: Text('Ok'),
            //         onPressed: () => Navigator.of(context).pop(),
            //       ),
            //     ],
            //   ),
            // );
          },
          onLaunch: (Map<String, dynamic> message) async {
            print("onLaunch: $message");
            // TODO optional
          },
          onResume: (Map<String, dynamic> message) async {
            print("onResume: $message");
            // TODO optional
          },
        );
      }
    
      @override
      void dispose() {
        if (iosSubscription != null) iosSubscription.cancel();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        // _handleMessages(context);
        return MaterialApp(home: Scaffold(body: HomeApp()));
      }
    
      /// Get the token, save it to the database for current user
      _saveDeviceToken() async {
        // Get the current user
        String uid = 'jeffd23';
        // FirebaseUser user = await _auth.currentUser();
    
        // Get the token for this device
        String fcmToken = await _fcm.getToken();
    
        // Save it to Firestore
        if (fcmToken != null) {
          var tokens = _db
              .collection('users')
              .document(uid)
              .collection('tokens')
              .document(fcmToken);
    
          await tokens.setData({
            'token': fcmToken,
            'createdAt': FieldValue.serverTimestamp(), // optional
            'platform': Platform.operatingSystem // optional
          });
        }
      }
    
      /// Subscribe the user to a topic
      _subscribeToTopic() async {
        // Subscribe the user to a topic
        _fcm.subscribeToTopic('puppies');
      }
    }
    
    Widget myAppBarIcon() {
      if (State is ValueNotifier) {
        return ValueListenableBuilder(
          builder: (BuildContext context, int newNotificationCounterValue,
              Widget child) {
            // return Container(
            // width: 50,
            // height: 10,
    
            child:
            Stack(
              children: [
                Icon(
                  Icons.notifications,
                  color: Colors.white,
                  size: 30,
                ),
                Container(
                  width: 30,
                  height: 30,
                  alignment: Alignment.topRight,
                  margin: EdgeInsets.only(top: 2),
                  child: Container(
                    width: 15,
                    height: 15,
                    decoration: BoxDecoration(
                        shape: BoxShape.circle,
                        color: Color(0xffc32c37),
                        border: Border.all(color: Colors.white, width: 1)),
                    child: Padding(
                      padding: const EdgeInsets.all(0.0),
                      child: Text(
                        newNotificationCounterValue.toString(),
                      ),
                    ),
                  ),
                ),
              ],
            );
    
            //return your badge here
          },
          valueListenable: notificationCounterValueNotifer,
        );
        // return Container(
        //   width: 50,
        //   height: 10,
        //   child: Stack(
        //     children: [
        //       Icon(
        //         Icons.notifications,
        //         color: Colors.white,
        //         size: 30,
        //       ),
        //       Container(
        //         width: 30,
        //         height: 30,
        //         alignment: Alignment.topRight,
        //         margin: EdgeInsets.only(top: 2),
        //         child: Container(
        //           width: 15,
        //           height: 15,
        //           decoration: BoxDecoration(
        //               shape: BoxShape.circle,
        //               color: Color(0xffc32c37),
        //               border: Border.all(color: Colors.white, width: 1)),
        //           child: Padding(
        //             padding: const EdgeInsets.all(0.0),
        //             child: Center(
        //               child: ValueListenableBuilder(),
        //             ),
        //           ),
        //         ),
        //       ),
        //     ],
        //   ),
        // );
      } else {
        return Container();
      }
    }
    
    class HomeApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            backgroundColor: Colors.deepOrange[900],
            title: Text('HuQQa BuzZ'),
            actions: <Widget>[myAppBarIcon()],