fix CupertinoTabView's Android back button handling with PopScope (#141604)
This PR fixes CupertinoTabView's handling of Android back button with PopScope and nested navigators by calling `NavigatorState.maybePop` instead of `NavigatorState.pop`, so that the Navigator pops only when it should.
Fix #139050
diff --git a/packages/flutter/lib/src/cupertino/tab_view.dart b/packages/flutter/lib/src/cupertino/tab_view.dart
index 1d38eb0..b08bcdd 100644
--- a/packages/flutter/lib/src/cupertino/tab_view.dart
+++ b/packages/flutter/lib/src/cupertino/tab_view.dart
@@ -197,7 +197,7 @@
if (!_isActive) {
return;
}
- _navigatorKey.currentState!.pop();
+ _navigatorKey.currentState!.maybePop();
},
child: child,
);
diff --git a/packages/flutter/test/cupertino/tab_test.dart b/packages/flutter/test/cupertino/tab_test.dart
index 63001a6..d96760f 100644
--- a/packages/flutter/test/cupertino/tab_test.dart
+++ b/packages/flutter/test/cupertino/tab_test.dart
@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:flutter/cupertino.dart';
+import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
@@ -289,4 +290,37 @@
expect(find.text('home'), findsOneWidget);
expect(find.text('second route'), findsNothing);
});
+
+ testWidgets('Handles Android back button', (WidgetTester tester) async {
+ final GlobalKey<NavigatorState> key = GlobalKey<NavigatorState>();
+ await tester.pumpWidget(
+ CupertinoApp(
+ home: CupertinoTabScaffold(
+ tabBar: CupertinoTabBar(
+ items: const <BottomNavigationBarItem>[
+ BottomNavigationBarItem(label: '', icon: Text('1')),
+ BottomNavigationBarItem(label: '', icon: Text('2'))
+ ],
+ ),
+ tabBuilder: (_, int i) => PopScope(
+ canPop: false,
+ child: CupertinoTabView(
+ navigatorKey: key,
+ builder: (BuildContext context) => const Text('first route'),
+ ),
+ ),
+ ),
+ ),
+ );
+
+ expect(find.text('first route'), findsOneWidget);
+
+ // Simulate android back button intent.
+ final ByteData message = const JSONMethodCodec().encodeMethodCall(const MethodCall('popRoute'));
+ await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) {});
+ await tester.pumpAndSettle();
+
+ // Navigator didn't pop, so first route is still visible
+ expect(find.text('first route'), findsOneWidget);
+ });
}