Flutter: 如何统计FCM通知的数量

4

我正在尝试在应用程序内(主屏幕)创建通知徽章,使用的是Flutter语言中的Firebase Cloud Messaging和Android应用程序。问题在于我无法弄清如何计算接收到的通知数量。

有没有建议的方法可以从Firebase Cloud Messaging计算接收到的通知数量到Android应用程序?

附注:我已更新代码,并仍然遇到错误。

// 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()],

2
你可以创建一个名为 notificationCounter 的全局变量,每当你收到一条新通知时,将该数字增加1。在打开通知屏幕时,你可以将其设置为0。最后,将其存储在 Firebase 文档中,这样下次启动应用程序时,你就可以从数据库中获取通知数量。 - Morez
@ Morez 如果我想在我的应用程序中保留所有通知怎么办? - Merym
@Morez,实际上我正在尝试做这个,但是我失败了,如果您能帮助我,我会很高兴的。 - user13125672
2个回答

2
这是我的做法:
//define a global variable
ValueNotifier<int> notificationCounterValueNotifer =
    ValueNotifier(0); 

你可以在这里阅读关于ValueNotifier的内容:https://roberapp.com/en/valuenotifier-how-to-change-a-value-from-any-widget-in-flutter/
当你收到新通知时,将该值增加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(),
                  ),
                ],
              ),
        );
      },
);

为了通知侦听器,您需要将ChangeNotifier作为mixin添加到您的类中:
class _MessageHandlerState extends State<MessageHandler> with ChangeNotifier

您可以选择使用ValueListenableBuilder在值更改时构建小部件。因此,为了更新徽章,我们使用此小部件:
 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,
);

您可以将值存储在数据库文档中,并在应用程序启动时分配它,以便您的notificationCounterValueNotifer值不为0。

如果您愿意,当您导航到notificationScreen时,您可以将其设置为0。

可能有更好的方法来完成这个任务,但这是我做的方法。

更新: 您需要从myAppBarIcon返回ValueListenableBuilder

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,
    );
}

错误信息为(行的子项不能包含任何空值,但在索引0处发现了一个空值),但仍然显示:/ - user13125672
你必须从 myAppBarIcon 中返回 ValueListenableBuilder,因为 ValueListenableBuilder 是一个小部件,但是 myAppBarIcon 没有返回它。 - Morez
我对帖子进行了另一次编辑,我使用了if else语句来避免空值,因为它需要另一个返回值(当它为空时)。现在我没有错误,但问题是:它没有显示应用程序栏上的通知图标,因为它只返回null。然而,我尝试从FCM发送通知,但图标仍未显示。 - user13125672
只需从函数中返回可监听的构建器值,并在构建器方法内添加您的逻辑。因此,如果没有通知时不想显示任何徽章,请在可监听的构建器值的构建器方法内返回一个空容器。您看不到任何东西,因为当应用程序启动时,该函数将返回一个空容器,即使值通知器的值发生更改,您的小部件树也将保持不变。 - Morez
1
当您关闭应用程序时,数据将丢失。您可以使用 Shared_Preferences 包将该数字保存在设备上:https://pub.dev/packages/shared_preferences。阅读有关该包的信息并查看示例以了解如何使用它。 - Morez
显示剩余8条评论

0

您可以使用:

List<ActiveNotification> activeNotification = await fln.getActiveNotifications();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接