Push notifications, ionic capacitor 5

This is my code for initializing push notifications, when i open the apk the app automatically closes, can someone point out what am i missing here

import { Injectable } from '@angular/core';
import { Capacitor } from '@capacitor/core';
import { ActionPerformed, PushNotifications, PushNotificationSchema, Token } from '@capacitor/push-notifications';
import { ModalController } from '@ionic/angular';
import { BehaviorSubject } from 'rxjs';
import { NotificationPage } from '../notification/notification.page';
// import { Plugins } from '@capacitor/core';
import { App } from '@capacitor/app';
import { registerPlugin } from '@capacitor/core';

// const { AppSettingsOpener } = Plugins;
export interface AppSettingsOpenerPlugin {
  open(): Promise<void>; // Declare the method signature
}
export const AppSettingsOpener = registerPlugin<AppSettingsOpenerPlugin>('AppSettingsOpener');

export const FCM_TOKEN = 'push_notification_token';

@Injectable({
  providedIn: 'root'
})
export class FcmService {

  private _redirect = new BehaviorSubject<any>(null);

  get redirect() {
    return this._redirect.asObservable();
  }

  constructor(public modalCtrl: ModalController,

  ) { }

  initPush() {
    if (Capacitor.getPlatform() !== 'web') {
      this.registerPush();
      // this.getDeliveredNotifications();
      App.addListener('appStateChange', async ({ isActive }) => {
        if (isActive) {
          console.log('App is active again. Retrying permission check...');
          this.registerPush(); // retry registering and requesting permission
        }
      });
    }
  }

  // private async registerPush() {
  //   try {
  //     await this.addListeners();
  //     let permStatus = await PushNotifications.checkPermissions();

  //     if (permStatus.receive === 'prompt') {
  //       permStatus = await PushNotifications.requestPermissions();
  //     }

  //     if (permStatus.receive !== 'granted') {
  //       throw new Error('User denied permissions!');
  //     }

  //     await PushNotifications.register();
  //   } catch(e) {
  //     console.log(e);
  //   }
  // }
  private async registerPush() {
    try {
      await this.addListeners();

      const granted = await this.ensurePushPermission();
      if (!granted) {
        console.warn('Notification permission not granted by user');
        return;
      }

      await PushNotifications.register();
    } catch (e) {
      console.error('Push registration failed:', e);
    }
  }
  private async ensurePushPermission(): Promise<boolean> {
    let permStatus = await PushNotifications.checkPermissions();
    console.log('Permission status (before):', permStatus);

    if (permStatus.receive === 'prompt') {
      permStatus = await PushNotifications.requestPermissions();
      console.log('Permission status (after prompt):', permStatus);
    }

    if (permStatus.receive !== 'granted') {
      console.warn('User denied notification permissions.');
      const confirmed = confirm('This app needs notification permission. Would you like to open settings to enable it?');
      if (confirmed) {
        try {
          await AppSettingsOpener.open();

        } catch (e) {
          console.error('Failed to open settings:', e);
        }
      }
      return false;
    }

    return true;
  }

  async getDeliveredNotifications() {
    const notificationList = await PushNotifications.getDeliveredNotifications();
    console.log('delivered notifications', notificationList);
  }

  addListeners() {
    PushNotifications.addListener(
      'registration',
      async (token: Token) => {
        console.log('My token: ', token);
        const fcm_token = (token?.value);
        let go = 1;
        const saved_token = JSON.parse((await localStorage.getItem('pushtoken')));
        if (saved_token) {
          if (fcm_token == saved_token) {
            console.log('same token');
            go = 0;
          } else {
            go = 2;
          }
        }
        if (go == 1) {
          // save token
          localStorage.setItem('pushtoken', JSON.stringify(fcm_token));
        } else if (go == 2) {
          // update token
          const data = {
            expired_token: saved_token,
            refreshed_token: fcm_token
          };
          localStorage.setItem('pushtoken', fcm_token);
        }
      }
    );

    PushNotifications.addListener('registrationError', (error: any) => {
      console.log('Error: ' + JSON.stringify(error));
    });

    PushNotifications.addListener(
      'pushNotificationReceived',
      async (notification: PushNotificationSchema) => {
        console.log('Push received: ' + JSON.stringify(notification));
        const data = notification?.data;
        if (data?.redirect) this._redirect.next(data?.redirect);
      }
    );

    PushNotifications.addListener(
      'pushNotificationActionPerformed',
      async (notification: ActionPerformed) => {
        const data = notification.notification.data;
        setTimeout(() => {
          this.shownotifications();
        }, 1000);
        console.log('Action performed: ' + JSON.stringify(notification.notification));
        console.log('push data: ', data);
        if (data?.redirect) this._redirect.next(data?.redirect);
      }
    );
  }
  async shownotifications() {
    const modal = await this.modalCtrl.create({
      component: NotificationPage,
      animated: true,
      // mode: 'ios',
      backdropDismiss: true,
    })

    return await modal.present();
  }

  async removeFcmToken() {
    try {
      const saved_token = JSON.parse((await localStorage.getItem('FCM_TOKEN')));
      localStorage.removeItem('FCM_TOKEN');
    } catch (e) {
      console.log(e);
      throw (e);
    }

  }
}```

This is my package.json

{
“name”: “appname”,
“version”: “0.0.1”,
“author”: “Ionic Framework”,
“homepage”: “https://ionicframework.com/”,
“scripts”: {
“ng”: “ng”,
“start”: “ng serve”,
“build”: “ng build”,
“test”: “ng test”,
“lint”: “ng lint”,
“e2e”: “ng e2e”
},
“private”: true,
“dependencies”: {
“@angular/common”: “~13.2.2”,
“@angular/core”: “~13.2.2”,
“@angular/forms”: “~13.2.2”,
“@angular/platform-browser”: “~13.2.2”,
“@angular/platform-browser-dynamic”: “~13.2.2”,
“@angular/router”: “~13.2.2”,
“@awesome-cordova-plugins/android-permissions”: “^6.13.0”,
“@awesome-cordova-plugins/app-version”: “^5.44.0”,
“@awesome-cordova-plugins/background-mode”: “^5.43.0”,
“@awesome-cordova-plugins/camera”: “^5.44.0”,
“@awesome-cordova-plugins/camera-preview”: “^5.44.0”,
“@awesome-cordova-plugins/chooser”: “^5.43.0”,
“@awesome-cordova-plugins/core”: “^5.46.0”,
“@awesome-cordova-plugins/device”: “^5.44.0”,
“@awesome-cordova-plugins/document-scanner”: “^5.43.0”,
“@awesome-cordova-plugins/file”: “^6.13.0”,
“@awesome-cordova-plugins/file-opener”: “^5.44.0”,
“@awesome-cordova-plugins/file-path”: “^5.44.0”,
“@awesome-cordova-plugins/file-transfer”: “^5.44.0”,
“@awesome-cordova-plugins/in-app-browser”: “^5.45.0”,
“@awesome-cordova-plugins/multiple-document-picker”: “^5.44.0”,
“@byteowls/capacitor-oauth2”: “^4.0.2”,
“@capacitor-community/speech-recognition”: “^6.0.0”,
“@capacitor/android”: “5.7.6”,
“@capacitor/app”: “^5.0.0”,
“@capacitor/core”: “^5.7.6”,
“@capacitor/filesystem”: “^6.0.2”,
“@capacitor/haptics”: “^5.0.0”,
“@capacitor/keyboard”: “^5.0.0”,
“@capacitor/local-notifications”: “^5.0.0”,
“@capacitor/push-notifications”: “^5.1.2”,
“@capacitor/status-bar”: “^5.0.0”,
“@capawesome/capacitor-file-picker”: “^0.5.0”,
“@ionic-native/android-permissions”: “^5.36.0”,
“@ionic-native/base64”: “^5.36.0”,
“@ionic-native/camera”: “^5.36.0”,
“@ionic-native/core”: “^5.36.0”,
“@ionic-native/crop”: “^5.36.0”,
“@ionic-native/device”: “^5.36.0”,
“@ionic-native/document-scanner”: “^5.36.0”,
“@ionic-native/downloader”: “^5.36.0”,
“@ionic-native/file”: “^5.36.0”,
“@ionic-native/file-opener”: “^5.36.0”,
“@ionic-native/file-transfer”: “^5.36.0”,
“@ionic-native/fingerprint-aio”: “^5.36.0”,
“@ionic-native/http”: “^5.36.0”,
“@ionic-native/multiple-document-picker”: “^5.36.0”,
“@ionic-native/preview-any-file”: “^5.36.0”,
“@ionic/angular”: “^6.0.0”,
“@types/hammerjs”: “^2.0.41”,
“angular2-signaturepad”: “^4.0.2”,
“chart.js”: “^3.8.0”,
“com-badrit-base64”: “github:hazemhagrass/phonegap-base64”,
“cordova-plugin-advanced-http”: “^3.3.1”,
“cordova-plugin-android-permissions”: “^1.1.5”,
“cordova-plugin-app-version”: “^0.1.14”,
“cordova-plugin-background-mode”: “^0.7.3”,
“cordova-plugin-camera”: “^7.0.0”,
“cordova-plugin-camera-preview”: “^0.12.3”,
“cordova-plugin-chooser”: “^1.3.2”,
“cordova-plugin-crop”: “^0.4.0”,
“cordova-plugin-device”: “^2.1.0”,
“cordova-plugin-document-scanner”: “^4.2.7”,
“cordova-plugin-file”: “^8.1.3”,
“cordova-plugin-file-opener2”: “^4.0.0”,
“cordova-plugin-file-transfer”: “github:apache/cordova-plugin-file-transfer”,
“cordova-plugin-filepath”: “^1.6.0”,
“cordova-plugin-fingerprint-aio”: “^5.0.1”,
“cordova-plugin-inappbrowser”: “^5.0.0”,
“cordova-plugin-keyboard-scroll”: “^0.0.2”,
“cordova-plugin-multiple-documents-picker”: “^1.0.0”,
“cordova-plugin-preview-any-file”: “^0.2.9”,
“firebase”: “^10.3.0”,
“hammerjs”: “^2.0.8”,
“integrator-cordova-plugin-downloader”: “^1.1.0”,
“ion2-calendar”: “^3.5.0”,
“ionic-selectable”: “^4.9.0”,
“jquery”: “^3.6.0”,
“moment”: “^2.29.4”,
“ng2-charts”: “^3.1.2”,
“ng2-file-upload”: “^1.4.0”,
“ngx-device-detector”: “^3.0.0”,
“ngx-ionic-image-viewer”: “^0.7.5”,
“rxjs”: “~6.6.0”,
“timeago.js”: “^4.0.2”,
“tslib”: “^2.2.0”,
“zone.js”: “~0.11.4”
},
“devDependencies”: {
“@angular-devkit/build-angular”: “~13.2.3”,
“@angular-eslint/builder”: “~13.0.1”,
“@angular-eslint/eslint-plugin”: “~13.0.1”,
“@angular-eslint/eslint-plugin-template”: “~13.0.1”,
“@angular-eslint/template-parser”: “~13.0.1”,
“@angular/cli”: “~13.2.3”,
“@angular/compiler”: “~13.2.2”,
“@angular/compiler-cli”: “~13.2.2”,
“@angular/language-service”: “~13.2.2”,
“@capacitor/cli”: “^5.0.0”,
“@ionic/angular-toolkit”: “^6.0.0”,
“@types/googlemaps”: “^3.43.3”,
“@types/jasmine”: “~3.6.0”,
“@types/jasminewd2”: “~2.0.3”,
“@types/jquery”: “^3.5.14”,
“@types/node”: “^12.11.1”,
“@typescript-eslint/eslint-plugin”: “5.3.0”,
“@typescript-eslint/parser”: “5.3.0”,
“eslint”: “^7.6.0”,
“eslint-plugin-import”: “2.22.1”,
“eslint-plugin-jsdoc”: “30.7.6”,
“eslint-plugin-prefer-arrow”: “1.2.2”,
“jasmine-core”: “~3.8.0”,
“jasmine-spec-reporter”: “~5.0.0”,
“jetifier”: “^2.0.0”,
“karma”: “~6.3.2”,
“karma-chrome-launcher”: “~3.1.0”,
“karma-coverage”: “~2.0.3”,
“karma-coverage-istanbul-reporter”: “~3.0.2”,
“karma-jasmine”: “~4.0.0”,
“karma-jasmine-html-reporter”: “^1.5.0”,
“protractor”: “~7.0.0”,
“ts-node”: “~8.3.0”,
“typescript”: “^4.1.5”
},
“description”: “An Ionic project”
}

Check LogCat in Android Studio for any errors.

Capacitor 5 is no longer supported so you’re best bet would be to upgrade to 6 or 7.

You are also using v6 of @capacitor/filesystem with Capacitor 5. You cannot mismatch major versions.

@ionic-native is also dead - A New Chapter for @ionic-native - Ionic Blog

Thank you for the update.
Migrating to capacitor 6 or 7 will be a complex one or just updating the capacitor version will be sufficient enough

Notifications have changed a lot in the last years specially related to them requiring permissions now and that could cause crashes on app startup. So if you are using Capacitor 5 the crash is most likely caused by firebase dependencies being out of date and not handling those permissions. You could start by adding a firebaseMessagingVersion variable in variables.gradle file and setting it to 24.1.0, which is the version used as default in version 7 of @capacitor/push-notifications.
But updating to Capacitor 7 and @capacitor/push-notifications 7 is highly recommended as updating the dependency without updating the plugin could also cause other issues.

1 Like