Getting the Android hardware back button working

I’ve followed the detailed documentation, I’ve added the code to my app and when I run it with the Chrome debugger attached I can see the listener is called:
image
But… nothing is logged to the console and no navigation happens.

I’ve added the code to my main src/App.vue and it looks like

<template>
  <ion-app>
    <ion-router-outlet />
  </ion-app>
</template>

<script lang="ts">
import {
  IonApp,
  IonRouterOutlet,
  useBackButton,
  useIonRouter,
} from "@ionic/vue";
import { defineComponent, onMounted } from "vue";
import { useRouter } from "vue-router";
import { Plugins } from "@capacitor/core";
const { coreApp } = Plugins;

export default defineComponent({
  name: "App",
  components: {
    IonApp,
    IonRouterOutlet,
  },
  setup() {
    const ionRouter = useIonRouter();
    const router = useRouter();
    useBackButton(10, (processNextHandler) => {
      console.log("useBackButton handler was called!");
      if (ionRouter.canGoBack()) {
        console.log("Go back");
        router.back();
      }
      processNextHandler();
    });
    // I can combine these into one listener, but for testing - using 2
    useBackButton(-1, () => {
      if (!ionRouter.canGoBack()) {
        console.log("Exit app");
        coreApp.exitApp();
      }
    });
  },
});
</script>

What have I missed? I’m running @ionic/vue@5.8.4 and @ionic/vue-router@5.8.4 and the full dependencies section is below (I need to update everything)

{
  "dependencies": {
    "@capacitor-community/camera-preview": "file:../camera-preview",
    "@capacitor/android": "^3.2.0",
    "@capacitor/app": "1.0.2",
    "@capacitor/camera": "^1.0.3",
    "@capacitor/core": "^3.1.2",
    "@capacitor/haptics": "1.0.2",
    "@capacitor/ios": "3.2.0",
    "@capacitor/keyboard": "1.0.2",
    "@capacitor/network": "^1.0.2",
    "@capacitor/splash-screen": "^1.1.2",
    "@capacitor/status-bar": "1.0.2",
    "@ionic-native/app-version": "^5.36.0",
    "@ionic/pwa-elements": "^3.0.2",
    "@ionic/vue": "^5.8.4",
    "@ionic/vue-router": "^5.8.4",
    "@types/uuid": "^8.3.1",
    "animate.css": "^4.1.1",
    "class-transformer": "^0.4.0",
    "cordova-plugin-app-version": "^0.1.12",
    "core-js": "^3.6.5",
    "dayjs": "^1.10.6",
    "image-blob-reduce": "^3.0.1",
    "prettier": "^2.3.2",
    "reflect-metadata": "^0.1.13",
    "uuid": "^8.3.2",
    "vue": "^3.0.0-0",
    "vue-router": "^4.0.0-0"
  },
  "devDependencies": {
    "@capacitor/cli": "^3.1.2",
    "@types/jest": "^24.0.19",
    "@typescript-eslint/eslint-plugin": "^2.33.0",
    "@typescript-eslint/parser": "^2.33.0",
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-e2e-cypress": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-plugin-router": "~4.5.0",
    "@vue/cli-plugin-typescript": "~4.5.0",
    "@vue/cli-plugin-unit-jest": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "@vue/compiler-sfc": "^3.0.0-0",
    "@vue/eslint-config-typescript": "^5.0.2",
    "@vue/test-utils": "^2.0.0-0",
    "capacitor-resources": "^2.0.5",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^7.0.0-0",
    "typescript": "~3.9.3",
    "vue-jest": "^5.0.0-0"
  },
}

Can you send over a sample application that I can run on my machine?

@ldebeasi Sure thing. GitHub - pbowyer/ionic-android-hardware-back-button and instructions on the app’s Home screen.

The listener is at least called which is better than my “real” app.

I did first create a demo based on the sidemenu template and that closed the app on every hardware back button press, so I made this one instead.

There are a couple problems here:

  1. You do not need to do router.back() yourself. This functionality is built into Ionic. Your handler has a higher priority than Ionic’s built in navigation handler, so yours gets called first. Since you call processNextHandler, Ionic’s navigation handler gets called, and the app navigates again.
  2. There was a bug introduced in Ionic Vue 5.6.14 which results in ionRouter.canGoBack() not returning the correct result. I have filed an issue here and will look into a fix: bug: vue, ionRouter.canGoBack not working after 5.6.14 · Issue #24109 · ionic-team/ionic-framework · GitHub. You can work around this by staying on Ionic Vue 5.6.13 for now.

Ahh thank you. So you have to call useBackButton in order to enable this functionality, but once you do the navigating back is magically handled.

I see others have missed this too, as a GitHub usage search (which I did to see what I was doing wrong) has examples calling router.back() e.g. this one.

Which now makes sense given the navigating back is automatic… :+1:

Thanks! I will roll back to 5.6.13.

Ah, 5.6.13 of which package? @ionic/vue is on 5.8 so hoping it doesn’t have to be rolled back so far

Hardware Back Button functionality is enabled regardless of your usage of useBackButton, though you can disable it via a config option: Config - Ionic Documentation. The useBackButton feature is there to provide for more advanced usage of the back button that Ionic does not cover automatically.

The Hardware Back Button Docs go into this a bit more, but to summarize Ionic handles three things automatically:

  1. Closing overlays (modals, popovers, alerts, etc)
  2. Closing menus.
  3. Navigating backwards to a previous page.

Ah, 5.6.13 of which package? @ionic/vue is on 5.8 so hoping it doesn’t have to be rolled back so far

I recommend updating both @ionic/vue and @ionic/vue-router. I plan on taking a look at this issue this week though, so hopefully you should not have to roll back for too long.

I see why I’m confused: since I started this Ionic Vue app in June/July the hardware back button has never worked. I thought this was because I hadn’t called useBackButton.

It’s great to hear you plan to look at the issue this week; I’ll hold off rolling back in the expectation it’s soon fixed.

Ah interesting. Are you using Capacitor? With the Capacitor 3 migration, the @capacitor/app plugin needs to be installed for hardware back button to work.

Also I have a experimental build of the Ionic Vue fix for the hardware back button if you are interested in testing it out:

npm install @ionic/vue@5.9.0-dev.202110251709.f0e844d @ionic/vue-router@5.9.0-dev.202110251709.f0e844d

Thank you, that’s working for me :smiley:

1 Like

Thanks for testing! This should be fixed in an upcoming release of Ionic.