'firebase_messaging returns Null check operator used on a null value after tapping the notification

I have posted an issue on flutterfire github and the response is not helping me at all. So I hope someone here will help me guide to fix the problem I'm facing.

Also I have posted another question here but it is with GetX plugin and the response on github said they won't exactly know the problem since I'm using GetX. If you want to see it here is the link to it FirebaseMessaging.instance.getInitialMessage() not working with Splash Screen

Anyway, I created a sample Flutter app without GetX. After I created the app, I faced an error where it says

Null check operator used on a null value

How we handle this kind of error?

Here is my main.dart

import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:learningapp/home_screen.dart';
import 'package:learningapp/login_screen.dart';
import 'package:learningapp/result_screen.dart';
import 'package:learningapp/splash_screen.dart';

import 'local_notification_service.dart';

//receive notif if app is on background even if app terminated
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  // ignore: avoid_print
  print('Handling a background message: ${message.messageId}');
}

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

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

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

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    LocalNotificationService.initialize(context);
    //open notif content from terminated state of the app
    FirebaseMessaging.instance.getInitialMessage().then((message) async {
      if (message != null) {
        final redirectRoute = message.data['route'];
        if (redirectRoute != null) {
          print('TERMINATED');
          print('redirectRoute $redirectRoute');
          Navigator.of(context).pushReplacementNamed(redirectRoute);
        }
      }
    });

    //only works if app in foreground
    FirebaseMessaging.onMessage.listen((message) {
      LocalNotificationService.display(message);
    });

    //onclick notif system tray only works if app in background but not terminated
    FirebaseMessaging.onMessageOpenedApp.listen((message) {
      final redirectRoute = message.data['route'];
      if (redirectRoute != null) {
        print('BACKGROUND');
        print('redirectRoute $redirectRoute');
        Navigator.of(context).pushReplacementNamed(redirectRoute);
      }
    });
  }

  bool isAuth = false;

  Future<bool> _checkIfLoggedIn() async {
    final currentUser = FirebaseAuth.instance.currentUser;
    print(currentUser);
    if (currentUser != null) {
      return isAuth = true;
    }
    return isAuth = false;
  }

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: Future.delayed(const Duration(seconds: 3)),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          print('isAuth : $isAuth');
          return MaterialApp(
            title: 'Flutter Demo',
            theme: ThemeData(
              primarySwatch: Colors.blue,
            ),
            initialRoute: isAuth ? 'home' : 'login',
            routes: {
              'home': (context) => const HomeScreen(),
              'login': (context) => const LoginScreen(),
              'result': (context) => const ResultScreen(),
            },
          );
        }

        return FutureBuilder(
          future: _checkIfLoggedIn(),
          builder: (context, snapshot) {
            return const SplashScreen();
          },
        );
      },
    );
  }
}

Here is my local notification service class

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

class LocalNotificationService {
  static final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
      FlutterLocalNotificationsPlugin();

  static void initialize(BuildContext context) {
    const InitializationSettings initializationSettings =
        InitializationSettings(
            android: AndroidInitializationSettings('@mipmap/ic_launcher'));

    flutterLocalNotificationsPlugin.initialize(
      initializationSettings,
      onSelectNotification: ((redirectRoute) async {
        if (redirectRoute != null) {
          print('FOREGROUND');
          print('redirectRoute $redirectRoute');
          Navigator.of(context).pushReplacementNamed(redirectRoute);
        }
      }),
    );
  }

  static void display(RemoteMessage remoteMessage) async {
    try {
      final id = DateTime.now().millisecondsSinceEpoch ~/ 1000;
      const NotificationDetails notificationDetails = NotificationDetails(
        android: AndroidNotificationDetails(
          "learningapp",
          "learningapp channel",
          importance: Importance.max,
          priority: Priority.high,
          color: Color(0xFF42A5F5),
        ),
      );

      await flutterLocalNotificationsPlugin.show(
        id,
        remoteMessage.notification!.title,
        remoteMessage.notification!.body,
        notificationDetails,
        payload: remoteMessage.data['route'],
      );
    } on Exception catch (e) {
      // ignore: avoid_print
      print(e);
    }
  }
}

Here is the sample log output

C:\Users\User\Desktop\learningapp>flutter run --release
Launching lib\main.dart on RNE L22 in release mode...
Running Gradle task 'assembleRelease'...
Note: C:\flutter\.pub-cache\hosted\pub.dartlang.org\firebase_messaging-11.2.8\android\src\main\java\io\flutter\plugins\firebase\messaging\JobIntentService.java uses or overrides a deprecated API.
Running Gradle task 'assembleRelease'...
Note: Recompile with -Xlint:deprecation for details.
Running Gradle task 'assembleRelease'...
     61.6s
√  Built build\app\outputs\flutter-apk\app-release.apk
(7.8MB).
Installing build\app\outputs\flutter-apk\app.apk...
   2,839ms

Flutter run key commands.
h List all available interactive commands.
c Clear the screen
q Quit (terminate the application on the device).
I/flutter ( 9987): User(displayName: , email: [email protected], emailVerified: false, isAnonymous: false, metadata: UserMetadata(creationTime: 2022-03-10 14:46:11.419, lastSignInTime: 2022-03-10 17:55:45.210), phoneNumber: , photoURL: null, providerData, [UserInfo(displayName: , email: [email protected], phoneNumber: , photoURL: null, providerId: password, uid: [email protected])], refreshToken: , tenantId: null, uid: RpEG5Y5qt7Y7aGvJ6Mf2FweAlf33)
W/FlutterJNI( 9987): FlutterJNI.loadLibrary called more than once
W/FlutterJNI( 9987): FlutterJNI.prefetchDefaultFontManager called more than once
W/FlutterJNI( 9987): FlutterJNI.init called more than once
I/flutter ( 9987): isAuth : true
I/flutter ( 9987): FOREGROUND
I/flutter ( 9987): redirectRoute result
E/flutter ( 9987): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Null check operator used on a null value
E/flutter ( 9987): #0      Navigator.of (package:flutter/src/widgets/navigator.dart:2561)
E/flutter ( 9987): #1      LocalNotificationService.initialize.<anonymous closure> (package:learningapp/local_notification_service.dart:20)
E/flutter ( 9987): #2      LocalNotificationService.initialize.<anonymous closure> (package:learningapp/local_notification_service.dart:16)
E/flutter ( 9987): #3      AndroidFlutterLocalNotificationsPlugin._handleMethod (package:flutter_local_notifications/src/platform_flutter_local_notifications.dart:460)
E/flutter ( 9987): #4      MethodChannel._handleAsMethodCall (package:flutter/src/services/platform_channel.dart:414)       
E/flutter ( 9987): #5      MethodChannel.setMethodCallHandler.<anonymous closure> (package:flutter/src/services/platform_channel.dart:407)
E/flutter ( 9987): #6      _DefaultBinaryMessenger.setMessageHandler.<anonymous closure> (package:flutter/src/services/binding.dart:377)
E/flutter ( 9987): #7      _DefaultBinaryMessenger.setMessageHandler.<anonymous closure> (package:flutter/src/services/binding.dart:374)
E/flutter ( 9987): #8      _invoke2.<anonymous closure> (dart:ui/hooks.dart:190)
E/flutter ( 9987): #9      _rootRun (dart:async/zone.dart:1426)
E/flutter ( 9987): #10     _CustomZone.run (dart:async/zone.dart:1328)
E/flutter ( 9987): #11     _CustomZone.runGuarded (dart:async/zone.dart:1236)
E/flutter ( 9987): #12     _invoke2 (dart:ui/hooks.dart:189)  
E/flutter ( 9987): #13     _ChannelCallbackRecord.invoke (dart:ui/channel_buffers.dart:42)
E/flutter ( 9987): #14     _Channel.push (dart:ui/channel_buffers.dart:132)
E/flutter ( 9987): #15     ChannelBuffers.push (dart:ui/channel_buffers.dart:329)
E/flutter ( 9987): #16     PlatformDispatcher._dispatchPlatformMessage (dart:ui/platform_dispatcher.dart:583)
E/flutter ( 9987): #17     _dispatchPlatformMessage (dart:ui/hooks.dart:89)
E/flutter ( 9987):

UPDATES on FCM getInitialMessage() returns null

I have solved the problem with an alternative solution for the GetX problem.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source