Search code examples
androidflutterdartpushflutter-getx

How to navigate to desired screen when FCM Background Message received?


I am having a hard time navigating to a screen when a background FCM message receives. Currently, I am sending an FCM message with some data and when it gets received by a device then it calls this package that shows a calling notification, and when the user clicks on accept call option then I want to open my app and navigate to the desired screen. I use GetX for navigation and when I try to go to another screen it gives this exception: enter image description here

I have tried almost everything to work this out but I am still unable to solve this problem.

my FirebaseMessaging.onBackgroundMessage Background handler which receives the notification also listens to user feedback on whether the call is accepted or rejected:

Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {


  var incoming = <String, dynamic>{
    'id': message.data['callerID'],
    'nameCaller': message.data['callerName'],
    'appName': 'Callkit',
    'avatar': message.data['callerImage'],
    'handle': '',
    'type': 0,
    'duration': 30000,
    'extra': <String, dynamic>{'userId': '1a2b3c4d'},
    'headers': <String, dynamic>{'apiKey': 'Abc@123!', 'platform': 'flutter'},
    'android': <String, dynamic>{
      'isCustomNotification': true,
      'isShowLogo': false,
      'ringtonePath': 'ringtone_default',
      'backgroundColor': '#0955fa',
      //'backgroundUrl': 'https://i.pravatar.cc/500',
      'actionColor': '#4CAF50'
    }};
  await FlutterCallkitIncoming.showCallkitIncoming(incoming);


  try {
    FlutterCallkitIncoming.onEvent.listen((event) {
      switch (event!.name) {
        case CallEvent.ACTION_CALL_INCOMING:
          print('INCOMING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
          break;
        case CallEvent.ACTION_CALL_START:
        // TODO: started an outgoing call
        // TODO: show screen calling in Flutter
          break;
        case CallEvent.ACTION_CALL_ACCEPT:
          print('accepted');
          Get.offAll(()=> Incoming(
              userName: null,
              userImage: null,
              userID: null,
              userUsername: null));
          break;
        case CallEvent.ACTION_CALL_DECLINE:
          print('rejected');
          break;
        case CallEvent.ACTION_CALL_ENDED:
        // TODO: ended an incoming/outgoing call
          break;
        case CallEvent.ACTION_CALL_TIMEOUT:
        // TODO: missed an incoming call
          break;
        case CallEvent.ACTION_CALL_CALLBACK:
        // TODO: only Android - click action `Call back` from missed call notification
          break;
        case CallEvent.ACTION_CALL_TOGGLE_HOLD:
        // TODO: only iOS
          break;
        case CallEvent.ACTION_CALL_TOGGLE_MUTE:
        // TODO: only iOS
          break;
        case CallEvent.ACTION_CALL_TOGGLE_DMTF:
        // TODO: only iOS
          break;
        case CallEvent.ACTION_CALL_TOGGLE_GROUP:
        // TODO: only iOS
          break;
        case CallEvent.ACTION_CALL_TOGGLE_AUDIO_SESSION:
        // TODO: only iOS
          break;
      }
      print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
    });
  } on Exception {}

}

Solution

  • Similar to the answer that Peter Koltai gave, your background handler is isolated from your application's context and so it's not possible to route to screens (which require a context) directly from your handler.

    One possible solution is to implement an Android service using native code that communicates with Flutter via a MethodChannel and on the event that a call is accepted, you can navigate screens.