Handling hardware back button in Ionic3 Vs Ionic4

Try This: app.comonent.ts

import { Component, ViewChildren, QueryList } from '@angular/core';
import { Platform, ModalController, ActionSheetController, PopoverController, IonRouterOutlet, MenuController } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';
import { Router } from '@angular/router';
import { Toast } from '@ionic-native/toast/ngx';

@Component({
    selector: 'app-root',
    templateUrl: 'app.component.html'
})
export class AppComponent {

    // set up hardware back button event.
    lastTimeBackPress = 0;
    timePeriodToExit = 2000;

    @ViewChildren(IonRouterOutlet) routerOutlets: QueryList<IonRouterOutlet>;

    constructor(
        private platform: Platform,
        private splashScreen: SplashScreen,
        private statusBar: StatusBar,
        public modalCtrl: ModalController,
        private menu: MenuController,
        private actionSheetCtrl: ActionSheetController,
        private popoverCtrl: PopoverController,
        private router: Router,
        private toast: Toast) {

        // Initialize app
        this.initializeApp();

        // Initialize BackButton Eevent.
        this.backButtonEvent();
    }

    // active hardware back button
    backButtonEvent() {
        this.platform.backButton.subscribe(async () => {
            // close action sheet
            try {
                const element = await this.actionSheetCtrl.getTop();
                if (element) {
                    element.dismiss();
                    return;
                }
            } catch (error) {
            }

            // close popover
            try {
                const element = await this.popoverCtrl.getTop();
                if (element) {
                    element.dismiss();
                    return;
                }
            } catch (error) {
            }

            // close modal
            try {
                const element = await this.modalCtrl.getTop();
                if (element) {
                    element.dismiss();
                    return;
                }
            } catch (error) {
                console.log(error);

            }

            // close side menua
            try {
                const element = await this.menu.getOpen();
                if (element) {
                    this.menu.close();
                    return;

                }

            } catch (error) {

            }

            this.routerOutlets.forEach((outlet: IonRouterOutlet) => {
                if (outlet && outlet.canGoBack()) {
                    outlet.pop();

                } else if (this.router.url === '/home') {
                    if (new Date().getTime() - this.lastTimeBackPress < this.timePeriodToExit) {
                        // this.platform.exitApp(); // Exit from app
                        navigator['app'].exitApp(); // work in ionic 4

                    } else {
                        this.toast.show(
                            `Press back again to exit App.`,
                            '2000',
                            'center')
                            .subscribe(toast => {
                                // console.log(JSON.stringify(toast));
                            });
                        this.lastTimeBackPress = new Date().getTime();
                    }
                }
            });
        });
    }
}

it's work for me, in ionic v4 beta


Update: This was fixed in v4.0.0-beta.8 (dfac9dc)


Related: ionic4 replacement for registerBackButtonAction


This is tracked on GitHub, in the Iconic Forum and Twitter
Until there is an official fix, you can use the workaround below.


Using platform.backButton.subscribe (see here) platform.backButton.subscribeWithPriority(0, ...) to let ionic handle closing all the modals/alerts/... , the code ionic uses when its own back button is pressed and the new router-controller together we get something like this:

import { ViewChild } from '@angular/core';
import { IonRouterOutlet, Platform } from '@ionic/angular';
import { Router } from '@angular/router';

//...

/* get a reference to the used IonRouterOutlet 
assuming this code is placed in the component
that hosts the main router outlet, probably app.components */
@ViewChild(IonRouterOutlet) routerOutlet: IonRouterOutlet;

constructor(
  ...
  /* if this is inside a page that was loaded into the router outlet,
  like the start screen of your app, you can get a reference to the 
  router outlet like this:
  @Optional() private routerOutlet: IonRouterOutlet, */
  private router: Router,
  private platform: Platform
  ...
) {
  this.platform.backButton.subscribeWithPriority(0, () => {
    if (this.routerOutlet && this.routerOutlet.canGoBack()) {
      this.routerOutlet.pop();
    } else if (this.router.url === '/LoginPage') {
      this.platform.exitApp(); 

      // or if that doesn't work, try
      navigator['app'].exitApp();
    } else {
      this.generic.showAlert("Exit", "Do you want to exit the app?", this.onYesHandler, this.onNoHandler, "backPress");
    }
  });
}

This is my working code on the Ionic 5 Project. using Cordova/PhoneGap

import {Component} from '@angular/core';
import {ToastService} from './_services/toast.service';

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss']
})
export class AppComponent {
  constructor(private toastCtrl: ToastService) {
    this.backButton();
  }
  backButton() {
      const that = this;
      let lastTimeBackPress = 0;
      const timePeriodToExit = 2000;
      function onBackKeyDown(e) {
          e.preventDefault();
          e.stopPropagation();
          if (new Date().getTime() - lastTimeBackPress < timePeriodToExit) {
              navigator.app.exitApp();
          } else {
              that.presentToast();
              lastTimeBackPress = new Date().getTime();
          }
      }
      document.addEventListener('backbutton', onBackKeyDown, false);
  }
  presentToast() {
    const toast = this.toastCtrl.create({
      message: "Press again to exit",
      duration: 3000,
      position: "middle"
    });
  toast.present();
  }
}

Tags:

Ionic3

Ionic4