Flutter deprecates WillPopScope and uses PopScope alternative




Original text 


<img src=”https://ducafecat.oss-cn-beijing.aliyuncs.com/podcast/2024/04/425a394c101cf8c5a715304b00c71a78.png” alt=”PopScope” style=”width:33%;” />

Learn how to replace the deprecated WillPopScope with PopScope in Flutter 3.16, and learn how to upgrade your Flutter app. Detailed guides and best practices to help you successfully migrate and update your navigation logic.

Flutter, WillPopScope, PopScope, replacement guide, migration, best practices, Flutter 3.19 migration


PopScope component definition


class PopScope extends StatefulWidget {
  /// Creates a widget that registers a callback to veto attempts by the user to
  /// dismiss the enclosing [ModalRoute].
  const PopScope({
    required this.child,
    this.canPop = true,

We know from the PopScope component definition:

  • When canPop is true , the system return gesture will cause the closed Navigator to receive pop-ups as usual. onPopInvoked will be called , and didPop is true at this time .
  • When canPop is false , the system return gesture will not pop up the route from the closed Navigator, but the onPopInvoked method will still be called. At this time didPop is false . At this time, logical judgment or other code that needs to be executed is made. If it needs to be returned, then Then execute Navigator.of(context).pop() ;.
  • Note that onPopInvoked will be called again at this time, but didPop is true at this time .
  • In onPopInvoked , you need to check didPop. If it is true , then return .



Step 1: Return the prompt function

Define the request time to facilitate calculation of intervals

  //Exit request time 
  DateTime? currentBackPressTime;

Invalid if the interval is greater than 4 seconds

  // Return key to exit 
  bool closeOnConfirm() {
     DateTime now = DateTime .now();
     // Physical key, the interval between two times is greater than 4 seconds, the exit request is invalid 
    if (currentBackPressTime == null ||
        now.difference(currentBackPressTime!) > const Duration(seconds: 4)) {
      currentBackPressTime = now;
        const SnackBar(
          behavior: SnackBarBehavior.floating,
          content: Center(child: Text( 'Press again to close the app' )),
          duration: Duration(seconds: 4),
      return  false ;

    // Exit request valid 
    currentBackPressTime = null ;
     return  true ;

Step 2: Exit confirmation when Pop

Initial canPop = fase enables exit confirmation

  // Main view
  Widget _buildView(MainController controller) {
    /// PopScope
     /// ios is the top navigation return button
     /// android is the system return button
     return PopScope(
      canPop: false , // Allow return 
      // Prevent two consecutive clicks to exit 
      onPopInvoked: ( bool didPop) async {
         if (didPop) {
           return ;
        if (closeOnConfirm()) {
           // System level navigation stack exits the program
      child: ......

pop exit time, ios is the top system navigation bar, android is the bottom system navigation bar.


In Flutter 3.16, WillPopScope has been deprecated and it is recommended to use PopScope instead. Through the definition of the PopScope component, we understand its working principle and usage. When canPop is true, the system’s return gesture will pop up the enclosed Navigator normally and call the onPopInvoked method. If canPop is false, the return gesture will not pop up the route from the navigator, but the onPopInvoked method will still be triggered. At this time, we can make logical judgments or insert other code as needed. It should be noted that the onPopInvoked method will be called again, but this time didPop is true. In onPopInvoked, we should judge based on the value of didPop and handle it accordingly. This article provides detailed guidance and best practices to help you successfully migrate and update your Flutter application’s navigation logic.

Thanks for reading this article

If you have any suggestions please let me know in the comments. I’m happy to improve.