Firebase Push Messaging

What is Firebase?

  • Build apps fast, without managing infrastructure
  • Built on Google infrastructure
  • Web and Mobile
  • Messaging
  • Analytics
  • Crash reporting
  • Hosting
  • Authentication
  • Databases

Get started for free!

But be wary

Firebase Costs Increased by 7,000%!
...I used only a few MB of bandwidth — yet their analytics showed 2 GB for that same period!
...they informed me that their profiling tool does not show this SSL overhead
 

Firebase has finished providing the credits and we have a meeting scheduled next week to dig deeper into usage. They have been great since I got in contact with Alex & Andrew over there. They have definitely resolved this issue in my eyes and I feel they have a better handle on how to handle this moving forward so this doesn’t happen to others!

We told them that we spent the full 25k grant we had just a few days ago and see the chance to apply for the 100k grant on Google Cloud Services. We contacted the team of Google Developers Latam, to tell them what had just happened. They allowed us to apply for the next grant, which google approved,

How we spent 30k USD in Firebase in less than 72 hours
We had reached more than 2 million sessions, more than 20 million pages visited...
We did more than 46 BILLION requests to Firestore
... It was just one bad line of code that was causing that amount of requests

What is Firebase Cloud Messaging?

  • Send messages and notifications to users across platforms—Android, iOS, and the web—for free.
  • Messages can be sent to single devices, groups of devices, or specific topics or user segments.

How does it work?

  • Register device and app with Firebase
  • You'll get a token sometimes known as
    • ​Device Token
    • Registration Token
    • FCM token (previously GCM token)

How does it work?

  • Server code that sends a message to an individual person/token, a group or people or a topic

How does it work?

  • Server code communicates with Firebase which will then handle the delivery of the messages

What Messages can I send?

{
  "message":{
    "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "notification":{
      "title":"Portugal vs. Denmark",
      "body":"great match!"
    }
  }
}
{
  "message":{
    "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "data":{
      "Nick" : "Mario",
      "body" : "great match!",
      "Room" : "PortugalVSDenmark"
    }
  }
}

What do I need?

  • Server side configuration
    • Project ID 
      • Name of your project needed to make request to Firebase
    • Server key
      • Used to send messages
    • Access Token

What do I need?

  • Client Side configuration
    • Token
      • Generated dynamically
    • Sender ID
      • Identifiers the sender
      • Generated in Firebase

What do I need?

  • Project ID
  • Server key
  • Sender ID

What do I need?

To the code!

Local Notifications

Notification.requestPermission(status => {
   console.log('Notification permission status:', status, true);
});

Request Permissions

Possible values:

  • default
  • denied
  • granted
Notification.permission

You need permissions to send

You need a service worker to display notifications

navigator.serviceWorker.register('serviceworker.js', {scope: '/'})
.then(function(reg) {
	log('Registration succeeded. Scope is ' + reg.scope);

}).catch(function(error) {
	log('Registration failed with ' + error);
});


// serviceworker.js
console.log('service worker here');

Local Notifications

payload = {
  notification : {
    "title": "Push notification",
    "body": "No payload so default value here",
    "badge": "/logo.png"
  }
}		  			},

navigator.serviceWorker.getRegistration().then(function(reg) {
  var time = Date.now() - 60*10;
  var options = {
    body: payload.notification.body,
    icon: payload.notification.badge,
    "webpush": {
      "headers": {
        "Urgency": "high"
      },
      "notification": {
        "title": "Web title",
        "body": "Web body",
        "badge": "/logo.png"
      },
    }
    
  };
  reg.showNotification(payload.notification.title, options);
});

Local Notifications

Tokens

var messaging = firebase.messaging();
function getToken(){
messaging.getToken().then(function(currentToken) {
  if (currentToken) {
    console.log("We have a token: " + currentToken);
    sendTokenToServer(currentToken);
  } else {
    console.log('No Instance ID token available. Request permission to generate one.');
  }
}).catch(function(err) {
  console.log('An error occurred while retrieving token. ', err);
  
});
}

// Callback fired if Instance ID token is updated.
messaging.onTokenRefresh(function() {
  messaging.getToken().then(function(refreshedToken) {
    console.log('Token refreshed.');
    console.log("We have a token: " + refreshedToken);
    sendTokenToServer(refreshedToken);
  }).catch(function(err) {
    console.log('Unable to retrieve refreshed token ', err);
  });
});

Get the token. Save it on your server

Handling FCM Notifications

// When web page in foreground in main web page when app is in the foreground
messaging.onMessage(function(payload) {
  console.log('Message received. ', payload);
  displayNotification(payload);
});


// in service worker firebase-messaging-sw.js
messaging.setBackgroundMessageHandler(function(payload) {
  console.log('[firebase-messaging-sw.js] Received background message ', payload);
  // Customize notification here
  var notificationTitle = 'Background Message Title';
  var notificationOptions = {
    body: 'Background Message body.',
    icon: '/firebase-logo.png'
  };

  return self.registration.showNotification(notificationTitle,
    notificationOptions);
});

Depends if app is in the foreground or background

Get Access Token

const {google} = require('googleapis');

const SCOPES = "https://www.googleapis.com/auth/firebase.messaging";
const SERVICE_ACCOUNT_JSON_FILE = 'SERVICE_ACCOUNT.json'

 function getAccessToken() {
  return new Promise(function(resolve, reject) {
    var key = require(SERVICE_ACCOUNT_JSON_FILE);
    var jwtClient = new google.auth.JWT(
      key.client_email,null,key.private_key,SCOPES, null
    );
    jwtClient.authorize(function(err, tokens) {
      if (err) {
        reject(err);
        return;
      }
      resolve(tokens.access_token);
    });
  });
}

getAccessToken().then(function(err, tokens){
      if (err) {
        console.error(err);
        return;
      }
      console.log(tokens);
});

Send Notification to Token

{
  "message": {
    "token" : "fByerczVlXk:APA91bGKIcOPQOq6ImL....",
    "notification": {
      "title": "Default Title",
      "body": "Default Content"
    },
    "webpush": {
      "headers": {
        "Urgency": "high"
      },
      "notification": {
        "title": "Web push title",
        "body": "Web push body",
        "badge": "/logo.png",
        "click_action": "https://google.com"
      },
      "fcm_options": {
        "link": "https://yahoo.com"
      }
    }
  }
}
POST to https://fcm.googleapis.com/v1/projects/{{ProjectName}}/messages:send

Headers
  Content-Type: application/json
  Authorization: Bearer {{AccessToken}}

Register a device to a topic

POST to https://iid.googleapis.com/iid/v1/{{TOKEN}}/rel/topics/{{TOPIC_NAME}}

Headers
  Content-Type: application/json
  Authorization: key={{ SERVER_KEY }}

Send Notification to Topic

{
  "message": {
    "topic": "topic_name1",
    "notification": {
      "title": "Topic 1",
      "body": "Message by topic"
    },
    "webpush": {
      "notification": {
  	"click_action": "https://yahoo.com"
      },
      "fcm_options": {
        "link": "https://dummypage.com"
      }
    }
  }
}
POST to https://fcm.googleapis.com/v1/projects/{{ProjectName}}/messages:send

Headers
  Content-Type: application/json
  Authorization: Bearer {{AccessToken}}

Send Notification to Topic 2

{
  "message": {
    "topic": "topic_name1",
    "notification": {
      "title": "Topic 1",
      "body": "Message by topic"
    }
  }
}
POST to https://fcm.googleapis.com/fcm/send

Headers
  Content-Type: application/json
  Authorization: key= {{ SERVER_KEY }}

Remove Token Registration

DELETE to  https://iid.googleapis.com/v1/web/iid/{{TOKEN}}

Headers
  Content-Type: application/json
  Authorization: key= {{ SERVER_KEY }}

Summary

  • So many docs (with repeated content)
  • Some parts not needed? e.g. 
    usePublicVapidKey
  • So many different authentications
  • Duplicate ways of sending messages e.g. 2 ways to send by topic
  • Some things don't work?!?!?
    • webpush link / click_action