Welcome to a comprehensive master series on implementing push notifications across web and mobile platforms! In this journey, we'll explore the intricacies of push notifications, from basic concepts to advanced implementations. Whether you're a seasoned developer or just starting out, this series will equip you with the knowledge and skills to integrate powerful push notification systems into your applications.
What We'll Cover
Throughout this series, we'll dive into:
- Web Push Notifications with React, Vite, and Firebase Cloud Messaging (FCM).
- Building a NestJS Server for remote control Web Push Notifications.
- Mobile Push Notifications with Expo and FCM
- Setting up a Node.js Server for Remote Control Mobile Push Notifications
By the end of this series, you'll have a robust understanding of push notification systems and the ability to implement them across different platforms.
Table of Contents
Introduction
Push notifications have become an integral part of modern web applications, allowing developers to engage users with timely updates even when they're not actively using the app. In this article, we'll walk through the process of implementing web push notifications using React, Vite, and Firebase Cloud Messaging (FCM).
Prerequisites
Before we begin, make sure you have the following installed:
- Node.js (v14 or later)
- npm (v6 or later)
- A code editor of your choice (e.g VSCode)
Setting Up the Project
Let's start by creating a new React project using Vite:
npm create vite@latest web-push-notification -- --template react
cd web-push-notification
npm install
This will create a new React project using Vite as the build tool. Now, let's install the necessary dependencies for FCM:
npm install firebase
What is Firebase Cloud Messaging (FCM)?
Firebase Cloud Messaging (FCM) is a cross-platform messaging solution that lets you reliably send messages at no cost. Here's what you need to know:
Purpose: FCM allows you to send notifications and data messages to users across platforms β Android, iOS, and web applications.
-
Key Features:
- Cross-Platform: Works seamlessly across mobile and web.
- Reliability: Delivers messages in real-time with high reliability.
- Scalability: Handles messaging for millions of devices without additional setup.
- Flexibility: Supports various message types including notification messages and data messages.
-
How it Works:
- Your app registers with FCM and receives a unique token.
- This token is sent to your server.
- Your server uses this token to send messages to the specific device via FCM.
-
Benefits:
- Free to use
- Easy integration with other Firebase services
- Supports targeted messaging and analytics
By leveraging FCM, we can implement robust push notifications in our React applications with minimal setup and maximum efficiency.
Configuring Firebase
- Go to the Firebase Console and create a new project (or use an existing one).
- Navigate to Project Settings > General and scroll down to "Your apps".
- Click on the web icon (</>) to add a new web app to your project.
- Follow the prompts to register your app. You'll receive a configuration object that looks like this:
- Create a new file called
config/firebase.js
in yoursrc
directory and paste the following code.
// src/config/firebase.js
import { initializeApp } from "firebase/app";
import { getMessaging, getToken, onMessage } from "firebase/messaging";
export const firebaseConfig = {
apiKey: import.meta.env.VITE_API_KEY,
authDomain: import.meta.env.VITE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_PROJECT_ID,
storageBucket: import.meta.env.VITE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_APP_ID,
};
export const FIREBASE_VAPID_KEY = import.meta.env.VITE_VAPID_KEY;
const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);
export const requestForToken = () => {
return getToken(messaging, { vapidKey: FIREBASE_VAPID_KEY })
.then((currentToken) => {
if (currentToken) {
return currentToken;
} else {
alert(
"No registration token available. Request permission to generate one."
);
return null;
}
})
.catch((err) => {
alert("An error occurred while retrieving token - " + err);
return null;
});
};
onMessage(messaging, ({ notification }) => {
new Notification(notification.title, {
body: notification.body,
icon: notification.icon,
});
});
Let's break this down:
Imports: We import necessary functions from Firebase, including
initializeApp
for initializing the Firebase app, andgetMessaging
,getToken
, andonMessage
for handling push notifications.Configuration: The
firebaseConfig
object contains your Firebase project's configuration. Here, we're using Vite's environment variables (prefixed withimport.meta.env.VITE_
) to securely store these values. This approach keeps your sensitive data out of your codebase.VAPID Key: The Voluntary Application Server Identification (VAPID) key is also stored as an environment variable. This key is used for identifying your server to push services. You can generate yours on your firebase project page by navigating to the
Cloud Message
tab under theProject Setting Page
, click on theGenerate key pair
button, then click on the menu by the right hand side of the newly generated string and click onShow private key
and then copy yourVAPID key
.Firebase Initialization: We initialize the Firebase app with
initializeApp(firebaseConfig)
and get the messaging instance withgetMessaging(app)
.Token Request Function: The
requestForToken
function is crucial for push notifications. It does the following:
- Calls
getToken
with the messaging instance and VAPID key. - If successful, it returns the token, which you'd typically send to your server.
- If no token is available, it alerts the user and returns null.
- If an error occurs, it logs the error and returns null.
-
Message Handling: The
onMessage
function sets up a listener for incoming messages when the app is in the foreground (that is, you are currently active on the page/website). When a message is received, it creates a newNotification
with the received title, body, and icon.
This setup allows your app to request permission for notifications, receive a token for the device (which you'd send to your server to target this device for notifications), and handle incoming messages when the app is open.
Initializing Firebase in Your App
Now, let's initialize Firebase in our app. Now, paste the code below in your App.jsx
in your src
directory:
// src/App.jsx
import React, { useEffect, useState } from "react";
import { requestForToken } from "../config/firebase";
function App() {
const [token, setToken] = useState("");
useEffect(() => {
const getToken = async () => {
const permission = await Notification.requestPermission();
if (permission === "granted") {
const token = await requestForToken();
if (token) {
setToken(token);
}
}
};
getToken();
}, []);
return (
<div className="App">
<h1>Push Notification with React & FCM</h1>
<p>
Device Token π <span style={{ fontSize: "11px" }}> {token} </span>
</p>
{token && <h2>Notification permission enabled ππ»</h2>}
{!token && <h2>Need notification permission βοΈ </h2>}
</div>
);
}
export default App;
Let's break down this component
-
State Management:
We use the
useState
hook to manage the device token state:
const [token, setToken] = useState("");
-
Effect Hook:
We use the
useEffect
hook to request notification permission and fetch the device token when the component mounts:
useEffect(() => {
const getToken = async () => {
// ... token request logic
};
getToken();
}, []);
- Permission Request: Inside the effect, we first request notification permission from the user:
const permission = await Notification.requestPermission();
-
Token Retrieval:
If permission is granted, we call our
requestForToken
function (from our Firebase configuration) to get the device token:
if (permission === "granted") {
const token = await requestForToken();
if (token) {
setToken(token);
}
}
-
Render Logic:
The component renders different content based on whether a token has been received:
- It always displays the heading and the device token (if available).
- If a token is present, it shows a success message.
- If no token is present, it shows a message indicating that notification permission is needed.
This component provides a simple interface for requesting push notification permissions and displaying the status to the user. The device token, once received, could be sent to your backend server for storing and later use in sending targeted push notifications.
Handling Background Notifications
An essential aspect of push notifications is the ability to receive and handle them when your web app is not actively open in the browser. This is where the Firebase service worker comes into play. Let's look at how to set this up:
Setting up the Firebase Service Worker
Create a file named firebase-messaging-sw.js
in your public
directory with the following content:
// src/public/firebase-messaging-sw.js
importScripts(
"https://www.gstatic.com/firebasejs/9.0.0/firebase-app-compat.js"
);
importScripts(
"https://www.gstatic.com/firebasejs/9.0.0/firebase-messaging-compat.js"
);
fetch("/firebase-config.json")
.then((response) => {
return response.json();
})
.then((jsContent) => {
const config = eval(jsContent);
firebase.initializeApp(config.firebaseConfig);
firebase.messaging();
})
.catch((error) => {
console.error("Error initializing Firebase in service worker:", error);
});
This script does the following:
- Imports the necessary Firebase scripts using CDN (direct
import
is not allowed in service worker file). - Fetches the Firebase configuration from a JSON file
firebase-config.json
. - Initializes Firebase with the fetched configuration.
- Sets up Firebase Cloud Messaging.
Configuring Firebase Service Worker
Create a file named firebase-config.json
in your public
directory:
// src/public/firebase-config.json
{
"firebaseConfig": {
"apiKey": "API_KEY",
"authDomain": "AUTH_DOMAIN",
"projectId": "PROJECT_ID",
"storageBucket": "STORAGE_BUCKET",
"messagingSenderId": "MESSAGING_SENDER_ID",
"appId": "APP_ID",
"vapidKey": "VAPID_KEY"
}
}
This file contains your Firebase configuration details.
Important Security Note π: Make sure to add firebase-config.json
to your .gitignore
file as it contains sensitive information. You should never commit this file to your version control system.
How It Works
- When a push notification is received and your web app is not active, the service worker intercepts the notification.
- The service worker uses the Firebase configuration to properly handle the notification.
- It then display a notification to the user using the user's browser notification notification API.
By setting up your service worker this way, you ensure that your web app can receive and handle push notifications even when it's not actively running in the browser. This significantly enhances the user experience and the effectiveness of your push notification strategy.
Testing Push Notifications
In preparing for this article, I created a Nest Js server to send push notification from the server using Firebase Cloud Messaging (FCM). To test your push notifications, follow the steps below ‡οΈ:
- Run your app with
npm run dev
- Open the app in a browser
http://localhost:5173/
and accept the notification permission prompt. As soon as you grant the notification permission, an fcm device token will be generated and displayed on the screen for you to copy. - Go to
Push Notification Server APIs Doc
, and fill in the body of the API.
Conclusion
Congratulations! You've successfully set up web push notifications using React, Vite, and Firebase Cloud Messaging. This is just the beginning of our journey into the world of push notifications.
In the next article, we'll dive into building a NestJS server to handle sending push notifications, giving you more control over when and how notifications are sent.
Stay tuned for more in this series on mastering push notifications across web and mobile platforms!
Stay Updated and Connected
To ensure you don't miss any part of this series and to connect with me for more in-depth discussions on Software Development (Web, Server, Mobile or Scraping / Automation), push notifications, and other exciting tech topics, follow me on:
Your engagement and feedback drive this series forward. I'm excited to continue this journey with you and help you master the art of push notifications across web and mobile platforms.
Don't hesitate to reach out with questions, suggestions, or your own experiences with push notifications.
You can find below the working source code for this article.
Source Code π.
Stay tuned and happy coding π¨βπ»π
Top comments (0)