设备离线时仅收到一个 Firebase 通知 Flutter

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

我在弄清楚如何通过 Flutter 上的 firebase 推送通知达到我想要的结果时遇到了一些麻烦。

基本上,我尝试在设备离线的情况下发送一组推送通知,然后我重新激活 wifi,但设备只收到一个通知。

我已经阅读了this,但我不知道如何接收所有通知并将其显示给用户。 基本上和whatsapp 一样。 文字

如果在通知消息中我设置了

notification
(带或不带
data
)键,则设备重新上线后只会收到一个通知。 如果在通知消息中我设置了
data
(没有
notification
),则无法设置标题和正文,因此不会向用户显示通知。

这是我用来处理 firebase 通知的代码:

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

Future handleBackgroundMessage(RemoteMessage message) async {
  print("Title: ${message.notification?.title}");
  print("Body: ${message.notification?.body}");
  print("Payload: ${message.data}");
}

class FirebaseApi {
  final _firebaseMessaging = FirebaseMessaging.instance;

  final _androidChannel = const AndroidNotificationChannel(
    'high_importance_channel',
    'High Importance Notifications',
    description: "This channel is used for important notifications",
    importance: Importance.defaultImportance,
  );

  final _localNotification = FlutterLocalNotificationsPlugin();

  void handleMessage(RemoteMessage? message) {
    if (message == null) return;
    print("Title: ${message.notification?.title}");
    print("Body: ${message.notification?.body}");
    print("Payload: ${message.data}");

    //action after the user tapped on the notification
  }

  Future initLocalNotifications() async {
    const iOS = DarwinInitializationSettings();
    const android = AndroidInitializationSettings("@drawable/ic_launcher");
    const settings = InitializationSettings(android: android, iOS: iOS);

    await _localNotification.initialize(settings,
        onDidReceiveNotificationResponse: (response) {
      final message = RemoteMessage.fromMap(jsonDecode(response.payload!));
      handleMessage(message);
    });

    final platform = _localNotification.resolvePlatformSpecificImplementation<
        AndroidFlutterLocalNotificationsPlugin>();
    await platform?.createNotificationChannel(_androidChannel);
  }

  Future initPushNotifications() async {
    await FirebaseMessaging.instance
        .setForegroundNotificationPresentationOptions(
            alert: true, badge: true, sound: true);

    FirebaseMessaging.instance.getInitialMessage().then(handleMessage);
    FirebaseMessaging.onMessageOpenedApp.listen(handleMessage);
    FirebaseMessaging.onBackgroundMessage(handleBackgroundMessage);
    FirebaseMessaging.onMessage.listen(
      (message) {
        final notification = message.notification;

        _localNotification.show(
          notification.hashCode,
          notification?.title ?? "Default title",
          notification?.body ?? "Default body",
          NotificationDetails(
            android: AndroidNotificationDetails(
                _androidChannel.id, _androidChannel.name,
                channelDescription: _androidChannel.description,
                icon: "@drawable/ic_launcher"),
          ),
          payload: jsonEncode(
            message.toMap(),
          ),
        );
      },
    );
  }

  Future<String?> initNotification() async {
    await _firebaseMessaging.requestPermission();
    String? fcmToken = await _firebaseMessaging.getToken();
    //log
    print(fcmToken);
    //start notifications
    initPushNotifications();
    initLocalNotifications();
    return fcmToken;
  }
}

任何帮助将不胜感激。

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

经过大量测试,我找到了一种解决方法,不知道这是否是最好的解决方案,但它工作正常。

我暂时只在 Android 上测试过。

基本上,我从我的 php 服务器将此负载发送到 Firebase V1 API:

{
   "message":{
      "token":"YOUR TOKEN",
      "data":{
         "title":"Title",
         "body":"Body"
      },
      "android":{
         "priority":"high"
      },
      "apns":{
         "headers":{
            "apns-priority":"10"
         }
      }
   }
}

通过省略

notification
标签,因为 firebase 文档显示“发送静默消息”并且通知不会出现在设备上,因此需要手动通知,在我的代码中我使用 flutter_local_notification 包。


@pragma('vm:entry-point')
Future handleBackgroundMessage(RemoteMessage message) async {
  /*print("background");
  print(message.toMap());*/
  try {
    FirebaseApi firebaseApi = FirebaseApi();
    await firebaseApi.initAndSendLocalNotification(message);
  } catch (e) {
    print(e);
  }
}

class FirebaseApi {
  final _androidChannel = const AndroidNotificationChannel(
    'high_importance_channel',
    'High Importance Notifications',
    description: "This channel is used for important notifications",
    importance: Importance.max,
  );

  final _localNotification = FlutterLocalNotificationsPlugin();

  void handleMessage(RemoteMessage? message) async {
    /*print("handle message");
    print(message?.toMap());*/
    if (message == null) return;
    //YOUR ACTION HERE
  }

  void handleInitialMessage(RemoteMessage? message) async {
    /*print("initial message");
    print(message?.toMap());*/
    if (message == null) return;
    //YOUR ACTION HERE
  }

  Future initLocalNotifications() async {
    const iOS = DarwinInitializationSettings();
    const android = AndroidInitializationSettings("@drawable/ic_launcher");
    const settings = InitializationSettings(android: android, iOS: iOS);

    await _localNotification.initialize(settings,
        onDidReceiveNotificationResponse: (response) {
      final message = RemoteMessage.fromMap(jsonDecode(response.payload!));
      handleMessage(message);
    });

    final appLaunchDetails =
        await _localNotification.getNotificationAppLaunchDetails();

    if (appLaunchDetails != null && appLaunchDetails.didNotificationLaunchApp) {
      if (appLaunchDetails.notificationResponse != null) {
        final message = RemoteMessage.fromMap(
            jsonDecode(appLaunchDetails.notificationResponse!.payload!));
        handleInitialMessage(message);
      }
    }

    final platform = _localNotification.resolvePlatformSpecificImplementation<
        AndroidFlutterLocalNotificationsPlugin>();
    await platform?.createNotificationChannel(_androidChannel);
  }

  initAndSendLocalNotification(RemoteMessage message) async {
    await initLocalNotifications();
    sendLocalNotification(message);
  }

  sendLocalNotification(RemoteMessage message) {
    final notification = message.data;
    _localNotification.show(
      message.hashCode,
      notification["title"],
      notification["body"],
      NotificationDetails(
        android: AndroidNotificationDetails(
            _androidChannel.id, _androidChannel.name,
            channelDescription: _androidChannel.description,
            icon: "@drawable/ic_launcher"),
      ),
      payload: jsonEncode(
        message.toMap(),
      ),
    );
  }

  Future initPushNotifications() async {
    await FirebaseMessaging.instance
        .setForegroundNotificationPresentationOptions(
            alert: true, badge: true, sound: true);

    //FirebaseMessaging.instance.getInitialMessage().then(handleInitialMessage);
    //FirebaseMessaging.onMessageOpenedApp.listen(handleBackgroundMessage);
    FirebaseMessaging.onBackgroundMessage(handleBackgroundMessage);
    FirebaseMessaging.onMessage.listen(
      (message) {
        //print(message.toMap());
        sendLocalNotification(message);
      },
    );
  }

  Future<String?> initNotification() async {
    final firebaseMessaging = FirebaseMessaging.instance;
    await firebaseMessaging.requestPermission();
    String? fcmToken = await firebaseMessaging.getToken();
    //start notifications
    initPushNotifications();
    initLocalNotifications();
    return fcmToken;
  }
}

通过这样做,前台、后台、终止状态应用程序通知都会得到正确处理,即使设备在离线时收到通知,一旦在线,所有通知都将发送到设备,因为 firebase 不会折叠待处理的通知。

希望它对某人有用。

© www.soinside.com 2019 - 2024. All rights reserved.