Flutter FCM:自定义声音与默认声音一起播放,并且当应用程序终止时重定向失败

问题描述 投票:0回答:1
  1. 我在 Flutter 应用程序中使用 Firebase Cloud Messaging (FCM),并且 试图实现以下目标:

  2. 收到通知时播放自定义通知声音。 单击通知时重定向到特定屏幕,甚至 如果应用程序已终止或未在后台运行。

问题:

  1. 自定义声音问题:

    • 当我在有效负载中包含 notification 对象时,通知会播放 这 默认声音而不是自定义声音。
    • 如果我在 android 中同时包含通知和自定义声音配置 部分,我收到两个通知:
      • 具有 默认声音。
      • 另一个带有 自定义声音。
  2. 重定向问题:

    • 当我删除 notification 对象并完全依赖 data 对象时, 这 自定义声音有效,但如果应用程序已终止或不在其中,则重定向失败 背景。
    • 在这种情况下应用程序不会收到通知点击事件。

我正在使用的有效负载:

Below is the payload I'm sending to FCM:
    {  
     "message": {
       "token": "DEVICE_FCM_TOKEN",  
       "notification": {  
         "title": "Visitor has been admitted!",  
         "body": "Dhaval developer (Visitor) has been admitted.",
       },  
      "android": {  
        "notification": {  
          "sound": "visitor_notification_sound"  
        }  
      },
      "apns":{
        "payload":{
            "aps":{
                "sound":"visitor_notification_sound.mp3"
            }
        }
      },  
      "data": {  
         "id": "1215454",  
         "notification_type": "visitor_visited",  
         "other_data_key": "other_data_value"  
     }  
  }  
}

观察结果:

  1. 随着通知对象:

    • 即使应用程序终止或不在后台,重定向也能正常工作。
    • 通知播放默认声音,而不是自定义声音。
  2. 没有通知对象:

    • 自定义声音效果很好。
    • 当应用程序终止或不在后台时,重定向失败(点击 未收到事件)。
  3. 包括通知和自定义声音android部分:

    • 收到两条通知:
      • 具有 默认声音。
      • 另一个带有 自定义声音。

颤振代码: 以下是我在 Flutter 应用程序中处理通知的方式:

main.dart

import 'package:flutter/material.dart';
import 'package:notification_demo/fcm_controller.dart';
import 'package:notification_demo/firebase_options.dart';

Future<void> main() async {
 WidgetsFlutterBinding.ensureInitialized();
 await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
 await FirebaseCloudMessagingService().initFCM();
 runApp(const MyApp());
}

class MyApp extends StatefulWidget {
 const MyApp({super.key});

 @override
 State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
 @override
 Widget build(BuildContext context) {
   return const MaterialApp(
     home: Scaffold(
       body: Center(
         child: Text('hello'),
       ),
     ),
   );
 }
}

fcm_controller.dart

import 'dart:convert';
import 'dart:developer';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'dart:math' as math;
import 'package:notification_demo/firebase_options.dart';

@pragma('vm:entry-point')
Future<void> notificationTapBackground(NotificationResponse notificationResponse) async {
 debugPrint('background notification tap');
}

final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
 await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
 debugPrint("Handling a background message ${message.messageId}");
 if (message.messageId != null && message.messageId!.isNotEmpty) {
   FirebaseCloudMessagingService.showNotification(message);
 }
}

class FirebaseCloudMessagingService {
 Future<void> initFCM() async {
   debugPrint('DDDD initFCM');
   try {
     await _requestPermission();
     await _initNotificationInfo();
     String deviceToken = await _getToken() ?? '';
     debugPrint('FCM Token: $deviceToken');
     await _setupMessageHandlers();
     FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
   } catch (e) {
     log("Exception: $e");
   }
 }

 Future<void> _requestPermission() async {
   NotificationSettings settings = await FirebaseMessaging.instance.requestPermission(
     alert: true,
     announcement: true,
     badge: true,
     carPlay: true,
     criticalAlert: true,
     provisional: true,
     sound: true,
   );
   debugPrint('Permission status: ${settings.authorizationStatus}');
 }

 Future<void> _initNotificationInfo() async {
   var initializationSettingAndroid = const AndroidInitializationSettings('@mipmap/ic_launcher');
   const DarwinInitializationSettings initializationSettingIOS = DarwinInitializationSettings();
   var initializationSettings = InitializationSettings(android: initializationSettingAndroid, iOS: initializationSettingIOS);
   await flutterLocalNotificationsPlugin.initialize(initializationSettings, onDidReceiveNotificationResponse: (NotificationResponse notificationResponse) async {
     handleNotificationTappedFormNotificationTray(jsonDecode(notificationResponse.payload ?? "{}"));
   }, onDidReceiveBackgroundNotificationResponse: notificationTapBackground);
 }

 Future<String?> _getToken() async {
   try {
     return await FirebaseMessaging.instance.getToken();
   } catch (e) {
     debugPrint("Error fetching token: $e");
     return null;
   }
 }

 Future<void> _setupMessageHandlers() async {
   FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
     showNotification(message);
   });
   FirebaseMessaging.onMessageOpenedApp.listen((event) async {
     await handleNotificationTappedFormNotificationTray(event.data);
   });
 }

 static Future<void> showNotification(RemoteMessage message) async {
   String title = message.data['title'] ?? '';
   String body = message.data['body'] ?? '';
   String soundName = 'notification_sound_android';
   String iosSoundName = 'notification_sound_android.mp3';
   if (message.data['notification_type'] == 'visitor_visited') {
     soundName = 'visitor_notification_sound';
     iosSoundName = 'visitor_notification_sound.mp3';
   }
   AndroidNotificationChannel channel = AndroidNotificationChannel(
     soundName,
     'General Notifications',
     importance: Importance.max,
     playSound: true,
     sound: RawResourceAndroidNotificationSound(soundName),
   );
   AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails(
     channel.id,
     channel.name,
     sound: RawResourceAndroidNotificationSound(soundName),
   );
   NotificationDetails notificationDetails = NotificationDetails(
     android: androidNotificationDetails,
     iOS: DarwinNotificationDetails(sound: iosSoundName),
   );
   flutterLocalNotificationsPlugin.show(
     math.Random().nextInt(100000),
     title,
     body,
     notificationDetails,
     payload: jsonEncode(message.data),
   );
 }

 Future<void> handleNotificationTappedFormNotificationTray(Map<String, dynamic> notificationData) async {
   debugPrint('Notification tapped: $notificationData');
   // Implement redirection logic here
 }
}

问题: 如何在 Flutter 中配置 FCM 并处理通知,以便:

  1. 自定义声音播放时不会触发默认声音或重复 通知。
  2. 单击通知会重定向到特定屏幕,即使应用程序是 终止或不在后台运行。
  3. 仅显示一个通知

有没有办法解决 notificationdata 对象之间的冲突以实现所需的行为?

android flutter firebase push-notification firebase-cloud-messaging
1个回答
0
投票

我确实有这个问题:

1.自定义声音播放,不会触发默认声音或重复通知。

  • 尝试物理设备,某些设备/模拟器可能无法工作。尤其是小米手机。

2.单击通知会重定向到特定屏幕,即使应用程序已终止或未在后台运行。

flutter_local_notification 有一个默认的点击通知进入应用程序时,尝试播放以下代码:

final NotificationAppLaunchDetails? notificationAppLaunchDetails =
    await _flutterLocalNotificationsPlugin1
        .getNotificationAppLaunchDetails();
final didNotificationLaunchApp =
    notificationAppLaunchDetails?.didNotificationLaunchApp ?? false;
if (didNotificationLaunchApp == true) {
  /// GET DATA
  final dataX = notificationAppLaunchDetails?.notificationResponse!.payload;
  Future.delayed(const Duration(seconds: 2), () async {
    /// PUT CODE HERE TO REDIRECT
  });
  // throw Exception('$dataX');
}

正如我使用 go_ 单击应用程序或重定向或扫描 qr 时,根据我的代码进行页面导航的路由器。

  1. 仅显示一条通知。

在 Firebase 上,我们有 2 种方法发送带有数据的有效负载,并且仅发送带有正文的通知。

  • 我使用的只是数据。根据我的情况,我调整数据以将标题和正文放入其中,因此我手动获取这些数据。由于一旦终止,我收到了两个通知,因为另一个通知没有数据,所以这就是原因。
© www.soinside.com 2019 - 2024. All rights reserved.