FirebaseMessaging 通知在 iOS 上在前台重复

问题描述 投票:0回答:1

我正在为 FirebaseMessaging 制作一个 Flutter 示例应用程序,以测试服务器通知的工作方式。因此,我按照 FlutterFire 上的指南进行了所有设置,它在 Android 上运行得很好。

就 iOS 而言,当应用程序处于后台时,它似乎工作得很好。当我在前台使用应用程序发送通知时,它会显示通知两次。如果它包含图像,则第一个通知将包含该图像,而第二个通知则不会。

我很迷茫,我不明白为什么会这样做。无论我使用 Firebase 控制台的测试通知还是我自己的后端使用

FirebaseMessaging.send
,行为都是相同的。

以下是代码片段:

main.dart

import 'dart:developer';
import 'dart:io';

import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:googlenotifpoc/notification_manager.dart';
import 'firebase_options.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    name: "...",
    options: DefaultFirebaseOptions.currentPlatform,
  );
  await FirebaseMessaging.instance.setAutoInitEnabled(true);

  const AndroidNotificationChannel channel = AndroidNotificationChannel(
    'high_importance_channel', // id
    'High Importance Notifications', // title
    description:
        'This channel is used for important notifications.', // description
    importance: Importance.max,
  );

  const AndroidNotificationDetails androidDetails = AndroidNotificationDetails(
        'high_importance_channel', // id
        'High Importance Notifications',
        channelDescription: 'This channel is used for important notifications.',
        importance: Importance.max,
        priority: Priority.high,
        ticker: 'ticker',
        icon: "ic_white",
        playSound: true,
    );

  await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
    alert: true, // Required to display a heads up notification
    badge: true,
    sound: true,
  ); 

  final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
      FlutterLocalNotificationsPlugin();

  await flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation<
          AndroidFlutterLocalNotificationsPlugin>()
      ?.createNotificationChannel(channel);

  FirebaseMessaging.onMessage.listen((event) => NotificationManager.showNotification(event, androidDetails),);

  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    FirebaseMessaging messaging = FirebaseMessaging.instance;

    messaging.requestPermission(
      alert: true,
      announcement: false,
      badge: true,
      carPlay: true,
      criticalAlert: false,
      provisional: false,
      sound: true,
    );
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            FutureBuilder<String?>(
              future: getFMCToken(),
              builder: (BuildContext context, AsyncSnapshot<String?> snapshot) {
                if (snapshot.hasData) {
                  log(snapshot.data ?? "-");
                  print(snapshot.data ?? "-");
                  return Text(
                    "FMC TOKEN: \n ${snapshot.data}",
                    textAlign: TextAlign.center,
                    style: const TextStyle(
                        fontSize: 16, fontWeight: FontWeight.bold),
                  );
                } else {
                  return const Text("Loading your FCM token...");
                }
              },
            ),
          ],
        ),
      ),
    );
  }

  Future<String?> getFMCToken() async {
    String? apnsToken;
    if(Platform.isIOS) {
      apnsToken = await FirebaseMessaging.instance.getAPNSToken();
      log("Got APNS token: $apnsToken");
      print("Got APNS token: $apnsToken");
    }

    if(Platform.isAndroid || apnsToken != null) {
      return FirebaseMessaging.instance.getToken();
    }

    return Future.value(null);
  }
}

通知管理类


import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

class NotificationManager {

  static Future<void> showNotification(RemoteMessage payload, AndroidNotificationDetails androidDetails) async {
    const android = AndroidInitializationSettings("ic_white");
    const initializationSettingsIOS = DarwinInitializationSettings();
    const initialSetting = InitializationSettings(android: android, iOS: initializationSettingsIOS);
    final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
    flutterLocalNotificationsPlugin.initialize(initialSetting);

    
    const iOSDetails = DarwinNotificationDetails();
    NotificationDetails platformChannelSpecifics = NotificationDetails(android: androidDetails, iOS: iOSDetails);

    await flutterLocalNotificationsPlugin.show(0, payload.notification!.title, payload.notification!.body, platformChannelSpecifics);
  }
}

ios notificationService.m

//
//  NotificationService.m
//  ImageNotification
//

#import "NotificationService.h"
#import "FirebaseMessaging.h"

@interface NotificationService ()

@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;

@end

@implementation NotificationService

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    
    // Modify the notification content here...
    //self.bestAttemptContent.title = [NSString stringWithFormat:@"%@ [modified]", self.bestAttemptContent.title];
    //self.contentHandler(self.bestAttemptContent);
    
    [[FIRMessaging extensionHelper] populateNotificationContent:self.bestAttemptContent withContentHandler:contentHandler];
}

- (void)serviceExtensionTimeWillExpire {
    // Called just before the extension will be terminated by the system.
    // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
    self.contentHandler(self.bestAttemptContent);
}

@end

Firebase 依赖项:

  firebase_messaging: ^14.7.9
  firebase_core: ^2.24.2
  flutter_local_notifications: ^16.2.0
  firebase_analytics: ^10.7.4
ios flutter firebase dart firebase-cloud-messaging
1个回答
1
投票

我找到了一个解决方案解决方法。看来问题来自于 firebase 插件和我的代码都尝试显示相同的通知,因此我必须将 iOS 和 Android 案例分开,以免在 iOS 上抛出本地通知:

FirebaseMessaging.onMessage.listen(
    (event) {
      if (Platform.isIOS) {
        log("received event for iOS : $event");
        return;
      }
      if (event.notification == null) return;
      NotificationManager.showNotification(event, androidDetails);
    },
  );
© www.soinside.com 2019 - 2024. All rights reserved.