An Intro to Using Expo Push Notifications
Joanna
Posted on February 3, 2020
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);
}
}
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]
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)}
}
// ...
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
}
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);
}
}
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:
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.
Posted on February 3, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.