首页 > 解决方案 > firebase_messaging onBackgroundMessage local_notifications

问题描述

当应用程序关闭或在后台时,我试图停止来自 firebase_message 的默认通知。

我想在应用程序关闭或使用 local_notifications 插件在后台显示自定义通知,该插件按预期工作,发送消息时存在问题,应用程序显示相同的通知两次,默认通知为 1,另一个与自定义通知。

我无法实现停止默认通知。谁能在这里指出我的错误?

初始代码来自 firebase 消息传递示例,删除不必要的片段并添加自定义通知。

还附上了当前的图像(不良行为)

在此处输入图像描述

如前所述,相同的通知显示了两次,想要摆脱图像上显示的第一个通知。

这是我的代码:

// 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();
  }
}

标签: flutterpush-notificationfirebase-cloud-messaging

解决方案


好吧,这是我这边的一个错误。阅读 FCM 文档后,似乎有两种类型的 FCM 推送:通知和数据。

通知具有默认行为,即显示当前默认的推送通知。设置数据消息推送时,不会触发默认行为,让您决定做什么。

通知负载示例

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

数据消息负载示例

"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.        
           

也就是说两个防止默认默认推送,都需要发送数据消息并添加相应的逻辑。


推荐阅读