Skip to content

Predictive back can close app when navigation stack is not empty #145290

@Geara0

Description

@Geara0

Steps to reproduce

  1. add android:enableOnBackInvokedCallback="true" to main/AndroidManifest.xml
  2. run the code below
  3. go to /home/second by tapping IconButton
  4. open modalBottomSheet by tapping IconButton
  5. swipe to go back -> modalBottomSheet closes
  6. swipe to go back -> app exits

Expected results

after step 6 we should be at /home page
(and if there is no android:enableOnBackInvokedCallback="true" - bug doesn't appear)

Actual results

after step 6 we go to desktop

Code sample

Code sample
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    final dispatcher = BackDispatcher();
    return MaterialApp.router(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      // routerConfig: router,
      routerDelegate: router.routerDelegate,
      routeInformationProvider: router.routeInformationProvider,
      routeInformationParser: router.routeInformationParser,
      backButtonDispatcher: dispatcher,
    );
  }
}

class BackDispatcher extends RootBackButtonDispatcher {
  @override
  Future<bool> didPopRoute() async {
    if (modalStack.isNotEmpty) {
      debugPrint('popping modal');
      Navigator.of(navKey.currentContext!).pop();
      return true;
    }

    return super.didPopRoute();
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('home page'),
      ),
      body: Center(
        child: IconButton(
          onPressed: () => context.go('/home/second'),
          icon: const Icon(Icons.link),
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  const SecondPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('second page'),
      ),
      body: Center(
        child: IconButton(
          onPressed: () {
            showModalBottomSheet(
              context: context,
              useRootNavigator: true,
              builder: (context) {
                return Container(
                  width: 100,
                  height: 100,
                  color: Colors.red,
                );
              },
            );
          },
          icon: const Icon(Icons.slideshow),
        ),
      ),
    );
  }
}

class Layout extends StatelessWidget {
  const Layout(
    this.shell, {
    super.key,
  });

  final StatefulNavigationShell shell;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(child: shell),
        Container(
          height: 10,
          color: Colors.blueGrey,
        ),
      ],
    );
  }
}

final modalStack = <Route>[];

class MyObserver extends RouteObserver {
  @override
  void didPush(Route route, Route? previousRoute) {
    if (previousRoute == null) return;
    debugPrint('!!! didPush ${route.runtimeType}');
    modalStack.add(route);
    super.didPush(route, previousRoute);
  }

  @override
  void didPop(Route route, Route? previousRoute) {
    debugPrint('!!! didPop ${route.runtimeType}');
    modalStack.removeLast();
    super.didPop(route, previousRoute);
  }
}

final navKey = GlobalKey<NavigatorState>();
GoRouter router = GoRouter(
  debugLogDiagnostics: true,
  observers: [MyObserver()],
  initialLocation: '/home',
  navigatorKey: navKey,
  routes: [
    GoRoute(
      path: '/',
      redirect: (_, state) {
        return state.fullPath == '/' ? '/home' : null;
      },
      routes: [
        StatefulShellRoute.indexedStack(
          builder: (context, state, shell) => Layout(shell),
          branches: [
            StatefulShellBranch(
              routes: [
                GoRoute(
                  path: 'home',
                  builder: (context, _) => const MyHomePage(),
                  routes: [
                    GoRoute(
                      path: 'second',
                      builder: (context, _) => const SecondPage(),
                    ),
                  ],
                ),
              ],
            ),
          ],
        ),
      ],
    ),
  ],
);

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.19.3, on macOS 14.3.1 23D60 darwin-arm64, locale en-RU)
    • Flutter version 3.19.3 on channel stable at /opt/homebrew/Caskroom/flutter/3.10.4/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision ba39319843 (10 days ago), 2024-03-07 15:22:21 -0600
    • Engine revision 2e4ba9c6fb
    • Dart version 3.3.1
    • DevTools version 2.31.1

[!] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/geara0/Library/Android/sdk
    ✗ cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.

[✓] Xcode - develop for iOS and macOS (Xcode 15.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15C500b
    • CocoaPods version 1.15.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2023.1)
    • Android Studio at /Users/geara0/Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314)

[✓] IntelliJ IDEA Ultimate Edition (version 2023.1.1)
    • IntelliJ at /Users/geara0/Applications/IntelliJ IDEA Ultimate.app
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] VS Code (version 1.87.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.84.0

[✓] Connected device (4 available)
    • M2101K6G (mobile)           • 79a46fc6      • android-arm64  • Android 13 (API 33)
    • sdk gphone64 arm64 (mobile) • emulator-5554 • android-arm64  • Android 14 (API 34) (emulator)
    • macOS (desktop)             • macos         • darwin-arm64   • macOS 14.3.1 23D60 darwin-arm64
    • Chrome (web)                • chrome        • web-javascript • Google Chrome 122.0.6261.129
    ! Error: Browsing on the local area network for iPhone HOME. Ensure the device is unlocked and attached with a cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 1 category.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listf: routesNavigator, Router, and related APIs.found in release: 3.19Found to occur in 3.19found in release: 3.21Found to occur in 3.21frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: go_routerThe go_router packageplatform-androidAndroid applications specificallyteam-frameworkOwned by Framework teamtriaged-frameworkTriaged by Framework teamworkaround availableThere is a workaround available to overcome the issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions