Search code examples
androidflutterfirebasefirebase-cloud-messagingflutter-local-notification

Why is my app using default sound on background notifications


I'm developing an app where I need a custom sound to play whenever I receive a notification in foreground and background. It works fine in the foreground but on the background, it plays the default sound from the device.

I'm using a physical phone to test the app Realme GT (RMX2202). I already tried in the emulator as well and the same happens

I am using the package flutter_local_notifications

Could I be missing something? I've checked multiples tutorials and people with the same problem, but none of them solves my issue.

This is my code:

 WidgetsFlutterBinding.ensureInitialized();

   RemoteMessage? initialMessage = newLogged == true
      ? await FirebaseMessaging.instance.getInitialMessage()
      : null;

  void initMessaging() async {
    final token = await FirebaseMessaging.instance.getToken();
    log(DateTime.now().toString() +
        ' ' +
        ' ------------ FIREBASE TOKEN -----> $token  ');
    firebaseToken = token.toString();

    FirebaseMessaging messaging = FirebaseMessaging.instance;
    late FlutterLocalNotificationsPlugin fltNotification;

    var androiInit = AndroidInitializationSettings("@mipmap/ic_launcher");
    var iosInit = DarwinInitializationSettings();
    var initSetting = InitializationSettings(android: androiInit, iOS: iosInit);
    fltNotification = FlutterLocalNotificationsPlugin();
    fltNotification.initialize(initSetting);
    var androidDetails = AndroidNotificationDetails(
      'id',
      'name',
      channelDescription: 'description',
      importance: Importance.max,
      priority: Priority.high,
      playSound: true,
      ticker: 'ticker',
      icon: ('@mipmap/ic_launcher'),
      sound: RawResourceAndroidNotificationSound('newservice'),
      // sound: UriAndroidNotificationSound("assets/sounds/classic.mp3"),
    );
    var iosDetails = DarwinNotificationDetails();
    var generalNotificationDetails =
        NotificationDetails(android: androidDetails, iOS: iosDetails);
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      RemoteNotification? notification = message.notification;
      AndroidNotification? android = message.notification?.android;
      if (notification != null && android != null) {
        fltNotification.show(notification.hashCode, notification.title,
            notification.body, generalNotificationDetails);
      }
    });
  }

Android Manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mkis.gb24">
   <application
        android:label="new GB24"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- Specifies an Android theme to apply to this Activity as soon as
                 the Android process has started. This theme is visible to the user
                 while the Flutter UI initializes. After that, this theme continues
                 to determine the Window background behind the Flutter UI. -->
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />

            <meta-data
              android:name="com.google.firebase.messaging.default_notification_icon" 
              android:resource="@mipmap/ic_launcher"
              />
              
              <meta-data
                android:name="com.google.firebase.messaging.default_notification_channel_id"
                android:value="default_notification_channel_id" />
        
            <intent-filter>
                <action android:name="FLUTTER_NOTIFICATION_CLICK" />
                 <category android:name="android.intent.category.DEFAULT" />
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </activity>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>
    
</manifest>

Solution

  • Solved it by forcing the name of the channel.id, channel.name and channel.description to be all the same.

    So basically changed this:

    NotificationDetails(
                  android: AndroidNotificationDetails(
                    channel.id,
                    channel.name,
                    channel.description,
                    icon: android?.smallIcon,
                  ),
                ));
    

    To this

    NotificationDetails(
                  android: AndroidNotificationDetails(
                    'MyID',
                    'MyName',
                    description: 'MyDescription',
                    icon: android?.smallIcon,
                  ),
                ));
    

    And added this:

      await Firebase.initializeApp();
    
      FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
      await flutterLocalNotificationsPlugin
          .resolvePlatformSpecificImplementation<
              AndroidFlutterLocalNotificationsPlugin>()
          ?.createNotificationChannel(channel);
    
    Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
      await Firebase.initializeApp();
      log('Handling a background message ${message.messageId}');
      log('${message.data}');
      flutterLocalNotificationsPlugin.show(
        message.data.hashCode,
        message.data['title'],
        message.data['body'],
        NotificationDetails(
          android: AndroidNotificationDetails(
            'MyID',
            'MyName',
            channelDescription: 'MyDescription',
            importance: Importance.max,
            priority: Priority.high,
            playSound: true,
            ticker: 'ticker',
            icon: ('@mipmap/ic_launcher'),
            sound: RawResourceAndroidNotificationSound('mySound'),
            // sound: UriAndroidNotificationSound("assets/sounds/classic.mp3"),
          ),
        ),
      );
    }
    

    EDIT: It's also important to mention that when using firebase, the notification channel has to be specified when sending a notification along with the click_action.

    And finally, in AndroidManifest.xml:

    <meta-data 
      android:name=
      "com.google.firebase.messaging.default_notification_channel_id"
      android:value=
      "default_channel_id" 
    />
    

    Because if the channel is not specified, Android will use the Miscellaneous channel instead and use the device's default notification sound.