May be used to intercept the Android back-button, as an alternative to `WillPopScope`.

Overview

pub package

back_button_interceptor

In simple cases, when you need to intercept the Android back-button, you usually add WillPopScope to your widget tree. However, when developing stateful widgets that interact with the back button, it's more convenient to use the BackButtonInterceptor.

You may add interceptor functions to be called when the back button is tapped. These functions may perform some useful work, and then, if any of them return true, the default button process ( usually popping a Route) will not be fired.

In more detail: All added functions are called, in order. If any function returns true, the combined result is true, and the default button process will NOT be fired. Only if all functions return false (or null), the combined result is false, and the default button process will be fired.

Optionally, you may provide a z-index. Functions with a valid z-index will be called before functions with a null z-index, and functions with larger z-index will be called first. When they have the same z-index, functions added last are called first.

Each function gets the boolean stopDefaultButtonEvent that indicates the current combined result from all the previous functions. So, if some function doesn't want to fire if some other previous function already fired, it can do:

if (stopDefaultButtonEvent) return false;

The same result may be obtained if the optional ifNotYetIntercepted parameter is true. Then the function will only be called if all previous functions returned false (that is, if stopDefaultButtonEvent is false).

Notes

  • After you've finished you MUST remove each function by calling the remove() method. Alternatively, you may also provide a name when adding a function, and then later remove it by calling the removeByName(name) method.

  • If any of your interceptors throw an error, the error message will be printed to the console, but the error thrown will be a general error with not much information. You can change the treatment of errors by changing the static errorProcessing field.

  • Your functions can also process information about routes by using the function's RouteInfo info parameter. To get the current route in the navigator, call info.currentRoute(context). Also, info.routeWhenAdded contains the route that was the current one when the interceptor was added through the BackButtonInterceptor.add() method.

  • You can set up some function so that it only runs when the current route is the same route of when the interceptor was created. To that end, you can use info.ifRouteChanged() method:

    bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) {    
      if (info.ifRouteChanged(context)) return false;
      ...
    }    
    

    This means the interceptor function is temporarily disabled while, for example, a dialog is open.

  • You can set up some function so that it only runs in certain routes:

    bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) {    
      if (["myRoute1", "myRoute2", "myRoute3"]
         .contains(info.currentRoute(context))) return false;
      ...
    }    
    
  • Both info.routeWhenAdded and info.ifRouteChanged() only work if you passed the context parameter to the BackButtonInterceptor.add() method. Otherwise, info.routeWhenAdded will be null and info.ifRouteChanged() will thrown an error.

  • The current route can also be obtained by using the static method BackButtonInterceptor.getCurrentNavigatorRouteName(context).

  • The interceptor function can return bool or Future .

Import the package

Add back_button_interceptor as a dependency in your pubspec.yaml. Then, import it:

import 'package:back_button_interceptor/back_button_interceptor.dart';

Examples

Intercepting

@override
void initState() {
   super.initState();
   BackButtonInterceptor.add(myInterceptor);
}

@override
void dispose() {
   BackButtonInterceptor.remove(myInterceptor);
   super.dispose();
}

bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) {
   print("BACK BUTTON!"); // Do some stuff.
   return true;
}

Named function and z-index

@override
void initState() {
   super.initState();
   BackButtonInterceptor.add(myInterceptor, zIndex:2, name:"SomeName");
}

@override
void dispose() {
   BackButtonInterceptor.removeByName("SomeName");
   super.dispose();
}

bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) {
   print("BACK BUTTON!"); // Do some stuff.
   return true;
}

Runnable Examples

  1. main

    Intercepts the back-button and prints a string to the console.

  2. main

    Intercepts the back-button and prints a string to the console, by using an async interceptor function.

  3. main_complex_example

    The first screen has a button which opens a second screen. The second screen has 3 red squares. By tapping the Android back-button (or the "pop" button) each square turns blue, one by one. Only when all squares are blue, tapping the back-button once more will return to the previous screen. Also, if you click the "Open Dialog" button, the interceptors are disabled while the dialog is open.

  4. main_complex_example_test

    This package is test friendly, and this examples shows how to test the back button.

Testing

For testing purposes, the BackButtonInterceptor.popRoute() method may be called directly, to simulate pressing the back button. The list of all fired functions and their results is
recorded in the BackButtonInterceptor.results static variable.

Note: You may want to add BackButtonInterceptor.removeAll(); to your test's setUp function, so that you remove old interceptors between tests.

Debugging

In complex cases, to make it easier for you to debug your interceptors, you may print them to the console, with their names and z-indexes, by doing:

print(BackButtonInterceptor.describe());

See also:


The Flutter packages I've authored:

My Medium Articles:

My article in the official Flutter documentation:


Marcelo Glasberg:
https://github.com/marcglasberg
https://twitter.com/glasbergmarcelo
https://stackoverflow.com/users/3411681/marcg
https://medium.com/@marcglasberg

Comments
  • version 5.1.0 compile fail

    version 5.1.0 compile fail

    console message

    ../../development/flutter/.pub-cache/hosted/pub.dartlang.org/back_button_interceptor-5.1.0/lib/src/back_button_interceptor.dart:30:31: Error: Property 'handlePopRoute' cannot be accessed on 'WidgetsBinding?' because it is potentially null.
         - 'WidgetsBinding' is from 'package:flutter/src/widgets/binding.dart' ('../../development/flutter/packages/flutter/lib/src/widgets/binding.dart').
        Try accessing using ?. instead.
              WidgetsBinding.instance.handlePopRoute;
                                      ^^^^^^^^^^^^^^
    

    WidgetsBinding.instance is null safety

    opened by MagicalWater 5
  • Version 6.0.0 causes an error when the Dart SDK version is less than 1.17.0

    Version 6.0.0 causes an error when the Dart SDK version is less than 1.17.0

    WidgetsBinding.instance was changed to non-nullable in flutter3.0. So, if the Dart SDK is less than 2.17.0, it will be treated as nullable. Therefore Version 6.0.0 only supports Dart SDK 2.17.0 or higher. I'm not good at English, so it may be hard to read, but thanks in advance.

    opened by yukisakai1225 4
  • Debug mode / Release APK

    Debug mode / Release APK

    Hi,

    In debug mode, using VC Studio, the plugin is working as expected: the function is running when the back button is pressed. But when I build the app, the function is not running anymore. (Back Button is disabled, but it doesn't launch the function onPressed)

    I tried to flutter clean and create a new build but I got the same issue. Some special permission is needed in the Manifest?

    question 
    opened by Icesofty 4
  • A null exception occures during debug run in this package

    A null exception occures during debug run in this package

    Steps to Reproduce

    1. Install flutter 2.10.5
    2. Install Android SDK 29
    3. Clone medito-app
    4. Install packages with pub
    5. Start android emulator or connect phone
    6. Run project in debug mode Expected results: The app up and running in the emulator or phone

    Actual results: A null exception during build

    Logs

    Launching lib/main.dart on Android SDK built for x86 64 in debug mode... The app could not be configured for release signing. In app purchases will not be testable. Seeexample/README.md` for more info and instructions. : Error: Property 'handlePopRoute' cannot be accessed on 'WidgetsBinding?' because it is potentially null.

    • 'WidgetsBinding' is from 'package:flutter/src/widgets/binding.dart' ('../../../../Documents/flutter/packages/flutter/lib/src/widgets/binding.dart').

    Try accessing using ?. instead. WidgetsBinding.instance.handlePopRoute; ^^^^^^^^^^^^^^ : Error: Property 'handlePushRoute' cannot be accessed on 'WidgetsBinding?' because it is potentially null.

    • 'WidgetsBinding' is from 'package:flutter/src/widgets/binding.dart' ('../../../../Documents/flutter/packages/flutter/lib/src/widgets/binding.dart'). Try accessing using ?. instead. WidgetsBinding.instance.handlePushRoute as Future Function(String?); ^^^^^^^^^^^^^^^

    FAILURE: Build failed with an exception.

    • Where: Script '/Users/atharvajagtap/Documents/flutter/packages/flutter_tools/gradle/flutter.gradle' line: 1102
    • What went wrong: Execution failed for task ':app:compileFlutterBuildDebug'.

    Process 'command '/Users/atharvajagtap/Documents/flutter/bin/flutter'' finished with non-zero exit value 1

    • Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
    • Get more help at https://help.gradle.org/

    BUILD FAILED in 1m 42s Exception: Gradle task assembleDebug failed with exit code 1 Exited (sigterm)`

       info • Unnecessary cast • lib/audioplayer/download_class.dart:83:38 • unnecessary_cast
       info • 'accentColor' is deprecated and shouldn't be used. Use colorScheme.secondary instead. For more information, consult
              the migration guide at
              https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. This feature was
              deprecated after v2.3.0-0.1.pre. • lib/main.dart:111:11 • deprecated_member_use
       info • This class (or a class that this class inherits from) is marked as '@immutable', but one or more of its instance
              fields aren't final: ApiResponse.status, ApiResponse.body, ApiResponse.message • lib/network/api_response.dart:18:7 •
              must_be_immutable
       info • 'data' is deprecated and shouldn't be used. Use values below • lib/network/folder/folder_response.dart:21:23 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use values below • lib/network/folder/folder_response.dart:23:23 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use values below • lib/network/folder/folder_response.dart:25:29 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use values below • lib/network/folder/folder_response.dart:26:24 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use values below • lib/network/folder/folder_response.dart:27:36 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use values below • lib/network/folder/folder_response.dart:28:23 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use values below • lib/network/folder/folder_response.dart:31:20 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use values below • lib/network/folder/folder_response.dart:33:27 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use values below • lib/network/folder/folder_response.dart:38:5 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use values below • lib/network/folder/folder_response.dart:44:27 •
              deprecated_member_use_from_same_package
       info • 'idInt' is deprecated and shouldn't be used. Use id instead • lib/network/folder/folder_response.dart:110:20 •
              deprecated_member_use_from_same_package
       info • 'idInt' is deprecated and shouldn't be used. Use id instead • lib/network/folder/folder_response.dart:131:5 •
              deprecated_member_use_from_same_package
       info • 'idInt' is deprecated and shouldn't be used. Use id instead • lib/network/folder/folder_response.dart:140:18 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. User title and body instead •
              lib/network/home/daily_message_response.dart:5:23 • deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. User title and body instead •
              lib/network/home/daily_message_response.dart:7:22 • deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. User title and body instead •
              lib/network/home/daily_message_response.dart:12:5 • deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. User title and body instead •
              lib/network/home/daily_message_response.dart:17:14 • deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. User title and body instead •
              lib/network/home/daily_message_response.dart:18:27 • deprecated_member_use_from_same_package
       info • Unused import: 'package:connectivity/connectivity.dart' • lib/network/home/home_bloc.dart:22:8 • unused_import
       info • 'data' is deprecated and shouldn't be used. Use fields instead • lib/network/packs/announcement_response.dart:5:22 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use fields instead • lib/network/packs/announcement_response.dart:7:30 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use fields instead • lib/network/packs/announcement_response.dart:9:22 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use fields instead • lib/network/packs/announcement_response.dart:11:29 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use fields instead • lib/network/packs/announcement_response.dart:13:28 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use fields instead • lib/network/packs/announcement_response.dart:15:28 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use fields instead • lib/network/packs/announcement_response.dart:17:27 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use fields instead • lib/network/packs/announcement_response.dart:19:20 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use fields instead • lib/network/packs/announcement_response.dart:24:5 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. Use fields instead • lib/network/packs/announcement_response.dart:30:27 •
              deprecated_member_use_from_same_package
       info • 'coverOld' is deprecated and shouldn't be used. Use cover instead • lib/network/packs/packs_response.dart:47:23 •
              deprecated_member_use_from_same_package
       info • 'backgroundImage' is deprecated and shouldn't be used. Use backgroundImageUrl •
              lib/network/packs/packs_response.dart:51:36 • deprecated_member_use_from_same_package
       info • 'backgroundImage' is deprecated and shouldn't be used. Use backgroundImageUrl •
              lib/network/packs/packs_response.dart:82:5 • deprecated_member_use_from_same_package
       info • 'coverOld' is deprecated and shouldn't be used. Use cover instead • lib/network/packs/packs_response.dart:85:5 •
              deprecated_member_use_from_same_package
       info • 'backgroundImage' is deprecated and shouldn't be used. Use backgroundImageUrl •
              lib/network/packs/packs_response.dart:94:32 • deprecated_member_use_from_same_package
       info • 'coverOld' is deprecated and shouldn't be used. Use cover instead • lib/network/packs/packs_response.dart:97:21 •
              deprecated_member_use_from_same_package
       info • The value of the field '_screen' isn't used • lib/network/session_options/session_options_bloc.dart:37:10 •
              unused_field
       info • The value of the local variable 'options' isn't used • lib/network/session_options/session_options_bloc.dart:110:9 •
              unused_local_variable
       info • 'backgroundImage' is deprecated and shouldn't be used. Use backgroundImageUrl instead •
              lib/network/session_options/session_opts.dart:30:36 • deprecated_member_use_from_same_package
       info • 'author' is deprecated and shouldn't be used. use attribution instead •
              lib/network/session_options/session_opts.dart:33:29 • deprecated_member_use_from_same_package
       info • 'audio' is deprecated and shouldn't be used. use files instead • lib/network/session_options/session_opts.dart:34:32
              • deprecated_member_use_from_same_package
       info • 'backgroundImage' is deprecated and shouldn't be used. Use backgroundImageUrl instead •
              lib/network/session_options/session_opts.dart:64:5 • deprecated_member_use_from_same_package
       info • 'author' is deprecated and shouldn't be used. use attribution instead •
              lib/network/session_options/session_opts.dart:67:5 • deprecated_member_use_from_same_package
       info • 'audio' is deprecated and shouldn't be used. use files instead • lib/network/session_options/session_opts.dart:70:7 •
              deprecated_member_use_from_same_package
       info • 'audio' is deprecated and shouldn't be used. use files instead • lib/network/session_options/session_opts.dart:72:9 •
              deprecated_member_use_from_same_package
       info • 'backgroundImage' is deprecated and shouldn't be used. Use backgroundImageUrl instead •
              lib/network/session_options/session_opts.dart:85:32 • deprecated_member_use_from_same_package
       info • 'author' is deprecated and shouldn't be used. use attribution instead •
              lib/network/session_options/session_opts.dart:89:9 • deprecated_member_use_from_same_package
       info • 'author' is deprecated and shouldn't be used. use attribution instead •
              lib/network/session_options/session_opts.dart:90:24 • deprecated_member_use_from_same_package
       info • 'audio' is deprecated and shouldn't be used. use files instead • lib/network/session_options/session_opts.dart:92:9 •
              deprecated_member_use_from_same_package
       info • 'audio' is deprecated and shouldn't be used. use files instead • lib/network/session_options/session_opts.dart:93:23
              • deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. use fields instead • lib/network/text/text_response.dart:4:17 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. use fields instead • lib/network/text/text_response.dart:5:23 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. use fields instead • lib/network/text/text_response.dart:6:26 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. use fields instead • lib/network/text/text_response.dart:7:22 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. use fields instead • lib/network/text/text_response.dart:13:5 •
              deprecated_member_use_from_same_package
       info • 'data' is deprecated and shouldn't be used. use fields instead • lib/network/text/text_response.dart:19:27 •
              deprecated_member_use_from_same_package
       info • Unused import: 'package:package_info/package_info.dart' • lib/tracking/tracking.dart:20:8 • unused_import
       info • Unused import: 'package:Medito/tracking/tracking.dart' • lib/utils/stats_utils.dart:17:8 • unused_import
       info • 'await' applied to 'void', which is not a 'Future' • lib/utils/stats_utils.dart:304:7 • await_only_futures
       info • The import of 'package:flutter/cupertino.dart' is unnecessary because all of the used elements are also provided by
              the import of 'package:flutter/material.dart' • lib/utils/text_themes.dart:1:8 • unnecessary_import
       info • The import of 'package:flutter/widgets.dart' is unnecessary because all of the used elements are also provided by the
              import of 'package:flutter/material.dart' • lib/utils/text_themes.dart:3:8 • unnecessary_import
       info • 'canLaunch' is deprecated and shouldn't be used. Use canLaunchUrl instead • lib/utils/utils.dart:95:18 •
              deprecated_member_use
       info • 'launch' is deprecated and shouldn't be used. Use launchUrl instead • lib/utils/utils.dart:96:17 •
              deprecated_member_use
       info • 'canLaunch' is deprecated and shouldn't be used. Use canLaunchUrl instead • lib/utils/utils.dart:121:13 •
              deprecated_member_use
       info • 'launch' is deprecated and shouldn't be used. Use launchUrl instead • lib/utils/utils.dart:122:11 •
              deprecated_member_use
       info • The import of 'package:flutter/cupertino.dart' is unnecessary because all of the used elements are also provided by
              the import of 'package:flutter/material.dart' • lib/widgets/empty_widget.dart:3:8 • unnecessary_import
       info • The import of 'package:flutter/foundation.dart' is unnecessary because all of the used elements are also provided by
              the import of 'package:flutter/material.dart' • lib/widgets/folders/folder_nav_widget.dart:27:8 • unnecessary_import
       info • The import of 'package:flutter/cupertino.dart' is unnecessary because all of the used elements are also provided by
              the import of 'package:flutter/material.dart' • lib/widgets/home/daily_message_item_widget.dart:5:8 •
              unnecessary_import
       info • The import of 'package:flutter/cupertino.dart' is unnecessary because all of the used elements are also provided by
              the import of 'package:flutter/material.dart' • lib/widgets/home/small_shortcuts_row_widget.dart:7:8 •
              unnecessary_import
       info • 'accentColor' is deprecated and shouldn't be used. Use colorScheme.secondary instead. For more information, consult
              the migration guide at
              https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. This feature was
              deprecated after v2.3.0-0.1.pre. • lib/widgets/home/stats_widget.dart:175:15 • deprecated_member_use
       info • The import of 'package:flutter/cupertino.dart' is unnecessary because all of the used elements are also provided by
              the import of 'package:flutter/material.dart' • lib/widgets/home/streak_tile_widget.dart:18:8 • unnecessary_import
       info • The import of 'package:flutter/widgets.dart' is unnecessary because all of the used elements are also provided by the
              import of 'package:flutter/material.dart' • lib/widgets/home/streak_tile_widget.dart:20:8 • unnecessary_import
       info • 'backwardsCompatibility' is deprecated and shouldn't be used. This property is obsolete and is false by default. This
              feature was deprecated after v2.4.0-0.0.pre. • lib/widgets/main/app_bar_widget.dart:45:9 • deprecated_member_use
       info • 'brightness' is deprecated and shouldn't be used. This property is no longer used, please use systemOverlayStyle
              instead. This feature was deprecated after v2.4.0-0.0.pre. • lib/widgets/main/app_bar_widget.dart:46:9 •
              deprecated_member_use
       info • The import of 'package:flutter/cupertino.dart' is unnecessary because all of the used elements are also provided by
              the import of 'package:flutter/material.dart' • lib/widgets/packs/announcement_banner_widget.dart:21:8 •
              unnecessary_import
       info • The import of 'package:flutter/cupertino.dart' is unnecessary because all of the used elements are also provided by
              the import of 'package:flutter/material.dart' • lib/widgets/packs/error_widget.dart:19:8 • unnecessary_import
       info • Unused import: '../../main.dart' • lib/widgets/player/background_sounds_sheet_widget.dart:32:8 • unused_import
       info • The import of 'package:flutter/cupertino.dart' is unnecessary because all of the used elements are also provided by
              the import of 'package:flutter/material.dart' • lib/widgets/player/player2/player_widget_2.dart:34:8 •
              unnecessary_import
       info • The import of 'package:flutter/rendering.dart' is unnecessary because all of the used elements are also provided by
              the import of 'package:flutter/cupertino.dart' • lib/widgets/player/player2/player_widget_2.dart:36:8 •
              unnecessary_import
       info • The declaration '_getLoadingScreenWidget' isn't referenced • lib/widgets/player/player2/player_widget_2.dart:286:10 •
              unused_element
       info • Unused import: 'package:Medito/widgets/home/daily_message_item_widget.dart' •
              test/widgets/home/courses_row_item_widget_test.dart:3:8 • unused_import
    
    83 issues found. (ran in 7.3s)
    

    Flutter doctor -v

    [✓] Flutter (Channel stable, 2.10.5, on macOS 12.3.1 21E258 darwin-x64, locale en-IN)
        • Flutter version 2.10.5 at /Users/atharvajagtap/fvm/versions/2.10.5
        • Upstream repository https://github.com/flutter/flutter.git
        • Framework revision 5464c5bac7 (4 weeks ago), 2022-04-18 09:55:37 -0700
        • Engine revision 57d3bac3dd
        • Dart version 2.16.2
        • DevTools version 2.9.2
    
    [✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
        • Android SDK at /Users/atharvajagtap/Library/Android
        • Platform android-31, build-tools 29.0.2
        • ANDROID_HOME = /Users/atharvajagtap/Library/Android
        • Java binary at: /Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/bin/java
        • Java version Java(TM) SE Runtime Environment (build 1.8.0_333-b02)
        • All Android licenses accepted.
    
    [✗] Xcode - develop for iOS and macOS
        ✗ Xcode installation is incomplete; a full installation is necessary for iOS development.
          Download at: https://developer.apple.com/xcode/download/
          Or install Xcode via the App Store.
          Once installed, run:
            sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
            sudo xcodebuild -runFirstLaunch
        ✗ CocoaPods installed but not working.
            You appear to have CocoaPods installed but it is not working.
            This can happen if the version of Ruby that CocoaPods was installed with is different from the one being used to invoke
            it.
            This can usually be fixed by re-installing CocoaPods.
          To re-install see https://guides.cocoapods.org/using/getting-started.html#installation for instructions.
    
    [✓] Chrome - develop for the web
        • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
    
    [!] Android Studio (not installed)
        • Android Studio not found; download from https://developer.android.com/studio/index.html
          (or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
    
    [✓] VS Code (version 1.67.1)
        • VS Code at /Applications/Visual Studio Code.app/Contents
        • Flutter extension version 3.40.0
    
    [✓] Connected device (1 available)
        • Chrome (web) • chrome • web-javascript • Google Chrome 101.0.4951.64
    
    [✓] HTTP Host Availability
        • All required HTTP hosts are available
    
    ! Doctor found issues in 2 categories.
    
    opened by athJ 3
  • _interceptor is being called before closing dialogs

    _interceptor is being called before closing dialogs

    I have a screen where I set an interceptor in initState like so: BackButtonInterceptor.add(_interceptor);

    If I open a dialog [showDialog(...)], and press the "back" button, I want the dialog to close and not fire the _interceptor method.

    Currently the _interceptor is being called first, and only after the second "back", the dialog will be closed.

    Of course I can set a flag that indicates if a dialog is opened, and make sure to set it for all dialogs on open&close, but I feel like a default behavior should be closing dialogs first.

    enhancement 
    opened by HTMHell 3
  • Suspected conflict with flow_builder

    Suspected conflict with flow_builder

    We are using the flow_builder package which also uses the SystemChannels.navigation.setMethodCallHandler();. In addition we use the loader_overlay package, which uses this package.

    As soon as a BackButtonInterceptor is added, the flow_builder package stops to register android back button navigations.

    This is how flow_builder works with the SystemChannels.navigation:

    image

    The flow builder calls that class in initState image

    Based on documentation of SystemChannels.navigation.setMethodCallHandler, the one replaces the other: image

    opened by flodaniel 2
  • Not working as described

    Not working as described

    If any function returns true, the combined result is true

    I have the following case which is not working as described:

    I have two widgets: MyScreen and CustomAppBar. In both widgets I initialize an interceptor. MyScreen has a Scaffold with a custom app bar widget I've made: CustomAppBar.

    CustomAppBar:

      bool _interceptor(bool stopDefaultButtonEvent, RouteInfo info) {
        print('Custom AppBar');
        return true;
      }
    

    MyScreen:

      bool _interceptor(bool stopDefaultButtonEvent, RouteInfo info) {
        print('My Screen');
        return false;
      }
    

    In this case, the default back button behavior IS fired, and the route is being popped.

    And the console looks like this:

    Custom AppBar My Screen

    If I return true in MyScreen too, then it is not fired. I tried using z-index, same result.

    Version 4.4.0

    opened by HTMHell 2
  • ifRouteChanged() context parameter problem

    ifRouteChanged() context parameter problem

    I am trying to implement your lib but I am facing a problem when I am trying to check back button behavior when I push a modal (CustomDialog).

    I have two BackButtonInterceptor implemented, one in my main.dart and one in another class :

    BackButtonInterceptor: Custom, z-index: null (ifNotYetIntercepted: false). BackButtonInterceptor: GlobalBackButtonInterceptor, z-index: null (ifNotYetIntercepted: false).

    I/flutter (19197): The BackButtonInterceptor threw an ERROR: Assertion failed: "The ifRouteChanged() method can only be called if the context parameter was passed to the BackButtonInterceptor.add() method.".
    E/flutter (19197): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: Assertion failed: "The ifRouteChanged() method can only be called if the context parameter was passed to the BackButtonInterceptor.add() method."
    E/flutter (19197): #0      BackButtonInterceptor.errorProcessing.<anonymous closure>.<anonymous closure> (package:back_button_interceptor/src/back_button_interceptor.dart:22:38)
    E/flutter (19197): #1      new Future.delayed.<anonymous closure> (dart:async/future.dart:326:39)
    E/flutter (19197): #2      _rootRun (dart:async/zone.dart:1182:47)
    E/flutter (19197): #3      _CustomZone.run (dart:async/zone.dart:1093:19)
    E/flutter (19197): #4      _CustomZone.runGuarded (dart:async/zone.dart:997:7)
    E/flutter (19197): #5      _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1037:23)
    E/flutter (19197): #6      _rootRun (dart:async/zone.dart:1190:13)
    E/flutter (19197): #7      _CustomZone.run (dart:async/zone.dart:1093:19)
    E/flutter (19197): #8      _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:1021:23)
    E/flutter (19197): #9      Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
    E/flutter (19197): #10     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:397:19)
    E/flutter (19197): #11     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:428:5)
    E/flutter (19197): #12     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
    

    I tried your example main_complex_example and it's working.

    That's my code :

    class CustomPage extends StatefulWidget {
      @override
      _CustomPageState createState() => _CustomPageState();
    }
    
    class _CustomPageState extends State<CustomPage> {
      @override
      void initState() {
        super.initState();
        BackButtonInterceptor.add(myInterceptor, name: "Custom", context: context);
      }
    
      bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) {
        print(BackButtonInterceptor.describe());
        print(stopDefaultButtonEvent);
        if (stopDefaultButtonEvent) return false;
        if (info.ifRouteChanged(context)) return false;
        return true;
      }
    
      @override
      void dispose() {
        BackButtonInterceptor.removeByName("Custom");
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
              centerTitle: true,
              title: Text("Custom"),
            ),
            body: Container(
                child: IconButton(
              icon: Icon(
                Icons.share,
                color: Colors.blueGrey[500],
                size: 30,
              ),
              onPressed: () => Navigator.of(context).push(PageRouteBuilder(
                  barrierDismissible: true, opaque: false, 
                  pageBuilder: (context, _, __) => CustomDialog(...)),
            )));
      }
    }
    

    Flutter doctor -v :

    [✓] Flutter (Channel stable, 1.22.0, on Mac OS X 10.15.6 19G2021, locale fr-FR)
        • Flutter version 1.22.0 at /Users/******/Workspace/flutter
        • Framework revision d408d302e2 (7 days ago), 2020-09-29 11:49:17 -0700
        • Engine revision 5babba6c4d
        • Dart version 2.10.0
    
    [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.1)
        • Android SDK at /Users/*******/Library/Android/sdk
        • Platform android-30, build-tools 30.0.1
        • ANDROID_HOME = /Users/*****/Library/Android/sdk
        • ANDROID_SDK_ROOT = /Users/*****/Library/Android/sdk
        • Java binary at: /Users/******/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/193.6626763/Android
          Studio.app/Contents/jre/jdk/Contents/Home/bin/java
        • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
        • All Android licenses accepted.
    
    [✓] Xcode - develop for iOS and macOS (Xcode 12.0.1)
        • Xcode at /Applications/Xcode.app/Contents/Developer
        • Xcode 12.0.1, Build version 12A7300
        • CocoaPods version 1.9.3
    
    [✓] Android Studio (version 4.0)
        • Android Studio at /Users/*******/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/193.6626763/Android
          Studio.app/Contents
        • Flutter plugin version 50.0.1
        • Dart plugin version 193.7547
        • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
    
     
    [✓] Connected device (1 available)            
        • MI PAD 4 (mobile) • 5a95aa78 • android-arm64 • Android 9 (API 28)
    
    • No issues found!
    
    bug 
    opened by NassB 2
  • Trouble running multiples tests that use the BackButtonInterceptor

    Trouble running multiples tests that use the BackButtonInterceptor

    While running multiple tests that use the interceptor i got this error:

    The BackButtonInterceptor threw an ERROR: 'package:provider/src/provider.dart': Failed assertion: line 189 pos 12: 'context != null': is not true..
    Pending timers:
    Timer (duration: 0:00:00.000000, periodic: false), created:
    #0      new _FakeTimer._ (package:quiver/testing/src/async/fake_async.dart:277:42)
    #6      BackButtonInterceptor.errorProcessing.<anonymous closure> (package:back_button_interceptor/src/back_button_interceptor.dart:22:12)
    #7      BackButtonInterceptor.popRoute (package:back_button_interceptor/src/back_button_interceptor.dart:138:24)
    #8      main.<anonymous closure>.<anonymous closure> (file:///home/rodrigo/Documentos/projects/polis/test/page/user_following_politics_page_test.dart:60:35)
    #21     AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1099:17)
    #22     AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1087:35)
    (elided 32 frames from class _FakeAsync, dart:async, and package:stack_trace)
    
    ══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
    The following assertion was thrown running a test:
    A Timer is still pending even after the widget tree was disposed.
    'package:flutter_test/src/binding.dart':
    Failed assertion: line 1119 pos 12: '() {
          if (   _currentFakeAsync.periodicTimerCount == 0
              && _currentFakeAsync.nonPeriodicTimerCount == 0) {
            return true;
          }
    
          debugPrint('Pending timers:');
          for (final String timerInfo in _currentFakeAsync.pendingTimersDebugInfo) {
            final int firstLineEnd = timerInfo.indexOf('\n');
            assert(firstLineEnd != -1);
    
            // No need to include the newline.
            final String firstLine = timerInfo.substring(0, firstLineEnd);
            final String stackTrace = timerInfo.substring(firstLineEnd + 1);
    
            debugPrint(firstLine);
            debugPrintStack(stackTrace: StackTrace.fromString(stackTrace));
            debugPrint('');
          }
          return false;
        }()'
    
    When the exception was thrown, this was the stack:
    #2      AutomatedTestWidgetsFlutterBinding._verifyInvariants (package:flutter_test/src/binding.dart:1119:12)
    #3      TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:716:7)
    <asynchronous suspension>
    #6      TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.dart:683:14)
    #7      AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1083:24)
    #13     AutomatedTestWidgetsFlutterBinding.runTest (package:flutter_test/src/binding.dart:1080:15)
    #14     testWidgets.<anonymous closure> (package:flutter_test/src/widget_tester.dart:133:24)
    #15     Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:172:27)
    <asynchronous suspension>
    #16     Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart)
    #17     Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:246:15)
    #22     Invoker.waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:243:5)
    #23     Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:170:33)
    #28     Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:169:13)
    #29     Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:400:30)
    (elided 33 frames from class _AssertionError, class _FakeAsync, class _RawReceivePortImpl, class _Timer, dart:async, dart:async-patch, and package:stack_trace)
    
    opened by rodrigobastosv 2
  • Snackbar is closed instead of going back

    Snackbar is closed instead of going back

    Hi @marcglasberg ,

    Thanks for the great package.

    I am facing one issue though. I am implementing double tap back button functionality in which first I am showing snackbar and on second tap I need to close the APP( or route to the previous screen if any). But, on the second tap when I am return false, it is just closing the snackbar.

    Can you please help with this?

    Thanks.

    question 
    opened by bajajsahil 2
  • Does this work with the material AppBar back button?

    Does this work with the material AppBar back button?

    Hi there,

    These library works wonderfully with the native Android back button, however, I'd also like the same behaviour when pressing the AppBar back button (from the flutter/material.dart package) and by default it doesn't appear to work. Is there a way to enable this behaviour?

    Cheers, George

    question 
    opened by george-ayris 2
  • v6.0.1 back button interception issues

    v6.0.1 back button interception issues

    Hi,

    following #21 I migrated the application to null-safety and upgraded to the last version of flutter and the package version but the issue still continues. It looks like the interceptor function is being executed, but the navigation pop is not being intercepted.

    Here are some details:

    YAML config:

    environment:
      sdk: '>=2.17.0 <=3.0.4'
    
    dependencies:
      # some additional packages
      back_button_interceptor: ^6.0.1
    

    Flutter Doctor:

    [√] Flutter (Channel stable, 3.0.4, on Microsoft Windows [Versi¢n 10.0.19044.1806], locale es-ES)
        • Flutter version 3.0.4 at C:\DEVELOPMENT\SRC\flutter
        • Upstream repository https://github.com/flutter/flutter.git
        • Framework revision 85684f9300 (11 days ago), 2022-06-30 13:22:47 -0700
        • Engine revision 6ba2af10bb
        • Dart version 2.17.5
        • DevTools version 2.12.2
    

    My interceptor implementation:

      // Some code
      BackButtonInterceptor.add(myInterceptor, context: this.context);
      // Some more code
    
      bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) {
        if (info.ifRouteChanged(context)) {
          Navigator.of(context).pop();
          return true;
        }
        if (state.updatedSchedule) {
          add(ScheduleEditGoBackNeedConfirmation());
        } else {
          add(ScheduleEditGoBack());
        }
        return true;
      }
    
      @override
      Future<void> close() async {
        BackButtonInterceptor.remove(myInterceptor);
        super.close();
      }
    

    The navigation works correctly when executed through the in-app nav buttons. The myInterceptor function is being executed as expected, but the navigation pop is not intercepted (it's executed anyways)

    opened by Lorenzohidalgo 2
  • Doesn't work with iOS swipe

    Doesn't work with iOS swipe

    The package description makes no mention of handling the iOS back swipe. It would be appreciated to update the package description to explicitly state that the iOS swipe is not supported (I had to download and test the sample in the iOS simulator to confirm). It would also be helpful if the description described whether iOS support is planned for a future release.

    documentation 
    opened by ghost 1
Owner
Marcelo Glasberg
Marcelo Glasberg
Flutter Triple Status Button can use toggle button but in three statuses.

triple_status_button Triple Status Button. Flutter Triple Status Button can use toggle button but in three statuses. Property Description height heigh

MahdiBagjani 2 Nov 13, 2021
A button that looks like a Cupertino text button

Cupertino Text Button A button that looks like a Cupertino text button! Text Button A simple text button can be created like this: CupertinoTextButton

Nick Sirovsky 0 Nov 24, 2022
Flutter reaction button plugin it is fully customizable widget such as Facebook reaction button

Flutter Reaction Button Flutter button reaction it is fully customizable widget such as Facebook reaction button. Preview Demo Usage Include 'flutter_

Abdelouahed Medjoudja 174 Dec 19, 2022
An alternative to Overlay which allows you to easily render and hit test a widget outside its parent bounds

An alternative to Overlay which allows you to easily render and hit test a widget outside its parent bounds. Based on the original idea by @shrouxm he

gskinner team 26 Dec 31, 2022
A button with ripple effect while being hold

ripple_button a button with ripple effect while being hold build requirements to run this project you need a working enviroment of flutter v2 or highe

null 2 Nov 8, 2021
A Widget that mimics the Facebook Reaction Button in Flutter.

ReactiveButton A Widget that mimics the Facebook Reaction Button in Flutter. Step by step explanation A full explanation on how to build such Widget m

Didier Boelens 47 Jul 12, 2022
A custom dropdown button lets the user select from a number of items

CircularDropDownMenu Description A custom dropdown button lets the user select from a number of items. The button shows the currently selected item as

Surya Dev Singh 2 Dec 5, 2020
Flutter base, with a navigation button

mysample A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if this

null 0 Dec 30, 2021
Flutter progress button

flutter_progress_button flutter_progress_button is a free and open source (MIT license) Material Flutter Button that supports variety of buttons style

Yang JIANG 91 Dec 6, 2022
Flutter Custom, Text, 3D, Social media button's package

Flutter Button flutter_button, which is a flutter package, contains animated, cool and awesome buttons. That you may like, thanks to this package you

Ismael Shakverdiev 15 Dec 29, 2022
A popup simple topModalSheet menu button widget with handsome design and easy to use

top_modal_sheet A popup simple topModalSheet menu button widget with handsome design and easy to use. Installations Add top_modal_sheet: ^1.0.0 in you

Baldemar Alejandres 5 Jul 29, 2022
AsyncButtonBuilder offers a simple way to extend any type of button with an asynchronous aspect

async_button_builder AsyncButtonBuilder offers a simple way to extend any type of button with an asynchronous aspect. It allows adding loading, disabl

Nollie 22 Jul 10, 2022
This flutter package provides an easy implementation of a Slider Button to cancel current transaction or screen

This flutter package provides an easy implementation of a Slider Button to cancel current transaction or screen

null 222 Nov 8, 2022
RoundedLoadingButton is a Flutter package with a simple implementation of an animated loading button, complete with success and error animations.

rounded_loading_button RoundedLoadingButton is a Flutter package with a simple implementation of an animated loading button, complete with success and

Chris Edgington 223 Jan 4, 2023
A library to easily create radio button and checkbox groups.

Check/Radio Group A library to easily create radio button and checkbox groups. Define font size, selection color, position of radios / check and text

Caiubi Tech 2 Jan 6, 2021
Simple flutter toggle button widge

This is simple flutter toggle button widget. Supports show text labels and icons, Possible set multiple value to toggle ui, not only

fukutan 1 Sep 27, 2022
AdvFAB - An Advanced floating action button that expands itself to reveal its hidden widget

AdvFAB (More Than Just A Floating Action Button) AdvFAB is An Advanced floating action button that expands itself to reveal its hidden widget. It can

null 19 Nov 4, 2022
React hooks for Flutter. Hooks are a new kind of object that manages a Widget life-cycles. They are used to increase code sharing between widgets and as a complete replacement for StatefulWidget.

English | Português Flutter Hooks A Flutter implementation of React hooks: https://medium.com/@dan_abramov/making-sense-of-react-hooks-fdbde8803889 Ho

Remi Rousselet 2.6k Dec 29, 2022
A sliding up panel widget which can be used to show or hide content, beautiful and simple.

flutter_sliding_up_panel A sliding up panel widget which can be used to show or hide content, beautiful and simple. demo Getting Started dependencies:

null 25 Dec 12, 2022