An Intro to Using Expo Push Notifications

joannat

Joanna

Posted on February 3, 2020

An Intro to Using Expo Push Notifications

I recently implemented push notifications for a native iOS app built on React Native with Expo and a NodeJS/Express server. Expo's Push Notifications API is very handy, but I was initially a bit confused about how to use this tool on my back end. In this blog, I'll run through my solution to this problem, in the hopes that it might help other folks who want to use push notifications in their mobile applications.

1. Get and store your user's push token

Expo's docs are helpful for this, and they give you a boilerplate function you can use on your front end.

To do this, I first created a file in our client directory called registerForPushNotificationsAsync.js, where I put the following, based off the Expo boilerplate:

import { Notifications } from 'expo';
import * as Permissions from 'expo-permissions';

export default async function registerForPushNotificationsAsync() {
  try {
    const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
    // Stop here if the user did not grant permissions
    if (status !== 'granted') {
      return null;
    }
    // Get the token that identifies this device
    const token = await Notifications.getExpoPushTokenAsync();
    return token; 
  }
  catch(err) {
    console.log(err);
  }
}
Enter fullscreen mode Exit fullscreen mode

Permissions.askAync() checks to see if the user has granted permission for notifications on their phone from your app. If the status is not granted, we escape the function. Otherwise, we ask the Expo API for a unique token. The token should look something like this:

ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]
Enter fullscreen mode Exit fullscreen mode

In my SignUp component in the React Native front end, I call registerForPushNotificationsAsync in the below function, googleSignUp, when a user clicks a "sign up" button.

// ...
import registerforPushNotificationsAsync from '../expoPushFunctions/registerForPushNotificationsAsync';
// ...
  const googleSignUp = async () => {
    try {
       // Get user Google auth info and add them to the database .
       // ...
      .then(async () => {
        // call the Expo function we created above
        const expoPushToken = await registerforPushNotificationsAsync();
        return expoPushToken
      })
      // and add the returned token to the user's record in the database
      .then(expoPushToken => {
        axios.patch(`${URL}/users/${user.email}/push`, {
          expoPushToken
        })
      })
      .catch(error => console.log(error));
    } catch(error) {console.log(error)}
  }
// ...
Enter fullscreen mode Exit fullscreen mode

So whenever a user signs up (and has allowed notifications from my app), they receive a unique Expo token, which is stored in their personal record in the database.

2. Send notifications from back end

I want to send the user notifications whenever a band they follow creates a new show.

Build the Expo API call

First, I set up the function that will make the Expo Push Notification API call. I made the file pushNotifications.js with the following function, also based on a boilerplate function from Expo:

const { Expo } = require('expo-server-sdk');
// Create a new Expo client
const expo = new Expo();
const sendNotifications = async (pushTokens, title, body) => {
    try {
        // Create the messages that you want to send to clents
        let messages = [];
        for (let pushToken of pushTokens) {
          // Check that all your push tokens appear to be valid Expo push tokens
          if (!Expo.isExpoPushToken(pushToken)) {
            console.error(`Push token ${pushToken} is not a valid Expo push token`);
            continue;
          }
          // Construct a message
          const message = {
            to: pushToken,
            sound: 'default',
            title,
            body
          }
          messages.push(message)
        }
        // Batching nofications
        let chunks = expo.chunkPushNotifications(messages);
        let tickets = [];
        (async () => {
          for (let chunk of chunks) {
            try {
              let ticketChunk = await expo.sendPushNotificationsAsync(chunk);
              console.log(ticketChunk);
              tickets.push(...ticketChunk);
            } catch (error) {
              console.error(error);
            }
          }
        })();
    }
  }
      catch(err) {
          console.log(err);
      }
}

module.exports = {
    sendNotifications,
    expo
}
Enter fullscreen mode Exit fullscreen mode

This function will be passed a title, body, and array of push tokens. I want to be able to use this function for different types of notifications, which is why I'm going to pass in the title and body of the message dynamically.

The function builds an Expo-compatible message for each user and sends the group of messages out in batches.

Create the route and the querying function

Like I said, every time a musician creates a new show on my app, I want their followers to be notified. So in a createShow function in my database helpers, I added a call to the Expo API through that sendNotifications function.

const createShow = async (req, res) => {
    try {
        let { name, dateTime, venueName, bandName } = req.body;
        // store new show in database
        const show = await Show.create({
           // ...
        })

        // For each band playing the show, send push notifications to followers
        await bandNames.forEach(async (bandName) => {
            // Create push tokens array for band followers
            let pushTokens = [];
            const band = await getRecordByName('band', bandName);

            // Get all followers of a given band
            const sql = `SELECT * FROM users WHERE id IN (
                SELECT id_fan FROM fans_bands WHERE id_band = ?)`;
            const followers = await sequelize.query(sql, {
                replacements: [band.id]
            })
            // Push their tokens to the pushTokens array
            followers.forEach(follower => {
                pushTokens.push(follower.expoPushToken)
            })
            // Construct title and body for message
            const title = `New show from ${band.name}!`;
            const body = 'Open Dive for more info.';
            await sendNotifications(pushTokens, title, body);
        })
        res.sendStatus(201);
    }
    catch (err) {
        console.log(err);
        res.sendStatus(400);
    }
}
Enter fullscreen mode Exit fullscreen mode

I've created an account in the app and followed a band to test this functionality out. With the app in the background on my phone, when I use Postman to create a sample show, I get the following result:

Imgur

And that's it! This is just one example of how you can use Expo's push notifications API, and I hope seeing this solution has helped make that process more clear.

💖 💪 🙅 🚩
joannat
Joanna

Posted on February 3, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

An Intro to Using Expo Push Notifications
reactnative An Intro to Using Expo Push Notifications

February 3, 2020