Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter Firebase Cloud Messaging onMessage is triggered twice

I already implemented the basic configuration suggested by the firebase_messaging flutter package. However, each time that I receive a notification on my flutter app onMessage is triggered twice. I'm using firebase_messaging 6.0.9, Dart 2.7.0 and Flutter 1.12.13+hotfix.5.

This is my [project]/android/build.gradle

    buildscript {
    repositories {
        google()
        jcenter()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.0'
        classpath 'com.google.gms:google-services:4.3.2'
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

rootProject.buildDir = '../build'
   subprojects {
       project.buildDir = "${rootProject.buildDir}/${project.name}"
   }
   subprojects {
       project.evaluationDependsOn(':app')
   }

   task clean(type: Delete) {
       delete rootProject.buildDir
   }

This is my [project]/android/app/build.gradle

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
    compileSdkVersion 28

    lintOptions {
        disable 'InvalidPackage'
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.chat_notification"
        minSdkVersion 16
        targetSdkVersion 28
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }
}

flutter {
    source '../..'
}

dependencies {
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}

apply plugin: 'com.google.gms.google-services'

And this is the code where the onMessage is triggered twice

import 'package:chat_notification/model/message.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';

class MessageWidget extends StatefulWidget {
  @override
  _MessageWidgetState createState() => _MessageWidgetState();
}

class _MessageWidgetState extends State<MessageWidget> {

  FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
  List<Message> messages = [];

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> response) async {
        print("onMessage: $response");
      },
      onLaunch: (Map<String, dynamic> response) async {
        print("onLaunch: $response");
      },
      onResume: (Map<String, dynamic> response) async {
        print("onResume: $response");
      },
    );
  }

  @override
  Widget build(BuildContext context) => ListView(
    children: messages.map(buildMessage).toList(),
  );

  Widget buildMessage(Message message) => ListTile(
    title: Text(message.title),
    subtitle: Text(message.body),
  );
}

I already try creating new projects but it seems to happen for each of them. I would really appreciate if anyone can help me about this.

EDIT:

This is no longer present in latest version of firebase_messaging: 7.0.0. Best solution I found is updating the package. Duplicated messages are not longer present.

like image 966
Gustavo Alexander Carrillo Rue Avatar asked Jan 11 '20 06:01

Gustavo Alexander Carrillo Rue


People also ask

How do I refresh FCM token flutter?

FirebaseMessaging _firebaseMessaging = new FirebaseMessaging(); _firebaseMessaging. configure( onMessage: (Map<String, dynamic> message) { }, onResume: (Map<String, dynamic> message) { }, onLaunch: (Map<String, dynamic> message) { }, ); _firebaseMessaging. getToken(). then((token) { saveToken(token); });

What are the two types of messages in firebase cloud messaging?

With FCM, developers can send two types of messages to users: notifications messages and data messages. Notification messages are displayed on the user's device by FCM on behalf of the application. Data messages are directly processed by the application, which is responsible for delivering the message to the user.

What is Firebase Cloud Messaging?

What does it do? Firebase Cloud Messaging (FCM) is a cross-platform messaging solution that lets you reliably send messages at no cost. Using FCM, you can notify a client app that new email or other data is available to sync. You can send notification messages to drive user re-engagement and retention.

How do I start using cloud messaging with flutterfire?

To start using the Cloud Messaging package within your project, import it at the top of your project files: Before using Firebase Cloud Messaging, you must first have ensured you have initialized FlutterFire. To create a new Messaging instance, call the instance getter on FirebaseMessaging:

Does flutterfirebase messaging support debugging for background isolates?

FlutterFirebase Messaging does now support debugging and hot reloading for background isolates, but only if your main isolate is also being debugged, (e.g. run your application in debug and then background it by switching apps so it's no longer in the foreground).

Why onattachedtoengine method of firebasemessagingplugin calls registerreceiver twice?

After fast investigation, the method onAttachedToEngine of the class FirebaseMessagingPlugin, which call registerReceiver, is called twice. That explain the double call.


2 Answers

Update:

This is no longer present in latest version of firebase_messaging (7.0.0 or up). Best solution I found is updating the package. Duplicated messages are not longer present.

Original Solution:

I am facing the same problem. I don't know the reason or the solution for it. A simple way-around is using a even odd counter to catch only one of the two callbacks.

import 'package:chat_notification/model/message.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';

class MessageWidget extends StatefulWidget {
  @override
  _MessageWidgetState createState() => _MessageWidgetState();
}

class _MessageWidgetState extends State<MessageWidget> {

  FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
  List<Message> messages = [];
  static int i = 0;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> response) async {
        if(i%2==0) {
          print("onMessage: $response");
          // something else you wanna execute
        };
        i++;
      },
      onLaunch: (Map<String, dynamic> response) async {
        print("onLaunch: $response");
      },
      onResume: (Map<String, dynamic> response) async {
        print("onResume: $response");
      },
    );
  }

  @override
  Widget build(BuildContext context) => ListView(
    children: messages.map(buildMessage).toList(),
  );

  Widget buildMessage(Message message) => ListTile(
    title: Text(message.title),
    subtitle: Text(message.body),
  );
}

This will run the code only once! Can be used for onLaunch and onResume similarly.

like image 142
werainkhatri Avatar answered Nov 05 '22 23:11

werainkhatri


I faced this issue with firebase_messaging: ^10.0.4

Going through literature, I see that this is a bug that keeps occurring every now and then across versions.

Knowing that, I personally wouldn't use the methods mentioned in the answer (using a boolean flag, odd/even flag).

I got around the issue by using a time controlled semaphore.

static int semaphore = 0;

FirebaseMessaging.onMessage.listen((RemoteMessage message) {
  if (semaphore != 0) {
    return;
  }
  semaphore = 1;
  Future.delayed(Duration).then((_) => semaphore = 0);
  handleMessage(message);
});

Also avoids concurrent remote message launches (based on the Duration you pass) - though I can't imagine a real world situation where remote messages might be launched concurrently.

like image 22
rasulfahad Avatar answered Nov 05 '22 23:11

rasulfahad