为啥 0 个待处理通知

Posted

技术标签:

【中文标题】为啥 0 个待处理通知【英文标题】:Why 0 pending notifications为什么 0 个待处理通知 【发布时间】:2021-08-11 17:18:57 【问题描述】:

我正在使用flutter_local_notification V 5.00+3 并调用flutterLocalNotificationsPlugin.pendingNotificationRequests()

总是返回 0(零),即使我执行

FlutterLocalNotificationsPlugin().show

两次不点击通知,离开通知,代码如下,摘自示例,简单修改添加idOfMsg作为消息的id

import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui';

import 'package:device_info/device_info.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_native_timezone/flutter_native_timezone.dart';
import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart';
import 'package:rxdart/subjects.dart';

final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
    FlutterLocalNotificationsPlugin();

/// Streams are created so that app can respond to notification-related events
/// since the plugin is initialised in the `main` function
final BehaviorSubject<ReceivedNotification> didReceiveLocalNotificationSubject =
    BehaviorSubject<ReceivedNotification>();

final BehaviorSubject<String?> selectNotificationSubject =
    BehaviorSubject<String?>();

const MethodChannel platform =
    MethodChannel('dexterx.dev/flutter_local_notifications_example');

class ReceivedNotification 
  ReceivedNotification(
    required this.id,
    required this.title,
    required this.body,
    required this.payload,
  );

  final int id;
  final String? title;
  final String? body;
  final String? payload;


String? selectedNotificationPayload;

/// IMPORTANT: running the following code on its own won't work as there is
/// setup required for each platform head project.
///
/// Please download the complete example app from the GitHub repository where
/// all the setup has been done
Future<void> main() async 
  // needed if you intend to initialize in the `main` function
  WidgetsFlutterBinding.ensureInitialized();

  final NotificationAppLaunchDetails? notificationAppLaunchDetails =
      await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
  String initialRoute = HomePage.routeName;
  if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) 
    selectedNotificationPayload = notificationAppLaunchDetails!.payload;
    initialRoute = SecondPage.routeName;
  

  const androidInitializationSettings initializationSettingsAndroid =
      AndroidInitializationSettings('@mipmap/ic_launcher');

  /// Note: permissions aren't requested here just to demonstrate that can be
  /// done later
  final iosInitializationSettings initializationSettingsIOS =
      IOSInitializationSettings(
          requestAlertPermission: false,
          requestBadgePermission: false,
          requestSoundPermission: false,
          onDidReceiveLocalNotification:
              (int id, String? title, String? body, String? payload) async 
            didReceiveLocalNotificationSubject.add(ReceivedNotification(
                id: id, title: title, body: body, payload: payload));
          );
  const MacOSInitializationSettings initializationSettingsMacOS =
      MacOSInitializationSettings(
          requestAlertPermission: false,
          requestBadgePermission: false,
          requestSoundPermission: false);
  final InitializationSettings initializationSettings = InitializationSettings(
      android: initializationSettingsAndroid,
      iOS: initializationSettingsIOS,
      macOS: initializationSettingsMacOS);
  await flutterLocalNotificationsPlugin.initialize(initializationSettings,
      onSelectNotification: (String? payload) async 
    if (payload != null) 
      debugPrint('notification payload: $payload');
    
    selectedNotificationPayload = payload;
    selectNotificationSubject.add(payload);
  );
  runApp(
    MaterialApp(
      initialRoute: initialRoute,
      routes: <String, WidgetBuilder>
        HomePage.routeName: (_) => HomePage(notificationAppLaunchDetails),
        SecondPage.routeName: (_) => SecondPage(selectedNotificationPayload)
      ,
    ),
  );


class PaddedElevatedButton extends StatelessWidget 
  const PaddedElevatedButton(
    required this.buttonText,
    required this.onPressed,
    Key? key,
  ) : super(key: key);

  final String buttonText;
  final VoidCallback onPressed;

  @override
  Widget build(BuildContext context) => Padding(
        padding: const EdgeInsets.fromLTRB(0, 0, 0, 8),
        child: ElevatedButton(
          onPressed: onPressed,
          child: Text(buttonText),
        ),
      );


class HomePage extends StatefulWidget 
  const HomePage(
    this.notificationAppLaunchDetails, 
    Key? key,
  ) : super(key: key);

  static const String routeName = '/';

  final NotificationAppLaunchDetails? notificationAppLaunchDetails;

  bool get didNotificationLaunchApp =>
      notificationAppLaunchDetails?.didNotificationLaunchApp ?? false;

  @override
  _HomePageState createState() => _HomePageState();


class _HomePageState extends State<HomePage> 
  @override
  void initState() 
    super.initState();
    _requestPermissions();
    _configureDidReceiveLocalNotificationSubject();
    _configureSelectNotificationSubject();
  

  void _configureSelectNotificationSubject() 
    selectNotificationSubject.stream.listen((String? payload) async 
      await Navigator.pushNamed(context, '/secondPage');
    );
  

  void _requestPermissions() 
    flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation<
            IOSFlutterLocalNotificationsPlugin>()
        ?.requestPermissions(
          alert: true,
          badge: true,
          sound: true,
        );
    flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation<
            MacOSFlutterLocalNotificationsPlugin>()
        ?.requestPermissions(
          alert: true,
          badge: true,
          sound: true,
        );
  

  void _configureDidReceiveLocalNotificationSubject() 
    didReceiveLocalNotificationSubject.stream
        .listen((ReceivedNotification receivedNotification) async 
      await showDialog(
        context: context,
        builder: (BuildContext context) => CupertinoAlertDialog(
          title: receivedNotification.title != null
              ? Text(receivedNotification.title!)
              : null,
          content: receivedNotification.body != null
              ? Text(receivedNotification.body!)
              : null,
          actions: <Widget>[
            CupertinoDialogAction(
              isDefaultAction: true,
              onPressed: () async 
                Navigator.of(context, rootNavigator: true).pop();
                await Navigator.push(
                  context,
                  MaterialPageRoute<void>(
                    builder: (BuildContext context) =>
                        SecondPage(receivedNotification.payload),
                  ),
                );
              ,
              child: const Text('Ok'),
            )
          ],
        ),
      );
    );
  

  @override
  void dispose() 
    didReceiveLocalNotificationSubject.close();
    selectNotificationSubject.close();
    super.dispose();
  

  @override
  Widget build(BuildContext context) => MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: const Text('Plugin example app'),
          ),
          body: SingleChildScrollView(
            child: Padding(
              padding: const EdgeInsets.all(8),
              child: Center(
                child: Column(
                  children: <Widget>[
                    const Padding(
                      padding: EdgeInsets.fromLTRB(0, 0, 0, 8),
                      child: Text(
                          'Tap on a notification when it appears to trigger'
                          ' navigation'),
                    ),
                    Padding(
                      padding: const EdgeInsets.fromLTRB(0, 0, 0, 8),
                      child: Text.rich(
                        TextSpan(
                          children: <InlineSpan>[
                            const TextSpan(
                              text: 'Did notification launch app? ',
                              style: TextStyle(fontWeight: FontWeight.bold),
                            ),
                            TextSpan(
                              text: '$widget.didNotificationLaunchApp',
                            )
                          ],
                        ),
                      ),
                    ),
                    if (widget.didNotificationLaunchApp)
                      Padding(
                        padding: const EdgeInsets.fromLTRB(0, 0, 0, 8),
                        child: Text.rich(
                          TextSpan(
                            children: <InlineSpan>[
                              const TextSpan(
                                text: 'Launch notification payload: ',
                                style: TextStyle(fontWeight: FontWeight.bold),
                              ),
                              TextSpan(
                                text: widget
                                    .notificationAppLaunchDetails!.payload,
                              )
                            ],
                          ),
                        ),
                      ),

                    PaddedElevatedButton(
                      buttonText: 'Show 1 plain notification with payload',
                      onPressed: () async 
                        await _showNotification(1);
                      ,
                    ),

                    PaddedElevatedButton(
                      buttonText: 'Show 2 plain notification with payload',
                      onPressed: () async 
                        await _showNotification(2);
                      ,
                    ),

                    PaddedElevatedButton(
                      buttonText: 'Check pending notifications',
                      onPressed: () async 
                        await _checkPendingNotificationRequests();
                      ,
                    ),
                  ],
                ),
              ),
            ),
          ),
        ),
      );

  Future<void> _showNotification(int idOfMsg) async 
    const AndroidNotificationDetails androidPlatformChannelSpecifics =
        AndroidNotificationDetails(
            'your channel id', 'your channel name', 'your channel description',
            importance: Importance.max,
            priority: Priority.high,
            ticker: 'ticker');
    const NotificationDetails platformChannelSpecifics =
        NotificationDetails(android: androidPlatformChannelSpecifics);
    await flutterLocalNotificationsPlugin.show(
        idOfMsg, 'plain title'+ idOfMsg.toString(), 'plain body', platformChannelSpecifics,
        payload: 'item x' + idOfMsg.toString());
  

  Future<void> _cancelNotification() async 
    await flutterLocalNotificationsPlugin.cancel(0);
  

  Future<void> _checkPendingNotificationRequests() async 
    final List<PendingNotificationRequest> pendingNotificationRequests =
        await flutterLocalNotificationsPlugin.pendingNotificationRequests();
    return showDialog<void>(
      context: context,
      builder: (BuildContext context) => AlertDialog(
        content:
            Text('$pendingNotificationRequests.length pending notification '
                'requests'),
        actions: <Widget>[
          TextButton(
            onPressed: () 
              Navigator.of(context).pop();
            ,
            child: const Text('OK'),
          ),
        ],
      ),
    );
  

  Future<void> _cancelAllNotifications() async 
    await flutterLocalNotificationsPlugin.cancelAll();
  


class SecondPage extends StatefulWidget 
  const SecondPage(
    this.payload, 
    Key? key,
  ) : super(key: key);

  static const String routeName = '/secondPage';

  final String? payload;

  @override
  State<StatefulWidget> createState() => SecondPageState();


class SecondPageState extends State<SecondPage> 
  String? _payload;
  @override
  void initState() 
    super.initState();
    _payload = widget.payload;
  

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: Text('Second Screen $_payload ?? ''  with payload: '),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () 
              Navigator.pop(context);
            ,
            child: const Text('Go back!'),
          ),
        ),
      );

请帮忙,以便我可以获取用户仍未点击或取消的通知列表。

【问题讨论】:

【参考方案1】:

pendingNotificationRequests 用于尚未出现在通知面板中的预定通知。

getActiveNotifications 用于通知面板中可用的通知。

【讨论】:

【参考方案2】:

我找到了示例中的解决方案

flutterLocalNotificationsPlugin
          .resolvePlatformSpecificImplementation<
          AndroidFlutterLocalNotificationsPlugin>()!
          .getActiveNotifications();

【讨论】:

以上是关于为啥 0 个待处理通知的主要内容,如果未能解决你的问题,请参考以下文章

ServiceNow 推送通知卡在“待处理”中

计算待处理的本地通知

如何使用通知待处理意图操作删除图像?

立即在 WooCommerce 中设置待处理订单并发送处理电子邮件通知

Codeforces 909E(Coprocessor,双队列维护)

Codeforces 909E(Coprocessor,双队列维护)