Get your simple push notifications app with Ionic 4 and Firebase Cloud Messaging

Recently I needed a simple mobile app to test my simple push notifications service. In my case it was a Android app receiving notifications from Firebase Cloud Messaging.

In this article I’m going to share my experience with you. I’ll show you how you can create your own simple Ionic 4 Android app and integrate it with FCM service.

But first of all I’m going to start with disclaimers:

  • Please remember that this is only simple starter example. To make sure your notifications behaving properly you have to store user subscriptions somewhere (for example in Firebase or local storage).
  • This article doesn’t cover iOS platform but it’s possible to use FCM as your push notifications provider in iOS apps.

Main goals

We’d like our app to have following features:

  • store devices tokens in Firebase database
  • overall push notifications receiving
  • topic-based push notifications subscription / unsubscription

Requirements

We will need:

  • Ionic 4,
  • NPM,
  • Android SDK,
  • Firebase account and app created,
  • and a little bit of patience 😉

Let’s go – project preparation

First of all we need to create a new Ionic project. I’m going to use a tabs template and ionic-angular type of the project.

ionic start pushNotificationsExample tabs --type=ionic-angular

 

At this point we can add an Android platform into our project

ionic cordova platform add android

If you need to test it in your browser you should add this platform into the project

ionic cordova platform add browser

Then we have to integrate a Cordova plugin for Firebase

ionic cordova plugin add cordova-plugin-firebase

 

Then we’ll need some packages from NPM – Firebase Ionic Native package and AngularFire2, a library for Angular and Firebase integration.

npm i -s @ionic-native/firebase@4.20.0
npm install --save angularfire2 firebase

Firebase setup

Now it’s time to configure a Firebase project. You should log into Firebase console  and add new project if you don’t have one already.

Now, go into your project’s console and add a new Android app to your project. Please note that a package name has to be exactly the same as the one used in your config.xml file.

<widget id="com.hello.push.notifications.example" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
config.xml:2

Download generated google-services.json file and place it into your Ionic’s project root folder.

Now it’s time to create a Firebase database. We’ll use it to store user’s devices tokens. Go to Database tab (below Develop), click ‘Create database‘ button and choose test mode.

Back to the code

Okay, it’s time to finally configure our app. First of all we have to configure Firebase libraries in main module file – app.module.ts.

Use the credentials you have in your google-services.json file in order to configure Firebase properly.

import { NgModule, ErrorHandler } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';

import { AboutPage } from '../pages/about/about';
import { ContactPage } from '../pages/contact/contact';
import { HomePage } from '../pages/home/home';
import { TabsPage } from '../pages/tabs/tabs';

import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { AngularFireModule } from 'angularfire2';
import { AngularFirestoreModule } from 'angularfire2/firestore';
import {NotificationsService} from "../services/notifications.service";
import {Firebase} from "@ionic-native/firebase";

const FIREBASE_CONFIG = {
  apiKey: 'Paste your current_key here',
  authDomain: 'Paste your firebase_url here...',
  databaseURL: 'Paste your firebase_url here...',
  projectId: 'Paste your project_id here...',
  storageBucket: 'Paste your storage_bucket here...',
  messagingSenderId: 'Paste your project_number here...'
};

@NgModule({
  declarations: [
    MyApp,
    AboutPage,
    ContactPage,
    HomePage,
    TabsPage
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp),
    AngularFireModule.initializeApp(FIREBASE_CONFIG),
    AngularFirestoreModule
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    AboutPage,
    ContactPage,
    HomePage,
    TabsPage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    Firebase,
    NotificationsService,
    {provide: ErrorHandler, useClass: IonicErrorHandler}
  ]
})
export class AppModule {}

Now, it’s time to create a service class for notifications handling. Later on we’ll import it into our providers in app.module.ts. Let’s call it NotificationsService.

import { Injectable } from '@angular/core';
import { AngularFirestore } from 'angularfire2/firestore';
import {Platform} from 'ionic-angular';
import {Firebase} from '@ionic-native/firebase';

@Injectable()
export class NotificationsService {

  constructor(private firebase: Firebase,
              private angularFirestore: AngularFirestore,
              private platform: Platform) {}

  async getToken() {
    let token;
    if (this.platform.is('android')) {
      token = await this.firebase.getToken();
    }
    this.saveToken(token);
  }

  private saveToken(token) {
    if (!token) return;
    const devicesDatabaseReference = this.angularFirestore.collection('device-tokens');
    const data = {
      token,
      userId: 'user-'+new Date().toISOString(),
    };
    return devicesDatabaseReference.doc(token).set(data);
  }

  topicSubscription(topic) {
    this.firebase.subscribe(topic).then((res:any) => {
      console.log('Subscribed to topic: ' + topic, res);
    });
  }

  topicUnsubscription(topic) {
    this.firebase.unsubscribe(topic).then((res:any) => {
      console.log('Unsubscribed from topic: ' + topic, res)
    });
  }

  onNotifications() {
    return this.firebase.onNotificationOpen();
  }
}

Now we can use our service inside components. In main component (app.component.ts) we’ll subscribe to main notifications.

...

@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  rootPage: any = TabsPage;

  constructor(private statusBar: StatusBar,
              private splashScreen: SplashScreen,
              private platform: Platform,
              private notificationsService: NotificationsService,
              private toastController: ToastController) {
    platform.ready().then(() => {
      statusBar.styleDefault();
      splashScreen.hide();
      this.notificationSetup();
    });
  }

  private async presentToast(message) {
    const toast = await this.toastController.create({
      message,
      duration: 3000
    });
    toast.present();
  }

  private notificationSetup() {
    this.notificationsService.getToken();
    this.notificationsService.onNotifications().subscribe(
      (msg) => {
        this.presentToast(msg.body);
      });
  }

}

When it comes to topic-based notifications we’ll use tabs files generated from. On the view layer we’ll use ion-toggle element to subscribe / unsubscribe feature.

For example let’s take HomeComponent file (home.ts) and let it subscribe / unsubscribe to topic called homeTopic.

...

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  public notifications: any;
  public isSubscribed: boolean;
  private TOPIC_NAME = 'homeTopic';
  constructor(public navCtrl: NavController,
              private notificationsService: NotificationsService,
              private toastController: ToastController) {
    this.isSubscribed = false;
  }

  ionViewDidEnter() {
    this.notifications = this.notificationsService.onNotifications().subscribe(
      (msg) => {
        this.presentToast(msg.body);
      });
  }
  ionViewDidLeave() {
    this.notifications.unsubscribe();
  }

  public handleSubscription(subscribed){
    if(subscribed) {
      this.notificationsService.topicSubscription(this.TOPIC_NAME);
    } else {
      this.notificationsService.topicUnsubscription(this.TOPIC_NAME);
    }
  }

  private async presentToast(message) {
    const toast = await this.toastController.create({
      message,
      duration: 3000,
      position: 'middle'
    });
    toast.present();
  }




}

Let’s use handleSubscription() function in the view layer (home.html). The key thing is the ion-toggle element. It’ll fire our function by every state change passing boolean variable into it.

<ion-toggle [(ngModel)]="subscription" (ngModelChange)="handleSubscription($event)"></ion-toggle>

Okay, you can build your app and test it. Personally I prefer to do it on the real device rather than emulator. The browser is not a good idea here as well because basically Cordova plugins won’t be running there.

For test purposes I’m using simple build command to generate unsigned *.apk app file.

ionic cordova build android

Now you’re ready to test push notifications on your phone.

Testing time

Check your Firebase database document after app initialization. There should be your device’s token stored. The date-time string in the user key was used just for debugging purposes, you probably won’t need this in production.

Take the token value and send some direct notifications from Cloud messaging tab in your Firebase console. Then you can send topic-based notifications and general notifications for all users there.

This is the effect of homeTopic notification:

And this is general push notification in the Android dashboard:

And that’s it.

Source code of this app is available on GitHub.

Enjoy!

2 thoughts on “Get your simple push notifications app with Ionic 4 and Firebase Cloud Messaging”

  1. Hi sir,
    Can you please provide a github working example a got error in those plugins
    cordova.system.library.4=com.google.firebase:firebase-core:16.0.8
    cordova.system.library.5=com.google.firebase:firebase-messaging:17.5.0
    cordova.system.library.6=com.google.firebase:firebase-config:16.4.1
    cordova.system.library.7=com.google.firebase:firebase-perf:16.2.4

Leave a Reply

Your e-mail address will not be published. Required fields are marked *