onMessage:对传入消息调用两次回调 Flutter web

Posted

技术标签:

【中文标题】onMessage:对传入消息调用两次回调 Flutter web【英文标题】:onMessage: callback called twice on incoming messages Flutter web 【发布时间】:2020-12-27 14:21:29 【问题描述】:

在我的应用程序中,对于 Web 版本,我将包 firebase 7.3.0 用于 Firebase 服务,我现在也在为 Web 设置 FCM。 当我在前台收到应用程序的新消息时,来自messaging()onMessage: 被触发两次。在某个 Flutter 版本之前,flutter_messaging 设备插件也曾经出现过这种情况,但现在已解决。

我基本上设置了一个StreamTransformer 来获取与flutter_messagingPlatformPushNotificationDevice 中使用的设备包相同类型的Map<String, dynamic> 中的消息,我使用Stub 来根据平台切换类。 在网络类PlatformPushNotificationWeb 中,我将消息传递实例化为var firebaseMessaging = messaging(); 并声明我的方法,其中之一是onMessage()

Stream<Map<String, dynamic>> onMessage()  async* 

    print('PlatformPushNotificationWeb.onMessage() started');
    handleData(Payload payload, EventSink<Map<String, dynamic>> sink) 
        Map<String,dynamic> message = 
          'notification': 
            'title': payload.notification.title,
            'body': payload.notification.body,
            'sound': true
          ,
          'data': payload.data
        ;
      sink.add(message);
    

    final transformer = StreamTransformer<Payload, Map<String, dynamic>>.fromHandlers(
        handleData: handleData);

    yield* firebaseMessaging.onMessage.transform(transformer);
  

所以无论平台如何,我所在区域的侦听器都会收到相同的消息类型,

Stream<PushNotificationState> _mapListenToMessagesToState(ListenToMessages event) async* 
    print('_mapListenToMessagesToState started');
    _pushNotificationSwitcher.onMessage().listen((message) 
      print('_mapListenToMessagesToState onMessage() listener: received new message');
      add(ReceivedNewMessage(message: message));
    );
  

但是对于每条传入的消息,我都会让侦听器响应两次。

我将index.html 设置为:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>fixit cloud biking</title>
  <!--  <meta name="google-signin-client_id" content="YOUR_GOOGLE_SIGN_IN_OAUTH_CLIENT_ID.apps.googleusercontent.com">-->
  <meta name="google-signin-client_id" content="xxxx.apps.googleusercontent.com">
<!--  <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">-->
</head>
<!--<body>-->
<body id="app-container">
<script src="main.dart.js?version=45" type="application/javascript"></script>
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.19.1/firebase-app.js"></script>

<!-- TODO: Add SDKs for Firebase products that you want to use
     https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/7.19.1/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.19.1/firebase-analytics.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.19.1/firebase-messaging.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.19.1/firebase-storage.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.19.1/firebase-database.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.19.1/firebase-remote-config.js"></script>


<script>
if ("serviceWorker" in navigator) 
  window.addEventListener("load", function () 
     //navigator.serviceWorker.register("/flutter_service_worker.js");
    navigator.serviceWorker.register("/firebase-messaging-sw.js");
  );

</body>
</html>

firebase-messaging-sw.js 文件为:

importScripts("https://www.gstatic.com/firebasejs/7.19.1/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/7.19.1/firebase-messaging.js");

firebase.initializeApp(
  apiKey: "xxxx",
            authDomain: "xxxx",
            databaseURL: "xxxx",
            projectId: "xxx",
            storageBucket: "xxxx",
            messagingSenderId: "xxxx",
            appId: "xxx",
            measurementId: "G-xxxx",
);
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function (payload) 
console.log('[firebase-messaging-sw.js] Received background message ', payload);

    const promiseChain = clients
        .matchAll(
            type: "window",
            includeUncontrolled: true
        )
        .then(windowClients => 
            for (let i = 0; i < windowClients.length; i++) 
                const windowClient = windowClients[i];
                windowClient.postMessage(payload);
            
        )
        .then(() => 
            return registration.showNotification("New Message");
        );
    return promiseChain;
);
self.addEventListener('notificationclick', function (event) 
    console.log('notification received: ', event)
);

可能是在PlatformPushNotificationWeb 类和firebase-messaging-sw.js 文件中实例化消息是onMessage: 回调被触发两次的原因吗? 非常感谢。

【问题讨论】:

【参考方案1】:

事实证明..一个很好的清理,android Studio 和机器重启解决了它..

现在我没有两次收到相同的消息,但对于那些实际上正在尝试重复消息的人来说,这将解决它,这只是一种解决方法。

刚刚声明了int lastMessageId = 0 变量。 当有消息进来时,对照它检查它的id,只有当它们不同时,才将新的消息ID保存为lastMessageId并显示消息。

Stream<PushNotificationState> _mapListenToMessagesToState(ListenToMessages event) async* 
    print('_mapListenToMessagesToState started');
    int lastMessageId = 0;

    _pushNotificationSwitcher.onMessage().listen((message) 
      print('incoming message is : $message');
      var data = message['data'];
      int messageId = int.parse(data['id']);

      if( lastMessageId != messageId) 
        lastMessageId = messageId;
        print(
            '_mapListenToMessagesToState onMessage() listener: received new message');
        add(ReceivedNewMessage(message: message));
      
    );
  

【讨论】:

以上是关于onMessage:对传入消息调用两次回调 Flutter web的主要内容,如果未能解决你的问题,请参考以下文章

新兴的API(javascript)

在 es6 中,创建一个带有回调的事件监听器到一个可迭代对象中

Qt回调函数

chrome.runtime.onMessage多次调用

调用 onMessage 后 ActiveMQ 消费者内存使用量不断增加

WebRTC 源码分析之一:几个核心设计概念