Send Push Notifications with Flutter, Firebase Cloud Messaging and Functions

Photo by Sandra Tan on Unsplash

Finally, a topic that is not covered (at least entirely).

Quarantine has been well spent. As an absolute beginner to Flutter and Firebase and everything in between, the past few months has been a personal growth renaissance. Thank you, internet, and everyone around the world who took the time to share their knowledge. And now it is my turn to return the favour.

So is this your problem?

You have come across a scenario, where you need to send push notifications from your Flutter app or web. if the answer is Yes, this is the place you need to be.

My use case was, I have one app with two user roles. Admin users and regular users. Whereas an admin user wants to send a message across all regular users using the mobile app Eg: a new promotion, server maintenance information, etc.

You can achieve a similar end-result through the Firebase Cloud Messaging (FCM) console. But where is the fun in that?

Problems have solutions

Basically (I mean truly in the most basic sense, not the overused filler word), the app (admin role) should talk to FCM and say.

“Hey FCM, could you please send this message across to all the clients using the app”

right?

So, what are the ways we can think of doing just that? I can think of three.

  1. Using the Cloud Messaging Plugin for Flutter
  2. Using FCM Server Protocols
  3. Using a Cloud Function to route the call

Let’s look at each option

1. Cloud Messaging Plugin for Flutter

This is not possible! as it is intended to receive push notifications. Not the other way around.

2. FCM Server Protocols (Cloud Messaging Rest API)

This is a possible path you can take, but you would easily need some additional work that needs to do apart from just sending a Cloud Message, (e.g. query the recipients from a Db). Probably something to sit in a backend server far far away. And you know what they say about having backend code in the client. Don’t do that!

Also keep in mind that you will have to take the pain to write that extra chunk of code to invoke a Rest API, and all the debugging that comes with it.

Although I didn’t try this option, this should work.

3. Using a Cloud Function

And we have a winner!

Firebase Cloud Functions is a powerful backend service which you can write server code without worrying about any of the complexities of managing infrastructure.

You can invoke a Cloud Function from the Flutter app either through HTTP or a database trigger and let the Cloud Function do the work for you. Inside the function use the Firebase Admin SDK and send messages as you wish. It is an elegant solution, see for yourself.

I am using Node.js because it is the default runtime. Seemed like the go-to move. But as it is stated here you can either use Python or Go as well.

Let’s get started, shall we?

I assume you have a basic idea in setting up the environment, writing and deploying a cloud function. If not, refer to this article and come back.

The function we need to write should take in a parameter; it could be an Id, a name or anything else, perform some logic and then send the message using the Admin API.

Here is my example,

exports.sendNotification = functions.https.onCall((data, context) => {const payload = {notification: {title: "The title of the notification",body: data["your_param_sent_from_the_client"], //Or you can set a server value here.},//If you want to send additional data with the message,//which you dont want to show in the notification itself.data: {data_to_send: "msg_from_the_cloud",}};admin.messaging().sendToTopic("AllPushNotifications", payload).then(value => {console.info("function executed succesfully");return { msg: "function executed succesfully" };}).catch(error => {console.info("error in execution");console.log(error);return { msg: "error in execution" };});});

And that is it, deploy the function without any errors.

On the Flutter side of things

For the Admin user

First, we need to trigger the cloud function. In my example, it is the app logged in as admin. This is the Flutter plugin you need.

And below is a way to call the cloud function.

Future<void> sendNotification(String promoId, String promoDesc) async {final results = await CloudFunctions.instance.getHttpsCallable(functionName: 'sendNotification').call({"your_param_sent_from_the_client": param});print(results);}

For the Regular user

Let’s see how to handle incoming cloud messages from the Flutter client, Add this plugin to your project. Add a similar class to PushNotificationsHandler which takes care of initializing and subscribing to push notifications.

Call init( ) from main.dart. Once it is called, the app logged in as regular user is ready to receive push notifications and take actions if necessary.

import 'package:firebase_messaging/firebase_messaging.dart';class PushNotificationsHandler {PushNotificationsHandler._();factory PushNotificationsHandler() => _instance;static final PushNotificationsHandler _instance =PushNotificationsHandler._();final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();bool _initialized = false;Future<void> init() async {if (!_initialized) {// For iOS request permission first._firebaseMessaging.requestNotificationPermissions();//You can subscribed to a topic, if you need to send to all devices//user segmented messages is not supported for the Admin SDK_firebaseMessaging.subscribeToTopic("AllPushNotifications");_firebaseMessaging.configure(
//fires when the app is open and running in the foreground.onMessage: (Map<String, dynamic> message) async {print("onMessage: $message");//do whatever},
//fires if the app is fully terminated.
onLaunch: (Map<String, dynamic> message) async {print("onLaunch: $message");//do whatever},
//fires if the app is closed, but still running in the background.onResume: (Map<String, dynamic> message) async {print("onResume: $message");//do whatever},);// For testing purposes print the Firebase Messaging tokenString token = await _firebaseMessaging.getToken();print("FirebaseMessaging token: $token");
_initialized = true;}}}

So now you should be able to send notifications from a Flutter app (Admin mode) and receive them to another Flutter app (User mode).

I hope all of that was straight forward. But here comes the section I think you will be interested the most.

The Common Pitfalls

https://imgur.com/r/ProgrammerHumor/XOOclJi

The “Why No Notification drama”

When testing the app, you would eagerly send notifications from your app, only to see nothing comes up to the system tray. The answer is probably here. If the app is in the foreground the notification will not be visible in the system tray instead it will only fire onMessageReceived and stay quiet.

You will get the notification on the System tray only if the app is in the background. But that is in Android, I haven’t checked how it works for iOS. Feel free to comment.

“When you have the need for spamming all users”

If you want to send the notification for all users, there is a handy tool in the FCM console where you can do just that. Under the target section, there is a tab called User segment where you can simply select all users who are using your app, just by selecting the app from the drop-down.

So.. if this feature is available, the admin SDK should also support that right? No, sadly it is not. You can’t send notifications to User segments nor to a Firebase User Identifier using the admin SDK.

What do we do then?

We have two options, one is to send notifications via FCM tokens that’s is generated per device. So you will have to collect and probably store all these Ids in a database and retrieve back in the cloud function at the time of sending the notification. This is great when you want to filter out your notifications, but if you want to send a message to all users or a majority of the users for that matter, you can use FCM topics.

Where there is a generic topic that every user is subscribed by default, as the code example shown above. So every time you want to send a message to all, you send the message under that topic. Kinda hacky but I have seen worse.

Conclusion

Flutter and Firebase is the new power couple in mobile development. Both technologies focus on simplicity, quick development cycles and let you worry about only on what really matters.

Hope this helped you to understand a bit more on how to implement push notifications with Flutter and Firebase.

Be the curious kid you always wanted to be.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store