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 an 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 the FCM service.

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

  • Please remember that this is only a 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 the 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 the following features:

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

The 2021 update:

For Ionic 5 and Capacitor-based applications, I’d suggest using this plugin.
The approach shown in this blog post is using Cordova Firebase plugin.

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 to our project

ionic cordova platform add android

If you need to test it in your browser you should add this platform to 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 a 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 device tokens. Go to the Database tab (below Develop), click the ‘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 the 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 notification 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 the 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 template files, generated from the initial command. On the view layer, we’ll use the ion-toggle element to subscribe / unsubscribe feature.

For example, let’s take the HomeComponent file (home.ts) and let it subscribe / unsubscribe to a 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 by passing the 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 a real device rather than an emulator. The browser is not a good idea here as well because basically, Cordova plugins won’t work there.

For test purposes, I’m using simple build command to generate an 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 a general push notification in the Android dashboard:

And that’s it.

The source code of this app is available on GitHub.

Enjoy!

9 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

  2. Hello
    I studied in a blog to be a reference. I tried a blog.
    thank you very much.

    I created the same way, but I can not receive the payload data even if I tap the push notification in IOS.
    Do you know the cause?

    Success until push notification
    Succeeds until app is launched when tapping the push notification
    You can not transition to any page by tapping the push notification.

    1. Hi Takeshi, thanks for your comment.
      Obviously you need to provide behaviour for your app when clicking push notification.
      In Ionic it basically comes down to check your application state (whether it’s minimized/open/closed) when you click on the notification.

      Please note that I didn’t cover iOS platform in this article. It will need few more steps to be fully compatible with iOS apps.

      Take care!

    1. Hi Asura. If I understand you correctly you have a problem with ion-toggle element.

      The function responsible for handling subscription is called handleSubscription and you can find it in HomePage component.

      You can always use the sources from GitHub for a reference.

      1. i have faced one more thing when i build android release. The error:
        ERROR in Error during template compile of ‘Firebase’
        Only initialized variables and constants can be referenced in decorators because the value of this variable is needed by the template compiler in ‘Plugin’
        ‘Plugin’ references ‘Plugin’
        ‘Plugin’ is not initialized at @ionic-native\core\decorators\interfaces.ts(100,22).

  3. Good luck!!!! at the end of the article creator give a hint

    use cordova-plugin-fcm-with-dependecy-updated instead and there’s an github link for ionic 3 example

    Best Regards

Leave a Reply

Your email address will not be published.