skip to Main Content

I have made this file push_notifications.dart

import 'dart:io';

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

const AndroidNotificationChannel androidSettings = AndroidNotificationChannel(
    'high_importance_channel', // id
    'High Importance Notifications', // title// description
    importance: Importance.high,
    playSound: true);

var iOSSettings = const IOSInitializationSettings(
  defaultPresentAlert: true,
  defaultPresentBadge: true,
  defaultPresentSound: true,
);

final FlutterLocalNotificationsPlugin localNotification =
    FlutterLocalNotificationsPlugin();

var initializationSettingsAndroid =
    const AndroidInitializationSettings('@mipmap/ic_launcher');

var initializationSettings = InitializationSettings(
  android: initializationSettingsAndroid,
  iOS: IOSInitializationSettings(),
);

var notificationDetails = NotificationDetails(
  android: AndroidNotificationDetails(
    androidSettings.id,
    androidSettings.name,
    importance: Importance.high,
    color: Colors.blue,
    playSound: true,
    icon: '@mipmap/ic_launcher',
  ),
  iOS: IOSNotificationDetails(),
);

class PushNotification {
  static final PushNotification _instance = PushNotification._ctor();

  factory PushNotification() {
    return _instance;
  }

  PushNotification._ctor();

  static init() async {
    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
    getToken();
    await localNotification
        .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin>()
        ?.createNotificationChannel(androidSettings);

    await localNotification
        .resolvePlatformSpecificImplementation<
            IOSFlutterLocalNotificationsPlugin>()
        ?.initialize(iOSSettings);

    await FirebaseMessaging.instance
        .setForegroundNotificationPresentationOptions(
      alert: true,
      badge: true,
      sound: true,
    );

    await FirebaseMessaging.instance.subscribeToTopic("topic");
  }

  static Future<void> _firebaseMessagingBackgroundHandler(
      RemoteMessage message) async {
    await Firebase.initializeApp();
    print("_firebaseMessagingBackgroundHandler : $message");
  }

  static getToken() async {
    await FirebaseMessaging.instance.getToken().then((token) {
      token = token;
      print("Token: $token");
    });
  }

  static void show(String title, String description) {
    localNotification.show(
      0,
      title,
      description,
      notificationDetails,
      payload: '',
    );
  }

  static listen(BuildContext context) {
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      print('Just received a notification when app is in background');
      showNotification(message, context);
    });

    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      print('Just received a notification when app is opened');
      showNotification(message, context);
    });
  }

  static showNotification(RemoteMessage message, BuildContext context) {
    RemoteNotification? notification = message.notification;
    AndroidNotification? android = message.notification?.android;
    AppleNotification? ios = message.notification?.apple;
    if (notification != null) {
      if (Platform.isIOS) {
        localNotification.show(
          notification.hashCode,
          notification.title,
          notification.body,
          notificationDetails,
        );
      } else {
        localNotification.show(
          notification.hashCode,
          notification.title,
          notification.body,
          notificationDetails,
        );
      }
    }

    if (message.data.containsKey("screen")) {
      Navigator.pushNamed(context, message.data["screen"]);
    }
  }
}

I initialised it in main.dart like this:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  // Initialize Firebase Cloud Messaging
  PushNotification.init();
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final AppRouter router = AppRouter();

  @override
  void initState() {
    PushNotification.listen(context);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => ThemeCubit(),
      child: BlocBuilder<ThemeCubit, ThemeState>(
        builder: (context, state) {
          return MaterialApp(
            debugShowCheckedModeBanner: false,
            onGenerateRoute: router.generateRoute,
            supportedLocales: AppLocalizations.supportedLocales,
            navigatorKey: navigatorKey,
          );
        },
      ),
    );
  }
}

Push notification only pops up when the app is in background. And this is what I’m sending via firebase

firebase

Also I’ve done changes in AndroidManifest.xml
AndroidManifest.xml

I want to navigate to contact-us screen. I have set the route and it’s working correctly with Navigator.pushNamed(context, 'contact-us');.
But somehow it’s not working with push notification.

3

Answers


  1. A few things here:

    1- click_action has to be set to "FLUTTER_NOTIFICATION_CLICK"

    2- click_action has to be set in the data section of a payload

    DATA='{ "notification": { "body": "this is a body", "title": "this is a title", }, "data": { "click_action": "FLUTTER_NOTIFICATION_CLICK", "sound": "default", "status": "done", "screen": "screenA", }, "to": "<FCM TOKEN>" }'
    This should allow you to receive the message in the onMessage handler in your flutter app.

    From there you can call Navigator.of(context).pushNamed(message[‘screen’]).

    If you don’t have a BuildContext at that point, you can register a GlobalKey as the navigatorKey property of your MaterialApp, and use it to access your Navigator globally, via GlobalKey.currentState

    Login or Signup to reply.
  2. Navigation through notification onTap is listened by FirebaseMessaging.onMessageOpenedApp
    example code is given below.

     FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      print('Just received a notification when app is opened');
      showNotification(message, context);
      if(message.notification != null){
        //"route" will be your root parameter you sending from firebase
        final routeFromNotification = message.data["route"];
        if (routeFromNotification != null) {
          routeFromNotification == "profile"?
            Navigator.of(context).pushNamed('profile')
        }
        else {
            developer.log('could not find the route');
          }
      }
    });
    
    Login or Signup to reply.
  3. You need to Provide GlobalKey and use navigation throw navigation Key like below initialise global key in main.dart for navigation without context

    GlobalKey<NavigatorState> navigatorKey = GlobalKey(debugLabel: "Main Navigator");
    

    Also provide navigator key Material App in navigationKey like below

    navigatorKey: navigatorKey,
    

    Use direct navigation using navigationKey and your navigation method in whole app where you want to use like below

    navigatorKey.currentState!.pushNamed('contact');
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search