catch Android back button event on Flutter

AndroidDartFlutter

Android Problem Overview


Is there any way I can catch the onBackPressed event from Android back button?

I've tried the WillPopScope but my onWillPop function only triggered when I tap on the Material back arrow button

I put it like this:

class MyView extends StatelessWidget{

Widget build(BuildContext context) {

    return new WillPopScope(
      onWillPop: () async {
        debugPrint("Will pop");
        return true;
      },
      child: ScopedModel<AppModel>(
      model: new AppModel(),
      child: new Scaffold(......

I need to catch it because somehow my screen behaved incorrectly when it came to back button pressed, it pops the screen and the screen below it, but somehow, using material back arrow button works normal.

Update:

The code works, my problem was not in the pop of this screen, but on the previous screen, I use 2 MaterialApp widgets, and somehow it gave a weird behavior.

Android Solutions


Solution 1 - Android

In order to prevent navigating back WillPopScope is the correct way and should be used as follow:

class Page2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new WillPopScope(
      child: new Scaffold(
        appBar: new AppBar(
          title: new Text('Page 2'),
        ),
        body: new Center(
          child: new Text('PAGE 2'),
        ),
      ),
      onWillPop: () async {
        return false;
      },
    );
  }
}

Future<T> pushPage<T>(BuildContext context, Widget page) {
  return Navigator.of(context)
      .push<T>(MaterialPageRoute(builder: (context) => page));
}

Can call the page like:

pushPage(context, Page2());

Solution 2 - Android

This is should be helpful.

@override
Widget build(BuildContext context) {
  return WillPopScope(
    onWillPop: () {
      _moveToScreen2(context, );
    },
    child: Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        leading: IconButton(
            icon: Icon(Icons.arrow_back),
            onPressed: () {
              _moveToScreen2(context);
            }),
        title: Text("Screen 1"),
      ),
    ),
  );
}

/**
* This is probably too thin to be in its own method - consider using
* `Navigator.pushReplacementNamed(context, "screen2")` directly
*/
void _moveToScreen2(BuildContext context) =>
    Navigator.pushReplacementNamed(context, "screen2");

Solution 3 - Android

Use WillPopScope method and return false

@override
Widget build(BuildContext context) {
  return WillPopScope(
     onWillPop: () async {
        // Do something here
        print("After clicking the Android Back Button");
        return false;
     },
     child: Scaffold(
       appBar: AppBar(
          title: Text("Handling the back button"),
       ),
       body: Center(
          child: Text("Body"),
       ),
    ),
  );
}

Solution 4 - Android

This code work for me.

I think there may be two reasons.

  1. Child of WillPopScope is Scaffold

  2. No return in onWillPop

    return new WillPopScope(
      onWillPop: () {
        if (!_isOpened) Navigator.pop(context);
      },
      child: new Scaffold(
        key: SharedService.orderScaffoldKey,
        appBar: appBar,
        body: new Builder(
          builder: (BuildContext context) {
            return page;
          },
        ),
      ),
    );
    

Solution 5 - Android

Just adding an important point here. Please note that by using WillPopScope, we will lose the back swipe gesture on iOS.

Reference: https://github.com/flutter/flutter/issues/14203

Solution 6 - Android

Another way todo this is to implement a NavigatorObserver and link it to the MaterialApp:

https://api.flutter.dev/flutter/widgets/RouteObserver-class.html

You don't have to use RouteAware, you can also implement your own NavigatorObserver.

This is for example how Flutter analytics works to automatically track screen opens/closes:

        MaterialApp(
          ...
          navigatorObservers: [
           FirebaseAnalyticsObserver(analytics: analytics),
          ],
        )

FirebaseAnalyticsObserver extends the RouteObserver which itself implements NavigatorObserver.

However WillPopScope is often the easier solution

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRizky AndriawanView Question on Stackoverflow
Solution 1 - AndroidArnold PargeView Answer on Stackoverflow
Solution 2 - AndroidMitchView Answer on Stackoverflow
Solution 3 - AndroidThiran HettiarachchiView Answer on Stackoverflow
Solution 4 - Android蔡旻袁View Answer on Stackoverflow
Solution 5 - AndroidMohammed SadiqView Answer on Stackoverflow
Solution 6 - AndroidTjerkWView Answer on Stackoverflow