skip to Main Content

When I click on the notification on background, it doesn’t redirect to the page I want.
I checked, and navigatorkey.currentContext is null.
(I’m using go_router, get_it, provider)

I referred to the blog below.
https://zzingonglog.tistory.com/40
https://zzingonglog.tistory.com/41

final navigatorKey = GlobalKey<NavigatorState>();
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
    FlutterLocalNotificationsPlugin();

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  String payloadData = jsonEncode(message.data);
  print('Got a message in background');
  if (message.notification != null) {
    PushNotification.showSimpleNotification(
      title: message.notification!.title!,
      body: message.notification!.body!,
      payload: payloadData,
    );
  }
}

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

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

  await PushNotification.init();
  await PushNotification.localNotiInit();

  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

  FirebaseMessaging.onMessage.listen((RemoteMessage message) {
    String payloadData = jsonEncode(message.data);
    print('Got a message in foreground');
    if (message.notification != null) {
      PushNotification.showSimpleNotification(
        title: message.notification!.title!,
        body: message.notification!.body!,
        payload: payloadData,
      );
    }
  });

  final NotificationAppLaunchDetails? notificationAppLaunchDetails =
      await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
  if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
    String payload =
        notificationAppLaunchDetails!.notificationResponse?.payload ?? "";
    print('Got a message in terminated');
    Future.delayed(Duration(seconds: 1), () {
      navigatorKey.currentContext
          ?.push('/notification/message', extra: payload);
    });
  }
  diSetup();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: router,
      title: 'MyApp',
      theme: ThemeData(
        scaffoldBackgroundColor: Colors.white,
        appBarTheme: AppBarTheme(
          // backgroundColor: ColorStyles.primary40,
          titleTextStyle: TextStyles.extraLargeTextBold.copyWith(
            color: ColorStyles.black,
          ),
          backgroundColor: Colors.transparent,
        ),
        useMaterial3: true,
      ),
    );
  }
}

I tried defining Globalkey here and there.

2

Answers


  1. The reason it isn’t navigating to the correct screen/page once clicking a notification, Is, since you have to actually assign the key to the MaterialApp.

    Essentially, you need to ‘tie’ the key to the MaterialApp to let it know what key to use.

    In your code:

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          ...
          navigatorKey: navigatorKey, // --> Add this line
    
    Login or Signup to reply.
    1. Assign the navigatorKey to both GoRouter and MaterialApp.router

      First, define a global navigatorKey and assign it to both your GoRouter and MaterialApp.router.

    final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
    
    final GoRouter router = GoRouter(
      navigatorKey: navigatorKey,
      routes: [
        // Your route definitions
      ],
    );
    

    Then, in your MyApp widget:

    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp.router(
          routerConfig: router,
          navigatorKey: navigatorKey, // Assign the navigatorKey here
          title: 'MyApp',
          theme: ThemeData(
            // Your theme data
          ),
        );
      }
    }
    
    1. Use router.go() Instead of navigatorKey.currentContext?.push()

      In your notification handler, rather than using navigatorKey.currentContext?.push(), you should use the GoRouter instance to navigate. Since you might not have a BuildContext, using the router directly is more reliable.

      First, make sure your GoRouter instance is accessible where you need it. You can achieve this by defining it globally or using a service locator.

    @pragma('vm:entry-point')
    Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
      String payloadData = jsonEncode(message.data);
      print('Got a message in background');
      if (message.notification != null) {
        PushNotification.showSimpleNotification(
          title: message.notification!.title!,
          body: message.notification!.body!,
          payload: payloadData,
        );
      }
    
      // Navigate to the desired route
      router.go('/notification/message', extra: payloadData);
    }
    
    1. Handle Initial Routes When the App Is Terminated

      When your app is launched from a terminated state due to a notification tap, you should handle the initial route appropriately.

      In your main() function:

    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
    
      // Your initialization code
    
      final NotificationAppLaunchDetails? notificationAppLaunchDetails =
          await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
      String initialRoute = '/';
      Object? initialExtra;
    
      if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
        String payload =
            notificationAppLaunchDetails!.notificationResponse?.payload ?? "";
        print('Got a message in terminated');
        initialRoute = '/notification/message';
        initialExtra = payload;
      }
    
      runApp(MyApp(initialRoute: initialRoute, initialExtra: initialExtra));
    }
    

    Then, modify your MyApp widget to accept the initial route:

    class MyApp extends StatelessWidget {
      final String initialRoute;
      final Object? initialExtra;
    
      const MyApp({super.key, required this.initialRoute, this.initialExtra});
    
      @override
      Widget build(BuildContext context) {
        final GoRouter router = GoRouter(
          navigatorKey: navigatorKey,
          initialLocation: initialRoute,
          initialExtra: initialExtra,
          routes: [
            // Your route definitions
          ],
        );
    
        return MaterialApp.router(
          routerConfig: router,
          navigatorKey: navigatorKey,
          title: 'MyApp',
          theme: ThemeData(
            // Your theme data
          ),
        );
      }
    }
    
    1. Access Payload in the Target Screen

      In your route definition for ‘/notification/message’, make sure to handle the extra data:

    GoRoute(
      path: '/notification/message',
      builder: (context, state) {
        final payload = state.extra as String?;
        return NotificationMessagePage(payload: payload);
      },
    ),
    

    Summary

    • Assign navigatorKey: Ensure your navigatorKey is assigned to both GoRouter and MaterialApp.router.
    • Use GoRouter for Navigation: Use router.go(‘/path’) instead of navigatorKey.currentContext?.push().
    • Handle Initial Routes: When the app launches from a terminated state, pass the initial route and payload to your MyApp widget.
    • Access Extra Data: In your target screen, access the payload via state.extra.

    Why This Works

    • Navigator Key Assignment: Assigning the navigatorKey connects your navigation logic to the app’s Navigator, making navigatorKey.currentState valid.
    • Using GoRouter: Since you’re using go_router, it’s best to use its API for navigation to ensure consistent behavior.
    • Initial Route Handling: Passing the initial route ensures that your app navigates to the correct screen upon launch from a notification.
    • Extra Data Access: Using state.extra allows you to pass and access additional data (like your payload) in the new route.

    By following these steps, your app should correctly navigate to the desired page when a notification is tapped, regardless of whether the app is in the foreground, background, or terminated.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search