Firebase notification didn't pop-up on screen when application is in background/terminated in Flutter

54 views Asked by At

I'm experimenting with Firebase notifications in a Flutter app, and as a newcomer to this technology, I've encountered an issue. When I send a notification while the app is in the foreground, it works as expected, and the notification pops up successfully. However, the same process doesn't function correctly when the app is in the background or terminated state. In these scenarios, I do receive a broadcast on the console, but it's worth noting that there are no error messages.

I/FLTFireMsgService(21367): FlutterFirebaseMessagingBackgroundService started!
D/FLTFireMsgReceiver(21367): broadcast received for message
W/FirebaseMessaging(21367): Notification Channel requested (1) has not been created by the app. Manifest configuration, or default, value will be used.
W/FirebaseMessaging(21367): Notification Channel set in AndroidManifest.xml has not been created by the app. Default value will be used.
I/flutter (21367): Handling a background message
I/flutter (21367): Saad
I/flutter (21367): This is a notification!
I/flutter (21367): {id: 12345, type: msg}

My main.dart:

void main() async{
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  runApp(const MyApp());
}

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler (RemoteMessage message) async{
  await Firebase.initializeApp();
  debugPrint("Handling a background message");
  debugPrint(message.notification!.title.toString());
  debugPrint(message.notification!.body.toString());
  debugPrint(message.data.toString());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
        providers: [
          ChangeNotifierProvider(create: (_) => AuthProvider()),
        ],
      child: MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.deepPurple,
      ),
      home: const FirstScreen(),
      // initialRoute: RoutesNames.splash,
      // onGenerateRoute: Routes.generateRoutes,
    ),
    );

  }
}

My Notification services class:

class NotificationServices{

  FirebaseMessaging messaging = FirebaseMessaging.instance;
  FlutterLocalNotificationsPlugin notificationsPlugin = FlutterLocalNotificationsPlugin();

  void initLocalNotification(BuildContext context, RemoteMessage message) async{
    var androidInitializationSettings = const AndroidInitializationSettings('@mipmap/ic_launcher');
    var iosInitializationSettings = const DarwinInitializationSettings();
    var initializationSettings = InitializationSettings(
      android: androidInitializationSettings,
      iOS: iosInitializationSettings
    );
    await notificationsPlugin.initialize(
      initializationSettings,
      onDidReceiveNotificationResponse: (payload){
        handleMessage(context, message);
      }
    );
  }

  void firebaseInIt(BuildContext context){
    FirebaseMessaging.onMessage.listen((msg) {
      if(kDebugMode){
        print(msg.notification!.title.toString());
        print(msg.notification!.body.toString());
      }
      if(Platform.isAndroid){
        initLocalNotification(context, msg);
        showNotification(msg);
      }
      else if(Platform.isIOS){
        // initLocalNotification(context, msg);
        // showNotification(msg);
      }
      else{
        //Nothing
      }
    });
  }

  Future<void> showNotification(RemoteMessage message) async{

    AndroidNotificationChannel channel = AndroidNotificationChannel(
      message.messageId.toString(),
      'High Importance Notifications',
      importance: Importance.max
    );

    AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails(
      channel.id.toString(),
      channel.name.toString(),
      channelDescription: 'Your Channel description',
      importance: Importance.high,
      priority: Priority.high,
      ticker: 'ticker'
    );

    DarwinNotificationDetails darwinNotificationDetails = const DarwinNotificationDetails(
      presentAlert: true,
      presentBadge: true,
      presentSound: true,
    );

    NotificationDetails notificationDetails = NotificationDetails(
      android: androidNotificationDetails,
      iOS: darwinNotificationDetails,
    );

    Future.delayed(Duration.zero, (){
      notificationsPlugin.show(
          0,
          message.notification!.title.toString(),
          message.notification!.body.toString(),
          notificationDetails
      );
    });
  }

  void requestNotificationPermission() async{

    NotificationSettings settings = await messaging.requestPermission(
      alert: true,
      announcement: true,
      badge: true,
      carPlay: true,
      criticalAlert: true,
      provisional: true,
      sound: true
    );

    if(settings.authorizationStatus == AuthorizationStatus.authorized){ // For Android
      debugPrint('User granted permission');
    }
    else if(settings.authorizationStatus == AuthorizationStatus.provisional){ // For IOS
      debugPrint('User granted provisional permission');
    }
    else{
      debugPrint('User denied permission');
    }
  }

  Future<String> getDeviceToken() async{
    String? token = await messaging.getToken();
    return token!;
  }

  void isTokenRefresh() async{
    messaging.onTokenRefresh.listen((event) {
      debugPrint(event.toString());
      debugPrint('Refresh');
    });
  }

  Future<void> setupInteractMessage(BuildContext context) async {

    // when app is terminated / killed
    RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage();
    if(initialMessage != null){
      handleMessage(context, initialMessage);
    }

    // when app is in background
    FirebaseMessaging.onMessageOpenedApp.listen((message) {
      handleMessage(context, message);
    });

  }

  void handleMessage(BuildContext context, RemoteMessage message){
    if(message.data['type'] == 'msg'){
      Navigator.push(context, MaterialPageRoute(builder: (_) => MessageScreen(
          id: message.data['id'],
          type: message.data['type']
      )));
    }
  }

  void sendPostNotification () {
    getDeviceToken().then((value) async{
      var data = {
        'to': value.toString(),
        'priority': 'high',
        'notification': {
          'title': 'Custom Notification',
          'body': 'Custom notify Body'
        },
        'data': {
          'id': '1123',
          'type': 'msg'
        }
      };
      await http.post(Uri.parse('https://fcm.googleapis.com/fcm/send'),
        body: jsonEncode(data),
        headers: {
          'Content-Type' : 'application/json; charset=UTF-8',
          'Authorization' : 'key=AAAAmMvK9iE:APA91bF_ww--Q4oE4egPFDjLc3VGsOYCy2oe5PF-8Yb0O-h_45vqyXQ2-U5g2VPDFaWhl9RxwTG8MshgC6WPfR0thA2SaEJ5F1dLy7BZlEUebu1qlIjubg9NsKPUIhDWWbnH_Jd9Xxov'
        }
      );
    });
  }
}

And my pubspec.yaml dependencies:

  cupertino_icons: ^1.0.2
  firebase_core: ^2.9.0
  firebase_storage: ^11.1.0
  firebase_auth: ^4.4.0
  cloud_firestore: ^4.5.0
  firebase_database: ^10.2.4
  fluttertoast: ^8.2.2
  http: ^0.13.5
  provider: ^6.0.5
  another_flushbar: ^1.12.29
  shared_preferences: ^2.1.0
  country_picker: ^2.0.20
  image_picker: ^1.0.1
  firebase_messaging: ^14.6.9
  flutter_local_notifications: ^15.1.1
  app_settings: ^5.1.1

It seems that I haven't configured the channel in the Android manifest file, but I attempted to handle it in the following manner in the application scope:

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

Is this the correct way to configure it?

0

There are 0 answers