Skip to content
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] Page.OnBackButtonPressed not called in MAUI Android #3174

Closed
aqua-ix opened this issue Jun 26, 2024 · 12 comments
Closed

[BUG] Page.OnBackButtonPressed not called in MAUI Android #3174

aqua-ix opened this issue Jun 26, 2024 · 12 comments

Comments

@aqua-ix
Copy link

aqua-ix commented Jun 26, 2024

Description

I want to hook the event triggered by pressing the back key on an Android device, but the standard MAUI method, Page.OnBackButtonPressed, is not being called.
https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.maui.controls.page.onbackbuttonpressed?view=net-maui-8.0

Steps to Reproduce

It can be reproduce this issue in this repo:
https://github.com/aqua-ix/MauiPlayground/tree/prism/onbackbutton

  1. Launch the app and navigate from the MainPage to the Third Page.
  2. Press the back key on the device while on the Third Page.
  3. Observe that ThirdPage.OnBackButtonPressed does not output any log.

If it were called, you would see a log like [ThirdPage] OnBackButtonPressed().

The Third Page was specifically created because the bug #2990 fix has not been included in the latest version 9.0.401-pre. This bug causes the app to exit when trying to navigate back using the device's back key from a page that includes a NavigationPage in the back stack.

Platform with bug

.NET MAUI

Affected platforms

Android

Did you find any workaround?

I haven't found it myself. If there is a workaround, please let me know.

Relevant log output

No response

@aqua-ix
Copy link
Author

aqua-ix commented Jul 3, 2024

builder.AddAndroid(android =>
{
    android.OnBackPressed(_ =>
    {
        var mainPage = Application.Current?.MainPage;
        var currentPage = MvvmHelpers.GetCurrentPage(mainPage);
        // currentPage is previous page

        return currentPage?.SendBackButtonPressed() ?? false;
    });
});

By hooking the Android lifecycle event OnBackPressed as described above and explicitly calling back the SendBackButtonPressed of the currently displayed page, I confirmed that the OnBackPressed of the Page class is being called. However, there is one problem: the page retrieved by the GetCurrentPage method is always the previously displayed page. This seems to be related to the bug in dotnet/maui#15296.

@dansiegel
Copy link
Member

You're trying to do something goofy here and without any explanation of your goals it's hard to say exactly what you should be doing instead. That being said Prism.Maui has some breaking changes for those coming from Prism.Forms. This is to correct behaviors that weren't quite right in Prism.Forms. This is one of those cases. Where you have a NavigationPage and Press the BackButton we could only respond after the fact in Prism.Forms. In Prism.Maui we intercept this by default and prevent the native navigation from happening. This is to allow Prism's Navigation to take precedence and allow things like IConfirmNavigation to work as intended.

@aqua-ix
Copy link
Author

aqua-ix commented Jul 4, 2024

@dansiegel

You're trying to do something goofy here and without any explanation of your goals it's hard to say exactly what you should be doing instead.

I apologize for the lack of clarity in my explanation.

In the app I am developing, there was a feature in the Prism.Forms era where the behavior differed when the user navigated using the "Up" button on the navigation bar versus the "Back" button on the device. Since transitioning to Prism.Maui, this behavior can no longer be implemented. Therefore, I am currently investigating other methods to distinguish whether the device's back button was pressed. Is there a way to do this that doesn't depend on whether OnBackButtonPressed is triggered?

@dansiegel
Copy link
Member

I'm not sure what you mean by the "Up" button. Keep in that when the Back Button either Software or Hardware is pressed in Prism.Maui this is intercepted and the NavigationService.GoBackAsync is called without any parameters

@brianlagunas
Copy link
Member

If you want to run code when the hardware or software back button is pressed, you should implement the INavigatedAware interface, or IConfirmNavigationAsync if you want to prevent navigation.

@aqua-ix
Copy link
Author

aqua-ix commented Jul 4, 2024

The "Up" button referred to the software button enclosed in the red frame of the image.
This is separate from the back operation using the blue-framed button or Android gestures.

I already implemented INavigatedAware, but in my app, there is an additional requirement to perform extra processing only when the Android hardware button is pressed. In Xamarin, I used Page.OnBackButtonPressed, which was called only when the Android or UWP hardware button was pressed. After introducing Prism.Maui, it seems that this is no longer called, making it difficult to distinguish whether the hardware button has been pressed.

@brianlagunas
Copy link
Member

Currently, Prism prevents the OnBackButtonPressed to prevent you from trying to intermix the two approaches and enforce the loose coupling/MVVM approach to respond to navigation events.

Currently in MAUI, the OnBackButtonPressed is called when either the Software Back Button or the Hardware Back Button is pressed. That is a behavior change in MAUI as well. Which sounds like wouldn't work for you either.

@aqua-ix
Copy link
Author

aqua-ix commented Jul 4, 2024

@brianlagunas

Currently, Prism prevents the OnBackButtonPressed to prevent you from trying to intermix the two approaches and enforce the loose coupling/MVVM approach to respond to navigation events.

I understand why OnBackButtonPressed was not being called when I install Prism.
I will consider a different approach.

Thanks for the explanation.

@thomasgalliker
Copy link

@aqua-ix how did you finally solve this? I'm struggling with the same problem. In some pages I blocked hardware-back navigation by overriding OnBackButtonPressed directly in the affected page. @brianlagunas I can use IConfirmNavigation instead, but is there a ways to figure out if the originator of the back-navigation request was the hardware/software back button of the Android device?

@brianlagunas
Copy link
Member

Internally we use the PageNavigationService.NavigationSource to check if the navigation was invoked by the device (hardware/software) or the nav service itself.

@thomasgalliker
Copy link

Yep, @brianlagunas I was thinking about that flag too. I managed to solve this problem, so it‘s no longer a show stopper for me. But what, if we pass this NavigationSource as navigation parameter along with all navigation calls, or at least with the go-back calls? I‘m just thinking louf 😊 If I knew the originator of the go-back call, I could return false if my ViewModel is asked about CanNavigate() 👍🏻

@aqua-ix
Copy link
Author

aqua-ix commented Aug 16, 2024

@thomasgalliker

By creating a custom handler for the ToolBar, I was able to detect when the software back button is tapped using a listener. I stored it as a property in the ViewModel, and handled it within the CanNavigate() method.

Below is a simple sample I created. In this sample, navigation is disabled with the hardware back button, but it allows navigation with the software back button.
https://github.com/aqua-ix/MauiPlayground/tree/prism/toolbarhandler

I hope this helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants