Using Firebase Cloud functions for Sending Push Notification To React Native App


(Skcript Bot) #1

Months back when I started to use Firebase for my react native project I really felt the relief from all those server related stuff as it gave me a architecture to handle most of my app logic in device itself. In Spite of facing some problems during the setup process and development process which is discussed here I never felt the need of a server for my project.

But there was one day when I really felt too closed within firebase and desperately needed a server. That was the day when I was trying automated emails for Sign In, Signup and other process, sending push notifications to user. During those days for sending push notification with FCM you need to use either the dashboard or a server with the firebase-admin npm package, but I don’t want to manage a separate server running.

Finally, after months firebase’s new cloud functions solves that problem and made me go completely serverless.

What are Cloud Functions?

So, cloud functions are the set of JavaScript functions that you can run directly in google cloud and integrated with your firebase application. It can interactive your database, files, users, and also has the ability to perform other firebase operations like triggering push notification.

The coolest part is you can do more things as you can power it with npm modules. Some of the things are like resizing the image, slack integrations, complex calculations and many more.

Using cloud functions to trigger FCM

When they firebase launched the cloud functions feature the first thing I wanted to try was to automate sending push notifications to the users based on the incoming data and events. As firebase already gives FCM(firebase cloud messaging) support we can make use of it.

Setting up Cloud Functions

For creating cloud functions you need to create a node project in the following structure

All the function code and the node modules will be managed inside the functions folder. The configuration will be defined in firebase.json, there is not much to look into the config for writing a simple function.

In our project we will be using the following node modules.

  • firebase-admin (For listening to changes in db, you can also use firebase module for it, but firebase-admin gives you more control on the data)
  • firebase-functions (For initializing and defining the functions)

Here is the function that I wrote for my database structure. You need to export all the function you want to run on firebase and you can write other functions for performing small tasks but don’t export it.

exports.sendMessageNotification = functions.database.ref('conversations/{conversationID}/messages/{messageID}').onWrite(event => {
  if (event.data.previous.exists()) {
    return;
  }
firebase.database().ref('messages').child(event.params.messageID).once('value').then(function(snap) {
    var messageData = snap.val();
var topic = 'notifications_' + messageData.receiverKey;
    var payload = {
      notification: {
        title: "You got a new Message",
        body: messageData.content,
      }
    };
    
    admin.messaging().sendToTopic(topic, payload)
        .then(function(response) {
          console.log("Successfully sent message:", response);
        })
        .catch(function(error) {
          console.log("Error sending message:", error);
        });
  });
});

As you noticed, here we created a function which will be triggered when there is a new write in the path where the conversationID and messageID are dynamic.

This will be triggered for all the write operation (Enter new or update the data) whereas we need to trigger the function only when there is a new message, so we use to check if the data is old one or new data and return if it’s old.

Later if the data is new I’m finding the message which is stored inside and in order to fetch the data from the corresponding path I take the messageID from the events params like

Once I get the I send a notification to the topic which the user will be subscribed to.

Setting up FCM in ReactNative

ReactNative doesn’t have a native support for FCM so I need to relay on the 3rd party library

You can follow their instruction in setting up the library, it’s pretty straight forward like other libraries for react native while you need to configure your APN keys for ios.

Setting up the JS part

First get the permission for receiving push notification with the following function

FCM.requestPermissions();

Next up is to get the token

FCM.getFCMToken();

Then we need to subscribe to the corresponding user’s notification channel so that he gets only his notification.

FCM.subscribeToTopic('notifications_' + userKey);

Then initialize the notification listener

this.notificationListener = FCM.on(FCMEvent.Notification, async (notif) => {
      if (!notif.local_notification) {
        FCM.presentLocalNotification({
          id: "UNIQ_ID_STRING",
          title: notif.aps.alert.title,
          body: notif.aps.alert.body,
          sound: "default",
          priority: "high",
          click_action: "ACTION",
          icon: "ic_launcher",
          show_in_foreground: true,
        });
      }
    });

Here whenever there is a notification is received by the application it should be sent as a local notification which can be done with the function with the corresponding data for notification.

The possible options you can have for a notification with this library are

FCM.presentLocalNotification({
  id: "UNIQ_ID_STRING",
  title: "My Notification Title",
  body: "My Notification Message",
  sound: "default",
  priority: "high",
  click_action: "ACTION",
  badge: 10,
  number: 10,
  ticker: "My Notification Ticker",
  auto_cancel: true,
  large_icon: "ic_launcher",
  icon: "ic_launcher",
  big_text: "Show when notification is expanded",
  sub_text: "This is a subText",
  color: "red",
  vibrate: 300,
  tag: 'some_tag',
  group: "group",
  my_custom_data:'my_custom_field_value',
  lights: true,
  show_in_foreground: true
});

And when you want to remove the lisenter you can use the following function

this.notificationListener.remove();

Once you set up the library just test it by creating a sample notification from firebase console. And once it works try the node changes and check if the notification works.

Other Possibilities With Firebase Cloud Functions
  • Resizing Images
  • Slack Notification
  • Stripe Integration
  • Automated Emails
  • Heavy operations can be ran

And many more possibilities, so you can extend the features of your app and remove some heavy code which run after a event of data changes from the app and move it to cloud functions. I felt FCM and ReactNative was not tried by anyone so I just posted about it as I worked on it recently. Hope people comes with lot more things like this.


This is a companion discussion topic for the original entry at https://www.skcript.com/svr/using-firebase-cloud-functions/

(Amirhossein Eslami) #2

Hey, I want to do this work with cron jobs! And make a cron for every user to send a notification to them. How can I do this? I know how to make a cron and send notification! But I don’t know how I can make a job for every one user?


(Varun Raj) #3

Hello Amirhossein,

You can have the user Ids in a node along with their registration tokens, you can use that node and loop to get all the user tokens when the cron runs and send the notification all the users.


(Amirhossein Eslami) #4

Thank you @varun. I think about this, But I have a specific end time for any users which I want to notify to them that time is up!
So every user has a unique time, And I want to make a cron job for everyone to check that time every 1hour and send a notification to them if they time is up!
If I do that you say, I should make a cron job and run it every minute for checking all users time and send a notification to them if they have less time. I think I have just this way to do. But if you have advice, Plz tell me. Thank you.


(Varun Raj) #5

In that case, run a cron for every 15 mins and make the user notification triggered only in 15 mins interval. This lets you run a very optimised way.

If you want to run it with a triggered action, make a cloud function listen to a node in db and change the node data when ever you want to run the action.