-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Bug]: Android physical back button exits the app #149
Comments
IMG_3829.mp4 |
Hi, I see the issue you are having and I want to solve it. Unfortunately, I need more information to be able to reproduce this specific behavior to then investigate what causes it. There are so many parts involved that currently I can only randomly guess what is going wrong.
Can you please specify which update caused that? What was the old version? |
@jb3rndt
Thanks~ |
Hi, thank you for providing some code. Unfortunately, I dont see how this reproduces the issues mentioned by @bugrevealingbme. When setting |
My application is too big so I can't share a code. However, if it is convenient for you, I can have my codes reviewed by remote connection |
I think this problem is related to gorouter |
This is an issue with new versions of Flutter and Android, because of the introduction of predictive back gestures, which is changing the whole way the back button is handled in Android. Basically if your app doesn't support predictive back gestures yet, then hitting Back will pop the whole app (close the app). Took me forever to figure this out. Here is the issue: flutter/flutter#135654 Here is the way I solved it -- call /// Used for obtaining a global [NavigatorState].
final navigatorKey = GlobalKey<NavigatorState>();
/// Get the global [NavigatorState] (for opening modals).
NavigatorState get navigator {
final navigatorState = navigatorKey.currentState;
if (navigatorState == null) {
// Should not happen as long as there is a Navigator in the router
throw 'navigatorKey.currentState is null';
}
return navigatorState;
}
/// Pop the current route if possible.
bool navigatorPop<T>([T? result]) {
if (navigatorKey.currentState?.canPop() ?? false) {
navigatorKey.currentState!.pop(result);
return true;
}
return false;
} Basically this pops the top modal or route, but then stops popping when there are no more routes or modals left to pop within the app. Then at that point, if you hit Back one more time, the app will pop. Then in your navigatorKey: navigatorKey, |
Is there anything this package can do differently to reduce problems with the predictive back? |
I wish I had an answer to that question, but all the information I could find about this fundamental change was hazy at best. The Flutter issue link is a good place to start. Manually handling Back events with the code I shared solved the problem for me. There is one other thing: there is an Android manifest value that can be set to enable predictive back, and if you enable that, the regular back event doesn't even reach Flutter. So there must be an actual API for predictive back that needs to be implemented. Sorry, a lot of this is guesswork, or fuzzy memories, and I don't have time to go back and research this again! |
Thanks for the reply and the investigation. Unfortunately, I still dont entirely understand where the problem comes from. Can you confirm that the example of this repo works as inteded for you? If so, what is different in your application that requires the code patch you posted above? (Lets ignore the android manifest value to enable predictive back).
In which case does an app not support predictive back? When the app uses the deprecated |
No, I wasn't using I do know that at one point, I was using the following code, appropriately hooked into /// Make back button close any open dialogs first, and only pop the route
/// if there are no dialogs open. (Default behavior is to pop the app on
/// every back button press)
class FixedBackButtonDispatcher extends RootBackButtonDispatcher {
@override
Future<bool> didPopRoute() async {
// Close any open modal dialog before attempting to pop route
if (navigatorKey.currentState?.canPop() ?? false) {
navigatorKey.currentState!.pop();
return true;
}
// Pop route, or pop app if at top level
return super.didPopRoute();
}
} I wish I could help further but my app has evolved far past the point where I was dealing with this, and I just don't remember any other details. |
Applying pageTransitionsTheme solved my problem.
|
Thanks for finding this, this is exactly the predictive back API that I suspected existed, but didn't know where to find! The back problem recurred for me recently, despite the fixes I put in place already. I tried adding this So the problem I have now is that if I switch tabs multiple times, then press Back, about 50% of the time the entire app is popped immediately -- the other 50% of the time, the app will switch between tabs in the reverse order that they were selected. There is no rhyme or reason as to when Back works properly and when it immediately pops the app. |
I think there's something funky going on here, in @override
Widget build(BuildContext context) {
if (_contextList.length != widget.tabs.length) {
_contextList = List<BuildContext?>.filled(widget.tabs.length, null);
}
if ((widget.handleAndroidBackButtonPress || widget.onWillPop != null) &&
widget.navigationShell == null) {
return PopScope(
canPop: canPop,
onPopInvoked: (didPop) async {
if (didPop) {
return;
}
final navigator = Navigator.of(context);
final shouldPop = await _canPopTabView();
// This is only used when onWillPop is provided
if (shouldPop) {
if (navigator.canPop()) {
navigator.pop();
} else {
await SystemNavigator.pop();
}
}
},
// ... and Future<bool> _canPopTabView() async {
if (!widget.handleAndroidBackButtonPress && widget.onWillPop != null) {
return widget.onWillPop!(_contextList[_controller.index]!);
} else {
final navigator = _navigatorKeys[_controller.index].currentState!;
if (_controller.historyIsEmpty() && !navigator.canPop()) {
if (widget.handleAndroidBackButtonPress && widget.onWillPop != null) {
return widget.onWillPop!(_contextList[_controller.index]!);
}
// CanPop should be true in this case, so we dont return true because the pop already happened
return false;
} else {
if (navigator.canPop()) {
navigator.pop();
} else {
_controller.jumpToPreviousTab();
}
return false;
}
}
} And, in @override
Widget build(BuildContext context) => Navigator(
key: widget.navigatorConfig.navigatorKey,
initialRoute: widget.navigatorConfig.initialRoute,
onGenerateRoute: _onGenerateRoute,
onUnknownRoute: _onUnknownRoute,
observers: _navigatorObservers,
);
// ... There are some very complex things going on here, but I suspect that the interactions between the app's root Why on earth is this so complex? Why not just use the root |
OK, I found a solution to the issue that I mentioned in the previous comment -- wrapping PopScope(
child: PersistentTabView(
// ... This seems to make With the above (Note that defining Also, I removed The fact that this fixes the problem seems to confirm to me that somewhere in all the complex logic of |
I'm sorry, after trying around quite some time I still cant reproduce the error. Can anyone provide some example code? (that I can run as-is) |
any update? still same |
This problem only exists with go_router |
No. As I said, I need something to reproduce the issue. |
Version
5.2.3
Flutter Doctor Output
What platforms are you seeing the problem on?
Android, iOS
What happened?
I have 2 problems.
1- If I click on the current tab, it returns to the previous tab. This problem came after an update.
2- If I go to the next page with the navbar (Navigator.push), Android's return button takes me directly out of the application. I'm using GoRouter (if I go with gorouter without navbar there is no problem, but this time there is no navbar).
Steps to reproduce
1- If I click on the current tab, it returns to the previous tab. This problem came after an update.
2- If I go to the next page with the navbar (Navigator.push), Android's return button takes me directly out of the application. I'm using GoRouter (if I go with gorouter without navbar there is no problem, but this time there is no navbar).
Code to reproduce the problem
Relevant log output
No response
Screenshots
No response
The text was updated successfully, but these errors were encountered: