top of page

[Flutter/dart] When Firebase Messaging notification is tapped with the app is in the background


Overview

In many cases, you'll send a message with Firebase Messaging and take some action when the notification is tapped (eg to go to a specific page).

It's easy if the app is in the foreground state (that is, the app is open) when the notification is tapped, but if the app is in the background state, some ingenuity is required.



Method

Is FirebaseMessaging.onBackgroundMessage () useless?


Firebase Messaging provides a method called onBackgroundMessage (). You might think that you can pass the method you want to execute when tapping the notification to this argument (hereinafter referred to as onBackGround)? However, there are the following problems.reference


  1. onBackgroundMessage () runs when the notification comes, not when a user taps the notification. In other words, when onBackGround () is executed, the app is not open yet, so you cannot do something like screen transition.

  2. onBackGround () needs to be a top-level function. That is, you cannot perform any action based on the state of a particular instance.

  3. onBackGround () is executed by another isolate. Since dart doesn't share memory between isolates, you can't directly rewrite the main isolate variable.

Solution


Take the following actions.

  1. Add the variable "resumeState" to the top level that represents the state when the application is restarted. Set the value to 0 at initialization. Set resumeState to 1 in onBackGround () (*).

  2. Determine the value of resumeState when the app is restarted. If 1, the desired process is executed.

  3. In the (*) part, change the value of the variable resumeState of another isolate using port.


This will solve all of the above issues.

We will look at the details below.



1 Add the variable "resumeState" to the top level that represents the state when the application is restarted


For dart, variables can be defined not only in the class but also at the top level.

void main() async{
  runApp(MyApp());
}

int resumeState=NOMAL_RESUME;
const NOMAL_RESUME=0;
const ON_NOTIFICATION_TAP=1;


2 Determine the value of resumeState when the app is restarted. If 1, the desired process is executed.


The procedure to perform some action when restarting the application in dart is as follows.


  1. Implement WidgetsBindingObserver with any widget (or state)

  2. Override didChangeAppLifecycleState().This method is called when the life cycle of the app changes.

  3. Since the argument "state" is AppLifecycleState.resumed when the application is restarted , the desired process is executed in this case (corresponding to onResume () on Android).

class basePageState extends State<basePage> with WidgetsBindingObserver{

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state==AppLifecycleState.resumed){
      if (resumeState==ON_NOTIFICATION_TAP) {
        //Write the desired process here!
        resumeState=NOMAL_RESUME;
      }
    }
  }
}


3 change the value of the variable resumeState of another isolate using port


As mentioned above, since onBackGround is executed in another isolate, resumeState defined in main isolate cannot be directly rewritten. Use port to exchange information between isolates. (reference)


Specifically, do as follows.

  1. Send an appropriate string from SendPort indicating that onBackGround () was called.

  2. If the above string is received by ReceivePort, change resumeState to 1.


static const String BG_PORT_NAME="bg_port";
static const String BG_MESSAGE="bg_message";

Future<void> onBackGround(RemoteMessage message)async{
  final port=IsolateNameServer.lookupPortByName(BG_PORT_NAME);
  port.send(BG_MESSAGE);
}
void setBackGroundHandling(){
  ReceivePort backgroundMessagePort=ReceivePort();
  IsolateNameServer.registerPortWithName(
    backgroundMessagePort.sendPort, BG_PORT_NAME);
    
  backgroundMessagePort.listen((message) {
    if (message.toString()==BG_MESSAGE){
      resumeState=ON_NOTIFICATION_TAP;
    }
  });
}
void main() async{
  //・・・
  FirebaseMessaging.onBackgroundMessage(onBackGround);
  setBackGroundHandling();
  runApp(MyApp());
}

With the above support, you will be able to execute the operation when tapping the notification even when the application is in the background state.




Recent Posts

See All

[Flutter/Dart] Format string with TextField

What want to do I want to create an input form using TextField. For example, if the input content is a monetary amount, I would like to display it in 3-digit delimiters with a ¥ prefix. Rather than ha

Let's do our best with our partner:​ ChatReminder

iphone6.5p2.png

It is an application that achieves goals in a chat format with partners.

google-play-badge.png
Download_on_the_App_Store_Badge_JP_RGB_blk_100317.png

Let's do our best with our partner:​ ChatReminder

納品:iPhone6.5①.png

It is an application that achieves goals in a chat format with partners.

google-play-badge.png
Download_on_the_App_Store_Badge_JP_RGB_blk_100317.png

Theme diary: Decide the theme and record for each genre

It is a diary application that allows you to post and record with themes and sub-themes for each genre.

google-play-badge.png
Download_on_the_App_Store_Badge_JP_RGB_blk_100317.png
bottom of page