Search code examples
flutterdartpush-notificationfirebase-cloud-messaging

Open Particular Screens according to Push Notification data


I am trying this logic that if there is OrderId in notification data then it should open OrdersScreen otherwise open default screen but there is orderId in the data still it opens default screen only i dont know can any one fix this

Homescreen

class _MyHomeScreenState extends State<MyHomeScreen>
    with SingleTickerProviderStateMixin {
  int _currentPage = 0;
  final PageController _pageController = PageController();
  Timer? _timer;
  bool _isConnected = true;
  bool _hasError = false;

  //NOTIFICATION
  Future<void> _initializeFCM() async {
    FirebaseMessaging messaging = FirebaseMessaging.instance;

    // Request notification permissions
    NotificationSettings settings = await messaging.requestPermission(
      alert: true,
      badge: true,
      sound: true,
    );

    if (settings.authorizationStatus == AuthorizationStatus.authorized) {
      final apnsToken = await FirebaseMessaging.instance.getAPNSToken();
      print('Apns: $apnsToken');

      print('User granted permission');
      final fcmToken = await FirebaseMessaging.instance.getToken();
      if (fcmToken != null) {
        print('FCM Token: $fcmToken');
      }
    } else {
      print('User declined or has not accepted permission');
    }

    // Handle background messages
    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

    FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
      print('🔔 Received a foreground notification:');
      print('📨 Message Data: ${message.data}');
      print('📄 Notification Title: ${message.notification?.title}');
      print('📄 Notification Body: ${message.notification?.body}');

      await _showNotification(
        message.notification?.title,
        message.notification?.body,
      );
    });

    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      print("Notification clicked: ${message.data}");
      _handleNotificationNavigation(message.data);
    });

    RemoteMessage? initialMessage =
        await FirebaseMessaging.instance.getInitialMessage();
    if (initialMessage != null) {
      print(
          "App opened from terminated state via notification: ${initialMessage.data}");
      _handleNotificationNavigation(initialMessage.data);
    }
  }

  void _handleNotificationNavigation(Map<String, dynamic> data) async {
    final String? orderId = data['orderId'];

    await Future.delayed(const Duration(seconds: 5));

    if (orderId != null && orderId.isNotEmpty) {
      Navigator.of(context).push(
        MaterialPageRoute(builder: (ctx) => OrdersScreen()),
      );
    } else {
      Navigator.of(context).push(
        MaterialPageRoute(builder: (ctx) => BottomBars()),
      );
    }
  }

  Future<void> _showNotification(String? title, String? body) async {
    const AndroidNotificationDetails androidDetails =
        AndroidNotificationDetails(
      'your_channel_id',
      'your_channel_name',
      icon: '@mipmap/ic_launcher',
      channelDescription: 'Your channel description',
      importance: Importance.high,
      priority: Priority.high,
    );

    const NotificationDetails platformDetails =
        NotificationDetails(android: androidDetails);

    final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
        FlutterLocalNotificationsPlugin();

    await flutterLocalNotificationsPlugin.show(
      0, // notification ID
      title, // notification title
      body, // notification body
      platformDetails,
    );
  }

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

    final data = message.data;
    _handleNotificationNavigation(data);
  }

  Future<void> _callPostAPI() async {
    final prefs = await SharedPreferences.getInstance();

    final alreadyCalled = prefs.getBool('apiCalledThisLaunch') ?? false;
    if (alreadyCalled) {
      print("API already called for this app launch");
      return;
    }

    final fcmToken = await FirebaseMessaging.instance.getToken();
    if (fcmToken == null) {
      print("Failed to fetch FCM Token");
      return;
    }

    final accessToken = prefs.getString('accessToken');
    if (accessToken == null) {
      print("Access token not found");
      return;
    }

    final platform = Platform.isAndroid
        ? "android"
        : Platform.isIOS
            ? "ios"
            : "unknown";

    final requestBody = {
      "token": fcmToken,
      "platform": platform,
    };

    final url = Uri.parse('');
    try {
      final response = await http.post(
        url,
        headers: {
          "Content-Type": "application/json",
          "Authorization": "Bearer $accessToken",
        },
        body: json.encode(requestBody),
      );

      if (response.statusCode == 200) {
        final responseData = json.decode(response.body);

        print(responseData);
        print("API called successfully");

        await prefs.setBool('apiCalledThisLaunch', true);
      } else {
        print("Failed to call API: ${response.statusCode}");
      }
    } catch (e) {
      print("Error calling API: $e");
    }
  }

I dont know if anything should change in Main.dart also

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  try {
    await Firebase.initializeApp();
    print("Handling a background message: ${message.messageId}");
  } catch (e) {
    print("Error handling background message: $e");
  }
}

Future<void> _firebaseMessagingAppOpenHandler(RemoteMessage message) async {
  try {
    await Firebase.initializeApp();
    print("Handling a App open message: ${message.messageId}");
  } catch (e) {
    print("Error handling App open message: $e");
  }
}

final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
    FlutterLocalNotificationsPlugin();

void initializeNotifications() async {
  const AndroidInitializationSettings initializationSettingsAndroid =
      AndroidInitializationSettings('');

  final InitializationSettings initializationSettings =
      InitializationSettings(android: initializationSettingsAndroid);

  await flutterLocalNotificationsPlugin.initialize(initializationSettings);
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final prefs = await SharedPreferences.getInstance();
  await prefs.setBool('apiCalledThisLaunch', false);
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  FirebaseMessaging.onMessageOpenedApp.listen(_firebaseMessagingAppOpenHandler);
  FirebaseMessaging.onMessage.listen((RemoteMessage message) {
    print(
        'Received a message while in the foreground: ${message.notification?.title}');
  });
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
    DeviceOrientation.portraitDown,
  ]);

  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => ProfileProvider()),
        ChangeNotifierProvider(create: (context) => SignupProvider()),
        ChangeNotifierProvider(create: (context) => Cart()),
        ChangeNotifierProvider(create: (context) => AddressProvider()),
        ChangeNotifierProvider(create: (context) => FavoriteProvider()),
      ],
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
        brightness: Brightness.light,
      ),
      darkTheme: ThemeData(
        brightness: Brightness.light,
      ),
      themeMode: ThemeMode.light,
      home: const SplashScreen(),
      routes: {
        '/cart': (context) => const CartScreen(),
        '/orders': (context) => OrdersScreen(),
        '/default': (context) => BottomBars(),
      },
    );
  }
}

in logs there is coming orderId still it opens the details screen

D/FLTFireMsgReceiver( 8640): broadcast received for message
I/flutter ( 8640): Received a message while in the foreground: Hurray!
I/flutter ( 8640): 🔔 Received a foreground notification:
I/flutter ( 8640): 📨 Message Data: {orderId: 676e8e92cf1c97006a3a981c, click_action: FLUTTER_NOTIFICATION_CLICK}
I/flutter ( 8640): 📄 Notification Title: Hurray!
I/flutter ( 8640): 📄 Notification Body: Your order has been confirmed 😃


Solution

  • This picture shows which method to use for extracting the notification data and when to use it.

    Based on your question, the image below shows when to use each method to extract the notification info. Additionally, please refer to the new notification payload, as the old one is deprecated.