That Guy
That Guy

Reputation: 234

Show FCM notification thoughout the app when the app is open (Flutter)

I'm using FCM to send push notifications to my device right now and it's working perfectly. However when the app is open, I only get the onResume to be executed when I'm in that particular page. I want to display the notification on the top regardless of which page(or class) the user is on. Basically I want the notifications to be displayed globally (Show popup). Any help would be appreciated. Here is the code from the page that displays the notifications.

if (Platform.isIOS) {
     iosSubscription = _fcm.onIosSettingsRegistered.listen((data) {
    _saveDeviceToken();
   });

  _fcm.requestNotificationPermissions(IosNotificationSettings());
} else {
  _saveDeviceToken();
}

_fcm.configure(
  onMessage: (Map<String, dynamic> message) async {
    print("onMessage: $message");
    var temp = message['notification'];
    setState(() {
      title.add(temp['title']);
      body.add(temp['body']);
    });
   
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        content: ListTile(
          title: Text(message['notification']['title']),
          subtitle: Text(message['notification']['body']),
        ),
        actions: <Widget>[
          FlatButton(
            color: const Color(0xFF650572),
            child: Text('Ok'),
            onPressed: () => Navigator.of(context).pop(),
          ),
        ],
      ),
    );
  },
  onLaunch: (Map<String, dynamic> message) async {
    print("onLaunch: $message");
    Navigator.push(
        context, MaterialPageRoute(builder: (context) => MessageHandler()));
    // TODO optional
  },
  onResume: (Map<String, dynamic> message) async {
    print("onResume: $message");
    Navigator.push(context,
        MaterialPageRoute(builder: (context) => MessageHandler()));
    // TODO optional
  },
);

}

Upvotes: 5

Views: 2244

Answers (1)

Muhammad Mohsin Ajmal
Muhammad Mohsin Ajmal

Reputation: 147

Wrap your MaterialApp in a wrapper class ... lets call that FCMWrapper.

class FCMWrapper extends StatefulWidget {
  final Widget child;

  const FCMWrapper({Key key, this.child}) : super(key: key);

  @override
  _FCMWrapperState createState() => _FCMWrapperState();
}

class _FCMWrapperState extends State<FCMWrapper> {
  @override
  Widget build(BuildContext context) {
    return Consumer<YourObservable>(
      builder: (context, yourObservable, _) {
        if (yourObservable != null && yourObservable.isNotEmpty) {
          Future(
            () => navigatorKey.currentState.push(
              PushNotificationRoute(
                  child: YourViewOnNotification(),
              )),
            ),
          );
        }
        return widget.child;
      },
    );
  }
}

I have stored my data in an observable from a separate class. So when I receive a notification I update my observable. Since we are consuming on that observable the PushNotificationRoute would be called.

PushNotificationRoute is simply a class which extends ModalRoute.

class PushNotificationRoute extends ModalRoute {
  final Widget child;

  PushNotificationRoute({this.child});

  ... //Override other methods to your requirement

  //This is important
  @override
  Widget buildPage(BuildContext context, Animation<double> animation,
      Animation<double> secondaryAnimation) {
    return SafeArea(
      child: Builder(builder: (BuildContext context) {
        return child;
      }),
    );
  }

  ...
  @override
  Duration get transitionDuration => Duration(milliseconds: 200);
}

Now in main.dart declare a global key like

var navigatorKey = GlobalKey<NavigatorState>();

and wrap your MaterialApp like

...

FCMWrapper(
          child: MaterialApp(
            navigatorKey: navigatorKey,
            title: 'Your App',

...

So now every time a notification comes in your observable should update and push a modal route which would be shown over anywhere in the app.

Upvotes: 2

Related Questions