Firebase Web Codelab
1. Overview
In this codelab, you'll learn how to use the Firebase platform to easily create Web applications and you will implement and deploy a chat client using Firebase.
What you'll learn
- Sync data using the Firebase Realtime Database and Cloud Storage.
- Authenticate your users using Firebase Auth.
- Deploy your web app on Firebase static hosting.
- Send notifications with Firebase Cloud Messaging.
What you'll need
- The IDE/text editor of your choice such as WebStorm, Atom or Sublime.
- npm which typically comes with NodeJS.
- A console.
- A browser such as Chrome.
- The sample code. See next step for this.
2. Get the sample code
Clone the GitHub repository from the command line:
git clone https://github.com/firebase/friendlychat-web
git clone https://github.com/firebase/friendlychat-web
Import the starter app
Using your IDE open or import the 📁 web-start
directory from the sample code directory. This directory contains the starting code for the codelab which consists of fully functional Chat Web App.
web-start
directory from the sample code directory. This directory contains the starting code for the codelab which consists of fully functional Chat Web App.3. Create a Firebase project and Set up your app
Create project
Enable Google Auth
To let users sign-in on the web app we'll use Google auth which needs to be enabled.
In the Firebase Console open the DEVELOP section > Authentication > SIGN IN METHOD tab (click here to go there) you need to enable the Google Sign-in Provider and click SAVE. This will allow users to sign-in the Web app with their Google accounts
Enable Cloud Storage
The app uses Cloud Storage to upload pics. To enable Cloud Storage on your Firebase project visit the Storage section and click the Get Started button. Then Click Got It when you receive the disclaimer about the security rules.
4. Install the Firebase Command Line Interface
The Firebase Command Line Interface (CLI) will allow you to serve your web apps locally and deploy your web app to Firebase hosting.
To install the CLI run the following npm command:
npm -g install firebase-tools
To verify that the CLI has been installed correctly open a console and run:
firebase --version
Make sure the Firebase version is above 3.3.0
Authorize the Firebase CLI by running:
firebase login
Make sure you are in the web-start
directory then set up the Firebase CLI to use your Firebase Project:
firebase use --add
Then select your Project ID and follow the instructions.
npm -g install firebase-tools
firebase --version
firebase login
web-start
directory then set up the Firebase CLI to use your Firebase Project:firebase use --add
5. Run the starter app
Now that you have imported and configured your project you are ready to run the app for the first time. Open a console at the web-start
folder and run firebase serve
:
firebase serve
This command should display this in the console:
Listening at http://localhost:5000
The web app should now be served from http://localhost:5000 open it. You should see your app's not (yet!) functioning UI:
The app cannot do anything right now but with your help it will soon! We only have laid out the UI for you so far. Let's now build a realtime chat!
web-start
folder and run firebase serve
:firebase serve
Listening at http://localhost:5000
6. User Sign-in
Initialize Firebase Auth
The Firebase SDK should be ready to use since it is imported and initialized it in the index.html
file (we've done that for you). In this application we'll be using the Firebase Realtime Database, Cloud Storage for Firebase and Firebase Authentication. Modify the FriendlyChat.prototype.initFirebase
function in the scripts/main.js
file so that it sets some shortcuts to the Firebase SDK features and initiates auth:
index.html
file (we've done that for you). In this application we'll be using the Firebase Realtime Database, Cloud Storage for Firebase and Firebase Authentication. Modify the FriendlyChat.prototype.initFirebase
function in the scripts/main.js
file so that it sets some shortcuts to the Firebase SDK features and initiates auth:main.js
// Sets up shortcuts to Firebase features and initiate firebase auth.
FriendlyChat.prototype.initFirebase = function() {
// Shortcuts to Firebase SDK features.
this.auth = firebase.auth();
this.database = firebase.database();
this.storage = firebase.storage();
// Initiates Firebase auth and listen to auth state changes.
this.auth.onAuthStateChanged(this.onAuthStateChanged.bind(this));
};
// Sets up shortcuts to Firebase features and initiate firebase auth.
FriendlyChat.prototype.initFirebase = function() {
// Shortcuts to Firebase SDK features.
this.auth = firebase.auth();
this.database = firebase.database();
this.storage = firebase.storage();
// Initiates Firebase auth and listen to auth state changes.
this.auth.onAuthStateChanged(this.onAuthStateChanged.bind(this));
};
Authorize Firebase with Google
When the user clicks the Sign in with Google button the FriendlyChat.prototype.signIn
function gets triggered (we already set that up for you!). At this point we want to authorize Firebase using Google as the Identity Provider. We'll sign in using a popup (Several other methods are available). Change the FriendlyChat.prototype.signIn
function with:
FriendlyChat.prototype.signIn
function gets triggered (we already set that up for you!). At this point we want to authorize Firebase using Google as the Identity Provider. We'll sign in using a popup (Several other methods are available). Change the FriendlyChat.prototype.signIn
function with:main.js
// Signs-in Friendly Chat.
FriendlyChat.prototype.signIn = function() {
// Sign in Firebase using popup auth and Google as the identity provider.
var provider = new firebase.auth.GoogleAuthProvider();
this.auth.signInWithPopup(provider);
};
The FriendlyChat.prototype.signOut
function is triggered when the user clicks the Sign out button. Add the following line to make sure we sign out of Firebase:
// Signs-in Friendly Chat.
FriendlyChat.prototype.signIn = function() {
// Sign in Firebase using popup auth and Google as the identity provider.
var provider = new firebase.auth.GoogleAuthProvider();
this.auth.signInWithPopup(provider);
};
FriendlyChat.prototype.signOut
function is triggered when the user clicks the Sign out button. Add the following line to make sure we sign out of Firebase:main.js
// Signs-out of Friendly Chat.
FriendlyChat.prototype.signOut = function() {
// Sign out of Firebase.
this.auth.signOut();
};
We want to display the signed-in user's profile pic and name in the top bar. Earlier we've set up the FriendlyChat.prototype.onAuthStateChanged
function to trigger when the auth state changes. This function gets passed a Firebase User
object when triggered. Change the two lines with a TODO
to read the user's profile pic and name:
// Signs-out of Friendly Chat.
FriendlyChat.prototype.signOut = function() {
// Sign out of Firebase.
this.auth.signOut();
};
FriendlyChat.prototype.onAuthStateChanged
function to trigger when the auth state changes. This function gets passed a Firebase User
object when triggered. Change the two lines with a TODO
to read the user's profile pic and name:main.js
// Triggers when the auth state change for instance when the user signs-in or signs-out.
FriendlyChat.prototype.onAuthStateChanged = function(user) {
if (user) { // User is signed in!
// Get profile pic and user's name from the Firebase user object.
var profilePicUrl = user.photoURL; // Only change these two lines!
var userName = user.displayName; // Only change these two lines!
...
We display an error message if the users tries to send messages when the user is not signed-in. To detect if the user is actually signed-in add these few lines to the top of the FriendlyChat.prototype.checkSignedInWithMessage
function where the TODO
is located:
// Triggers when the auth state change for instance when the user signs-in or signs-out.
FriendlyChat.prototype.onAuthStateChanged = function(user) {
if (user) { // User is signed in!
// Get profile pic and user's name from the Firebase user object.
var profilePicUrl = user.photoURL; // Only change these two lines!
var userName = user.displayName; // Only change these two lines!
...
FriendlyChat.prototype.checkSignedInWithMessage
function where the TODO
is located:main.js
// Returns true if user is signed-in. Otherwise false and displays a message.
FriendlyChat.prototype.checkSignedInWithMessage = function() {
// Return true if the user is signed in Firebase
if (this.auth.currentUser) {
return true;
}
...
// Returns true if user is signed-in. Otherwise false and displays a message.
FriendlyChat.prototype.checkSignedInWithMessage = function() {
// Return true if the user is signed in Firebase
if (this.auth.currentUser) {
return true;
}
...
Test Signing-in to the app
- Reload your app if it is still being served or run
firebase serve
on the command line to start serving the app from http://localhost:5000 and open it in your browser.
- Sign-In using the Sign In button
- After Signing in the profile pic and name of the user should be displayed:
firebase serve
on the command line to start serving the app from http://localhost:5000 and open it in your browser.7. Read messages
Import Messages
In your project in Firebase console visit the Database section on the left navigation bar. On this page you will see the data that is stored in your Firebase Realtime Database.
In the overflow menu of the Database select Import JSON. Browse to the initial_messages.json
file at the root of the repository, select it then click the Import button. This will replace any data currently in your database.
You could also edit the database manually, using the green + and red x to add and remove items manually or use the Firebase CLI with this command:
firebase database:set / ../initial_messages.json
After importing the JSON file your database should contain the following elements:
friendlychat-12345/
messages/
-K2ib4H77rj0LYewF7dP/
text: "Hello"
name: "anonymous"
-K2ib5JHRbbL0NrztUfO/
text: "How are you"
name: "anonymous"
-K2ib62mjHh34CAUbide/
text: "I am fine"
name: "anonymous"
These are a few sample chat messages to get us started with reading from the Database.
initial_messages.json
file at the root of the repository, select it then click the Import button. This will replace any data currently in your database.firebase database:set / ../initial_messages.json
friendlychat-12345/
messages/
-K2ib4H77rj0LYewF7dP/
text: "Hello"
name: "anonymous"
-K2ib5JHRbbL0NrztUfO/
text: "How are you"
name: "anonymous"
-K2ib62mjHh34CAUbide/
text: "I am fine"
name: "anonymous"
Synchronize Messages
To synchronize messages on the app we'll need to add listeners that triggers when changes are made to the data and then create a UI element that show new messages.
Add code that listens to newly added messages to the app's UI. To do this modify the FriendlyChat.prototype.loadMessages
function. This is where we'll register the listeners that listens to changes made to the data. We'll only display the last 12 messages of the chat to avoid displaying a very long history on load.
FriendlyChat.prototype.loadMessages
function. This is where we'll register the listeners that listens to changes made to the data. We'll only display the last 12 messages of the chat to avoid displaying a very long history on load.main.js
// Loads chat messages history and listens for upcoming ones.
FriendlyChat.prototype.loadMessages = function() {
// Reference to the /messages/ database path.
this.messagesRef = this.database.ref('messages');
// Make sure we remove all previous listeners.
this.messagesRef.off();
// Loads the last 12 messages and listen for new ones.
var setMessage = function(data) {
var val = data.val();
this.displayMessage(data.key, val.name, val.text, val.photoUrl, val.imageUrl);
}.bind(this);
this.messagesRef.limitToLast(12).on('child_added', setMessage);
this.messagesRef.limitToLast(12).on('child_changed', setMessage);
};
// Loads chat messages history and listens for upcoming ones.
FriendlyChat.prototype.loadMessages = function() {
// Reference to the /messages/ database path.
this.messagesRef = this.database.ref('messages');
// Make sure we remove all previous listeners.
this.messagesRef.off();
// Loads the last 12 messages and listen for new ones.
var setMessage = function(data) {
var val = data.val();
this.displayMessage(data.key, val.name, val.text, val.photoUrl, val.imageUrl);
}.bind(this);
this.messagesRef.limitToLast(12).on('child_added', setMessage);
this.messagesRef.limitToLast(12).on('child_changed', setMessage);
};
Test Message Sync
- Reload your app if it is still being served or run
firebase serve
on the command line to start serving the app from http://localhost:5000 and open it in your browser.
- The sample messages we imported earlier into the database should be displayed in the Friendly-Chat UI (see below). You can also manually add new messages directly from the Database section of the Firebase console. Congratulations, you are reading real-time database entries in your app!
- Reload your app if it is still being served or run
firebase serve
on the command line to start serving the app from http://localhost:5000 and open it in your browser. - The sample messages we imported earlier into the database should be displayed in the Friendly-Chat UI (see below). You can also manually add new messages directly from the Database section of the Firebase console. Congratulations, you are reading real-time database entries in your app!
8. Send Messages
Implement Message Sending
In this section you will add the ability for users to send messages. The code snippet below is triggered upon clicks on the SEND button and pushes a message object with the contents of the message field to the Firebase database. The push()
method adds an automatically generated key to the pushed object's path. These keys are sequential which ensures that the new messages will be added to the end of the list. Update the FriendlyChat.prototype.saveMessage
function with:
push()
method adds an automatically generated key to the pushed object's path. These keys are sequential which ensures that the new messages will be added to the end of the list. Update the FriendlyChat.prototype.saveMessage
function with:main.js
// Saves a new message on the Firebase DB.
FriendlyChat.prototype.saveMessage = function(e) {
e.preventDefault();
// Check that the user entered a message and is signed in.
if (this.messageInput.value && this.checkSignedInWithMessage()) {
var currentUser = this.auth.currentUser;
// Add a new message entry to the Firebase Database.
this.messagesRef.push({
name: currentUser.displayName,
text: this.messageInput.value,
photoUrl: currentUser.photoURL || '/images/profile_placeholder.png'
}).then(function() {
// Clear message text field and SEND button state.
FriendlyChat.resetMaterialTextfield(this.messageInput);
this.toggleButton();
}.bind(this)).catch(function(error) {
console.error('Error writing new message to Firebase Database', error);
});
}
};
// Saves a new message on the Firebase DB.
FriendlyChat.prototype.saveMessage = function(e) {
e.preventDefault();
// Check that the user entered a message and is signed in.
if (this.messageInput.value && this.checkSignedInWithMessage()) {
var currentUser = this.auth.currentUser;
// Add a new message entry to the Firebase Database.
this.messagesRef.push({
name: currentUser.displayName,
text: this.messageInput.value,
photoUrl: currentUser.photoURL || '/images/profile_placeholder.png'
}).then(function() {
// Clear message text field and SEND button state.
FriendlyChat.resetMaterialTextfield(this.messageInput);
this.toggleButton();
}.bind(this)).catch(function(error) {
console.error('Error writing new message to Firebase Database', error);
});
}
};
Test Sending Messages
- Reload your app if it is still being served or run
firebase serve
on the command line to start serving the app from http://localhost:5000 and open it in your browser.
- After signing-in, enter a message and hit the send button, the new message should be visible in the app UI and in the Firebase console with your user photo and name:
- Reload your app if it is still being served or run
firebase serve
on the command line to start serving the app from http://localhost:5000 and open it in your browser. - After signing-in, enter a message and hit the send button, the new message should be visible in the app UI and in the Firebase console with your user photo and name:
9. Send Images
We'll now add a feature that shares images by uploading them to Cloud Storage. Cloud Storage for Firebase is a file/blob storage service.
Save images to Cloud Storage
We have already added for you a button that triggers a file picker dialog. After selecting a file the FriendlyChat.prototype.saveImageMessage
function is triggered and you can get a reference to the selected file. Now we'll add code that:
- Creates a "placeholder" chat message with a temporary loading image into the chat feed.
- Upload the file to Cloud Storage to the path:
/<uid>/<postId>/<file_name>
- Update the chat message with the newly uploaded file's Cloud Storage URI in lieu of the temporary loading image.
Add the following at the bottom of the FriendlyChat.prototype.saveImageMessage
function where the TODO
is located:
FriendlyChat.prototype.saveImageMessage
function is triggered and you can get a reference to the selected file. Now we'll add code that:/<uid>/<postId>/<file_name>
FriendlyChat.prototype.saveImageMessage
function where the TODO
is located:main.js
// Saves the a new message containing an image URI in Firebase.
// This first saves the image in Cloud Storage.
FriendlyChat.prototype.saveImageMessage = function(event) {
...
// Check if the user is signed-in
if (this.checkSignedInWithMessage()) {
// We add a message with a loading icon that will get updated with the shared image.
var currentUser = this.auth.currentUser;
this.messagesRef.push({
name: currentUser.displayName,
imageUrl: FriendlyChat.LOADING_IMAGE_URL,
photoUrl: currentUser.photoURL || '/images/profile_placeholder.png'
}).then(function(data) {
// Upload the image to Cloud Storage.
var filePath = currentUser.uid + '/' + data.key + '/' + file.name;
return this.storage.ref(filePath).put(file).then(function(snapshot) {
// Get the file's Storage URI and update the chat message placeholder.
var fullPath = snapshot.metadata.fullPath;
return data.update({imageUrl: this.storage.ref(fullPath).toString()});
}.bind(this));
}.bind(this)).catch(function(error) {
console.error('There was an error uploading a file to Cloud Storage:', error);
});
}
};
// Saves the a new message containing an image URI in Firebase.
// This first saves the image in Cloud Storage.
FriendlyChat.prototype.saveImageMessage = function(event) {
...
// Check if the user is signed-in
if (this.checkSignedInWithMessage()) {
// We add a message with a loading icon that will get updated with the shared image.
var currentUser = this.auth.currentUser;
this.messagesRef.push({
name: currentUser.displayName,
imageUrl: FriendlyChat.LOADING_IMAGE_URL,
photoUrl: currentUser.photoURL || '/images/profile_placeholder.png'
}).then(function(data) {
// Upload the image to Cloud Storage.
var filePath = currentUser.uid + '/' + data.key + '/' + file.name;
return this.storage.ref(filePath).put(file).then(function(snapshot) {
// Get the file's Storage URI and update the chat message placeholder.
var fullPath = snapshot.metadata.fullPath;
return data.update({imageUrl: this.storage.ref(fullPath).toString()});
}.bind(this));
}.bind(this)).catch(function(error) {
console.error('There was an error uploading a file to Cloud Storage:', error);
});
}
};
Display images from Cloud Storage
In the chat messages we saved the Cloud Storage reference of the images. These are of the form gs://<bucket>/<uid>/<postId>/<file_name>
. To display these images we need to query Cloud Storage for a URL.
To do this replace the FriendlyChat.prototype.setImageUrl
function content with:
gs://<bucket>/<uid>/<postId>/<file_name>
. To display these images we need to query Cloud Storage for a URL.FriendlyChat.prototype.setImageUrl
function content with:main.js
// Sets the URL of the given img element with the URL of the image stored in Cloud Storage.
FriendlyChat.prototype.setImageUrl = function(imageUri, imgElement) {
// If the image is a Cloud Storage URI we fetch the URL.
if (imageUri.startsWith('gs://')) {
imgElement.src = FriendlyChat.LOADING_IMAGE_URL; // Display a loading image first.
this.storage.refFromURL(imageUri).getMetadata().then(function(metadata) {
imgElement.src = metadata.downloadURLs[0];
});
} else {
imgElement.src = imageUri;
}
};
// Sets the URL of the given img element with the URL of the image stored in Cloud Storage.
FriendlyChat.prototype.setImageUrl = function(imageUri, imgElement) {
// If the image is a Cloud Storage URI we fetch the URL.
if (imageUri.startsWith('gs://')) {
imgElement.src = FriendlyChat.LOADING_IMAGE_URL; // Display a loading image first.
this.storage.refFromURL(imageUri).getMetadata().then(function(metadata) {
imgElement.src = metadata.downloadURLs[0];
});
} else {
imgElement.src = imageUri;
}
};
Test Sending images
- Reload your app if it is still being served or run
firebase serve
on the command line to start serving the app from http://localhost:5000 then open it in your browser.
- After signing-in, click the image upload button: and select an image file using the file picker, a new message should be visible in the app UI with your selected image:
- If you try adding an image while not signed-in you should see a Toast telling you that you must sign in in order to add images.
- Reload your app if it is still being served or run
firebase serve
on the command line to start serving the app from http://localhost:5000 then open it in your browser. - After signing-in, click the image upload button: and select an image file using the file picker, a new message should be visible in the app UI with your selected image:
- If you try adding an image while not signed-in you should see a Toast telling you that you must sign in in order to add images.
10. Show Notifications
We'll now add support for browser notifications. This way your users could receive a notification when a new message has been posted in the chat. Firebase Cloud Messaging (FCM) is a cross-platform messaging solution that lets you reliably deliver messages and notifications at no cost.
Whitelist the GCM Sender ID
In the web app manifest you need to specify the gcm_sender_id
, a hard-coded value indicating that FCM is authorized to send messages to this app. Friendlychat already has a manifest.json
configuration file so add the browser sender ID exactly as shown (do not change the value):
gcm_sender_id
, a hard-coded value indicating that FCM is authorized to send messages to this app. Friendlychat already has a manifest.json
configuration file so add the browser sender ID exactly as shown (do not change the value):manifest.json
{
"name": "Friendly Chat",
"short_name": "Friendly Chat",
"start_url": "/index.html",
"display": "standalone",
"orientation": "portrait",
"gcm_sender_id": "103953800507"
}
{
"name": "Friendly Chat",
"short_name": "Friendly Chat",
"start_url": "/index.html",
"display": "standalone",
"orientation": "portrait",
"gcm_sender_id": "103953800507"
}
Add the Firebase Messaging service worker
The web app needs a Service Worker that will receive and display web notifications. Create a file named firebase-messaging-sw.js
at the root of your project with the following content:
firebase-messaging-sw.js
at the root of your project with the following content:firebase-messaging-sw.js
importScripts('/__/firebase/3.8.0/firebase-app.js');
importScripts('/__/firebase/3.8.0/firebase-messaging.js');
importScripts('/__/firebase/init.js');
firebase.messaging();
The service worker simply loads and initializes the Firebase Cloud Messaging SDK which will take care of displaying notifications.
importScripts('/__/firebase/3.8.0/firebase-app.js');
importScripts('/__/firebase/3.8.0/firebase-messaging.js');
importScripts('/__/firebase/init.js');
firebase.messaging();
Get FCM device tokens
When notifications have been enabled on a device or browser, you'll be given a device token. This device token is what we use to send a notification to a particular device.
When the user signs-in we call the FriendlyChat.prototype.saveMessagingDeviceToken
function. That's where we'll get the FCM device token and save it to the Realtime Database.
Update the FriendlyChat.prototype.saveMessagingDeviceToken
function with:
FriendlyChat.prototype.saveMessagingDeviceToken
function. That's where we'll get the FCM device token and save it to the Realtime Database.FriendlyChat.prototype.saveMessagingDeviceToken
function with:main.js
// Saves the messaging device token to the datastore.
FriendlyChat.prototype.saveMessagingDeviceToken = function() {
firebase.messaging().getToken().then(function(currentToken) {
if (currentToken) {
console.log('Got FCM device token:', currentToken);
// Saving the Device Token to the datastore.
firebase.database().ref('/fcmTokens').child(currentToken)
.set(firebase.auth().currentUser.uid);
} else {
// Need to request permissions to show notifications.
this.requestNotificationsPermissions();
}
}.bind(this)).catch(function(error){
console.error('Unable to get messaging token.', error);
});
};
However this will not work initially. For your app to be able to retrieve the device token the user needs to grant your app permission to show notifications.
// Saves the messaging device token to the datastore.
FriendlyChat.prototype.saveMessagingDeviceToken = function() {
firebase.messaging().getToken().then(function(currentToken) {
if (currentToken) {
console.log('Got FCM device token:', currentToken);
// Saving the Device Token to the datastore.
firebase.database().ref('/fcmTokens').child(currentToken)
.set(firebase.auth().currentUser.uid);
} else {
// Need to request permissions to show notifications.
this.requestNotificationsPermissions();
}
}.bind(this)).catch(function(error){
console.error('Unable to get messaging token.', error);
});
};
Request permissions to show notifications
When the user has not yet granted you permission to show notifications you will not be given a device token. In this case we call the firebase.messaging().requestPermission()
method which will display a browser dialog asking for this permission:
Update the FriendlyChat.prototype.requestNotificationsPermissions
function with:
firebase.messaging().requestPermission()
method which will display a browser dialog asking for this permission:FriendlyChat.prototype.requestNotificationsPermissions
function with:main.js
// Requests permissions to show notifications.
FriendlyChat.prototype.requestNotificationsPermissions = function() {
console.log('Requesting notifications permission...');
firebase.messaging().requestPermission().then(function() {
// Notification permission granted.
this.saveMessagingDeviceToken();
}.bind(this)).catch(function(error) {
console.error('Unable to get permission to notify.', error);
});
};
// Requests permissions to show notifications.
FriendlyChat.prototype.requestNotificationsPermissions = function() {
console.log('Requesting notifications permission...');
firebase.messaging().requestPermission().then(function() {
// Notification permission granted.
this.saveMessagingDeviceToken();
}.bind(this)).catch(function(error) {
console.error('Unable to get permission to notify.', error);
});
};
Get your Device token
- Reload your app if it is still being served or run
firebase serve
on the command line to start serving the app from http://localhost:5000 then open it in your browser.
- After signing-in, you should see the Notifications permission dialog being displayed:
- Click Allow and open the JavaScript console of your browser, you should see a message that reads:
Got FCM device token: cWL6w:APA91bHP...4jDPL_A-wPP06GJp1OuekTaTZI5K2Tu
- Copy your device token, you will need it for the next step.
firebase serve
on the command line to start serving the app from http://localhost:5000 then open it in your browser.Got FCM device token: cWL6w:APA91bHP...4jDPL_A-wPP06GJp1OuekTaTZI5K2Tu
Send a notification to your device
Now that you have your device token you can send a notification. You will also need your Firebase app's Server Key. to get it open your app's Firebase Console > Project Settings > Cloud Messaging and copy the Server Key.
To send a notification you need to send the following HTTP request:
POST /fcm/send HTTP/1.1
Host: fcm.googleapis.com
Content-Type: application/json
Authorization: key=YOUR_SERVER_KEY
{
"notification": {
"title": "New chat message!",
"body": "There is a new message in FriendlyChat",
"icon": "/images/profile_placeholder.png",
"click_action": "http://localhost:5000"
},
"to":"YOUR_DEVICE_TOKEN"
}
You can do this by using cURL in a command line:
curl -H "Content-Type: application/json" \
-H "Authorization: key=YOUR_SERVER_KEY" \
-d '{
"notification": {
"title": "New chat message!",
"body": "There is a new message in FriendlyChat",
"icon": "/images/profile_placeholder.png",
"click_action": "http://localhost:5000"
},
"to": "YOUR_DEVICE_TOKEN"
}' \
https://fcm.googleapis.com/fcm/send
The notification will only appear if your FriendlyChat app is in the background. You must, for instance, navigate away or display another tab for the notification to be displayed.
When the app is in the foreground, you can catch the messages sent by FCM.
If your app is on the background you should see a notification appear such as:
Now that you have your device token you can send a notification. You will also need your Firebase app's Server Key. to get it open your app's Firebase Console > Project Settings > Cloud Messaging and copy the Server Key.
To send a notification you need to send the following HTTP request:
POST /fcm/send HTTP/1.1
Host: fcm.googleapis.com
Content-Type: application/json
Authorization: key=YOUR_SERVER_KEY
{
"notification": {
"title": "New chat message!",
"body": "There is a new message in FriendlyChat",
"icon": "/images/profile_placeholder.png",
"click_action": "http://localhost:5000"
},
"to":"YOUR_DEVICE_TOKEN"
}
You can do this by using cURL in a command line:
curl -H "Content-Type: application/json" \
-H "Authorization: key=YOUR_SERVER_KEY" \
-d '{
"notification": {
"title": "New chat message!",
"body": "There is a new message in FriendlyChat",
"icon": "/images/profile_placeholder.png",
"click_action": "http://localhost:5000"
},
"to": "YOUR_DEVICE_TOKEN"
}' \
https://fcm.googleapis.com/fcm/send
The notification will only appear if your FriendlyChat app is in the background. You must, for instance, navigate away or display another tab for the notification to be displayed.
When the app is in the foreground, you can catch the messages sent by FCM.
If your app is on the background you should see a notification appear such as:
11. Database Security Rules [Optional]
Set Database Security Rules
The Firebase Realtime Database uses a specific rules language to define access rights, security and data validations.
New Firebase Projects are set up with default rules that only allow authenticated users to use the Realtime Database. You can view and modify these rules in the Database section of Firebase console under the RULES tab. You should be seeing the default rules:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
This rule allows any signed-in user to read and write any data in your Firebase Realtime database.
Update the rules to the following which only allows users to read and write their own Firebase Cloud Messaging device tokens:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
database-rules.json
{
"rules": {
"messages": {
".read": "auth !== null",
".write": "auth !== null"
},
"fcmTokens": {
"$token": {
// Users can only read their own device tokens
".read": "data.val() === auth.uid",
// Users can only write to their own device tokens
".write": "!data.exists() || data.val() === auth.uid",
// value has to be the UID of the user
".validate": "newData.val() === auth.uid"
}
}
}
}
You can update these rules manually directly in the Firebase console. Alternatively you can write these rules in a file and apply them to your project using the CLI:
- Save the rules shown above in a file named
database-rules.json
.
- In your
firebase.json
file, add a database.rules
attribute pointing to a JSON file containing the rules shown above (the hosting
attribute should already be there):
{
"rules": {
"messages": {
".read": "auth !== null",
".write": "auth !== null"
},
"fcmTokens": {
"$token": {
// Users can only read their own device tokens
".read": "data.val() === auth.uid",
// Users can only write to their own device tokens
".write": "!data.exists() || data.val() === auth.uid",
// value has to be the UID of the user
".validate": "newData.val() === auth.uid"
}
}
}
}
database-rules.json
.firebase.json
file, add a database.rules
attribute pointing to a JSON file containing the rules shown above (the hosting
attribute should already be there):firebase.json
{
"database": {
"rules": "database-rules.json"
},
"hosting": {
"public": "./",
"ignore": [
"firebase.json",
"database-rules.json",
"storage.rules"
]
}
}
{
"database": {
"rules": "database-rules.json"
},
"hosting": {
"public": "./",
"ignore": [
"firebase.json",
"database-rules.json",
"storage.rules"
]
}
}
Deploy Database Security Rules
You can then deploy these rules with the Firebase CLI using firebase deploy --only database
:
firebase deploy --only database
This is the console output you should see:
=== Deploying to 'friendlychat-12345'...
i deploying database
✔ database: rules ready to deploy.
i starting release process (may take several minutes)...
✔ Deploy complete!
Project Console: https://console.firebase.google.com/project/friendlychat-12345/overview
firebase deploy --only database
:firebase deploy --only database
=== Deploying to 'friendlychat-12345'...
i deploying database
✔ database: rules ready to deploy.
i starting release process (may take several minutes)...
✔ Deploy complete!
Project Console: https://console.firebase.google.com/project/friendlychat-12345/overview
12. Storage Security Rules [Optional]
Set Storage Security Rules
Cloud Storage for Firebase uses a specific rules language to define access rights, security and data validations.
New Firebase projects are set up with default rules that only allow authenticated users to use Cloud Storage. You can view and modify these rules in the Storage section of Firebase console under the RULES tab. You should be seeing the following default rule:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
This rule allow any signed-in user to read and write any files in your Storage bucket.
Update the rules to the following which only allows users to write to their own folder:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
storage.rules
service firebase.storage {
match /b/{bucket}/o {
match /{userId}/{timeStamp}/{fileName} {
allow write: if request.auth.uid == userId;
allow read;
}
}
}
You can update these rules manually directly in the Firebase console. Alternatively you can write these rules in a file and apply them to your project using the CLI:
- Save the rules shown above in a file named
storage.rules
- In your
firebase.json
file, add a storage.rules
attribute pointing to a file containing the rules shown above:
service firebase.storage {
match /b/{bucket}/o {
match /{userId}/{timeStamp}/{fileName} {
allow write: if request.auth.uid == userId;
allow read;
}
}
}
storage.rules
firebase.json
file, add a storage.rules
attribute pointing to a file containing the rules shown above:firebase.json
{
// If you went through the "Realtime Database Security Rules" step.
"database": {
"rules": "database-rules.json"
},
"storage": {
"rules": "storage.rules"
},
"hosting": {
"public": "./",
"ignore": [
"firebase.json",
"database-rules.json",
"storage.rules"
]
}
}
{
// If you went through the "Realtime Database Security Rules" step.
"database": {
"rules": "database-rules.json"
},
"storage": {
"rules": "storage.rules"
},
"hosting": {
"public": "./",
"ignore": [
"firebase.json",
"database-rules.json",
"storage.rules"
]
}
}
Deploy Storage Security Rules
You can then deploy these rules with the Firebase CLI using firebase deploy --only storage
:
firebase deploy --only storage
This is the console output you should see:
=== Deploying to 'friendlychat-12345'...
i deploying storage
i storage: checking rules for compilation errors...
✔ storage: rules file compiled successfully
i starting release process (may take several minutes)...
✔ Deploy complete!
Project Console: https://console.firebase.google.com/project/friendlychat-12345/overview
firebase deploy --only storage
:firebase deploy --only storage
=== Deploying to 'friendlychat-12345'...
i deploying storage
i storage: checking rules for compilation errors...
✔ storage: rules file compiled successfully
i starting release process (may take several minutes)...
✔ Deploy complete!
Project Console: https://console.firebase.google.com/project/friendlychat-12345/overview
13. Deploy your app using Firebase static hosting
Firebase comes with a hosting service that will serve your static assets/web app. You deploy your files to Firebase Hosting using the Firebase CLI. Before deploying you need to specify which files will be deployed in your firebase.json
file. We have already done this for you because this was required to serve the file for development through this codelab. These settings are specified under the hosting
attribute:
firebase.json
file. We have already done this for you because this was required to serve the file for development through this codelab. These settings are specified under the hosting
attribute:firebase.json
{
// If you went through the "Realtime Database Security Rules" step.
"database": {
"rules": "database-rules.json"
},
// If you went through the "Storage Security Rules" step.
"storage": {
"rules": "storage.rules"
},
"hosting": {
"public": "./",
"ignore": [
"firebase.json",
"database-rules.json",
"storage.rules"
]
}
}
This will tell the CLI that we want to deploy all files in the current directory ( "public": "./"
) with the exception of the files listed in the ignore
array.
Now deploy your files to Firebase static hosting by running firebase deploy
:
firebase deploy
This is the console output you should see:
=== Deploying to 'friendlychat-12345'...
i deploying database, storage, hosting
✔ database: rules ready to deploy.
i storage: checking rules for compilation errors...
✔ storage: rules file compiled successfully
i hosting: preparing ./ directory for upload...
✔ hosting: ./ folder uploaded successfully
✔ hosting: 9 files uploaded successfully
i starting release process (may take several minutes)...
✔ Deploy complete!
Project Console: https://console.firebase.google.com/project/friendlychat-12345/overview
Hosting URL: https://friendlychat-12345.firebaseapp.com
Then simply visit your web app hosted on Firebase Hosting on https://<project-id>.firebaseapp.com
or by running firebase open hosting:site
.
The Hosting tab in the Firebase console will display useful information such as the history of your deploys with the ability to rollback to previous versions and the ability to set up a custom domain.
{
// If you went through the "Realtime Database Security Rules" step.
"database": {
"rules": "database-rules.json"
},
// If you went through the "Storage Security Rules" step.
"storage": {
"rules": "storage.rules"
},
"hosting": {
"public": "./",
"ignore": [
"firebase.json",
"database-rules.json",
"storage.rules"
]
}
}
"public": "./"
) with the exception of the files listed in the ignore
array.firebase deploy
:firebase deploy
=== Deploying to 'friendlychat-12345'...
i deploying database, storage, hosting
✔ database: rules ready to deploy.
i storage: checking rules for compilation errors...
✔ storage: rules file compiled successfully
i hosting: preparing ./ directory for upload...
✔ hosting: ./ folder uploaded successfully
✔ hosting: 9 files uploaded successfully
i starting release process (may take several minutes)...
✔ Deploy complete!
Project Console: https://console.firebase.google.com/project/friendlychat-12345/overview
Hosting URL: https://friendlychat-12345.firebaseapp.com
https://<project-id>.firebaseapp.com
or by running firebase open hosting:site
.
Comments
Post a Comment