-
Couldn't load subscription status.
- Fork 1.9k
[iOS] Fix App crash with NullReferenceException in ShellSectionRenderer #32109
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
Open
devanathan-vaithiyanathan
wants to merge
4
commits into
dotnet:main
Choose a base branch
from
devanathan-vaithiyanathan:fix_31961
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -852,6 +852,24 @@ internal void SendNavigatedFrom(NavigatedFromEventArgs args, bool disconnectHand | |||
| if (args.NavigationType == NavigationType.Pop || | ||||
| args.NavigationType == NavigationType.PopToRoot) | ||||
| { | ||||
| #if IOS | ||||
| // Don't dispose Handlers too early on iOS! | ||||
| // iOS aggressively cleans up page Handlers during navigation, but if the page | ||||
| // is still in Shell's navigation stack, users can navigate back to it. | ||||
| // Disposing the Handler makes the page invisible. | ||||
| // So only dispose Handler if page not in current Shell stack | ||||
| if (Shell.Current != null) | ||||
| { | ||||
| // Check if this page is still referenced in Shell's navigation stack | ||||
| var currentStack = Shell.Current.CurrentItem?.CurrentItem?.Stack; | ||||
| if (currentStack?.Contains(this) == true) | ||||
| { | ||||
| // Page is still in navigation stack, don't dispose Handler | ||||
| return; | ||||
| } | ||||
| } | ||||
| #endif | ||||
|
|
||||
|
||||
194 changes: 194 additions & 0 deletions
194
src/Controls/tests/TestCases.HostApp/Issues/Issue31961.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,194 @@ | ||
| using System.Collections.ObjectModel; | ||
|
|
||
| namespace Maui.Controls.Sample.Issues; | ||
|
|
||
| // Interface for navigation awareness | ||
| public interface INavigationAware | ||
| { | ||
| void OnShellNavigated(ShellNavigatedEventArgs args); | ||
| } | ||
|
|
||
| [Issue(IssueTracker.Github, 31961, "[iOS] App crash with NullReferenceException in ShellSectionRenderer", PlatformAffected.iOS | PlatformAffected.macOS)] | ||
| public class Issue31961 : Shell | ||
| { | ||
| public Issue31961() | ||
| { | ||
| var mainPage = new ShellContent | ||
| { | ||
| Title = "Main", | ||
| Content = new Issue31961MainPage(), | ||
| Route = "MainPage" | ||
| }; | ||
|
|
||
| var tabBar = new TabBar(); | ||
| tabBar.Items.Add(mainPage); | ||
| Items.Add(tabBar); | ||
|
|
||
| // Register routes for navigation | ||
| Routing.RegisterRoute("Issue31961FirstPage", typeof(Issue31961FirstPage)); | ||
| Routing.RegisterRoute("Issue31961SecondPage", typeof(Issue31961SecondPage)); | ||
| Routing.RegisterRoute("Issue31961ThirdPage", typeof(Issue31961ThirdPage)); | ||
| Routing.RegisterRoute("Issue31961ModalPage", typeof(Issue31961ModalPage)); | ||
| } | ||
|
|
||
| protected override void OnNavigated(ShellNavigatedEventArgs args) | ||
| { | ||
| if (Current.CurrentPage?.BindingContext is INavigationAware bindingContext) | ||
| { | ||
| bindingContext.OnShellNavigated(args); | ||
| } | ||
|
|
||
| base.OnNavigated(args); | ||
| } | ||
| } | ||
|
|
||
| public partial class Issue31961MainPage : ContentPage | ||
| { | ||
| public Command NavigateToPage1Command { get; } | ||
|
|
||
| public Issue31961MainPage() | ||
| { | ||
| // Initialize command | ||
| NavigateToPage1Command = new Command(async () => await NavigateToPage1Async()); | ||
|
|
||
| var btnNavigate = new Button | ||
| { | ||
| Text = "Go to Page 1", | ||
| FontSize = 20, | ||
| AutomationId = "MainPage", | ||
| HorizontalOptions = LayoutOptions.Center, | ||
| VerticalOptions = LayoutOptions.Center, | ||
| Command = NavigateToPage1Command | ||
| }; | ||
|
|
||
| Content = btnNavigate; | ||
| } | ||
|
|
||
| async Task NavigateToPage1Async() | ||
| { | ||
| await Shell.Current.GoToAsync("Issue31961FirstPage"); | ||
| } | ||
| } | ||
|
|
||
| public class Issue31961FirstPage : ContentPage, INavigationAware | ||
| { | ||
| bool _wasModalShown = false; | ||
|
|
||
| public Command OpenModalCommand { get; } | ||
| public Command NavigateToPage2Command { get; } | ||
|
|
||
| public Issue31961FirstPage() | ||
| { | ||
| Title = "Page 1"; | ||
| BindingContext = this; // Set binding context to enable INavigationAware | ||
|
|
||
| // Initialize commands | ||
| OpenModalCommand = new Command(async () => await OpenModalAsync()); | ||
| NavigateToPage2Command = new Command(async () => await NavigateToPage2Async()); | ||
|
|
||
| var btnOpenModal = new Button { Text = "Open Modal Page", AutomationId = "OpenModalButton", Command = OpenModalCommand }; | ||
| var btnGoToPage2 = new Button { Text = "Go to Page 2", Command = NavigateToPage2Command }; | ||
|
|
||
| Content = new VerticalStackLayout | ||
| { | ||
| Padding = 20, | ||
| Spacing = 20, | ||
| Children = { btnOpenModal, btnGoToPage2 } | ||
| }; | ||
| } | ||
|
|
||
| async Task OpenModalAsync() | ||
| { | ||
| _wasModalShown = true; | ||
| await Shell.Current.GoToAsync("Issue31961ModalPage"); | ||
| } | ||
|
|
||
| async Task NavigateToPage2Async() | ||
| { | ||
| await Shell.Current.GoToAsync("Issue31961SecondPage"); | ||
| } | ||
|
|
||
| public void OnShellNavigated(ShellNavigatedEventArgs args) | ||
| { | ||
| // This will be called when Shell navigation occurs | ||
| if (_wasModalShown) | ||
| { | ||
| _wasModalShown = false; // Reset the flag | ||
| // Navigate to Page2 only after modal action is completed | ||
| NavigateToPage2Command.Execute(null); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public class Issue31961ModalPage : ContentPage | ||
| { | ||
| public Command CloseModalCommand { get; } | ||
|
|
||
| public Issue31961ModalPage() | ||
| { | ||
| Title = "Modal Page"; | ||
| BackgroundColor = Colors.LightGray; | ||
|
|
||
| // Initialize command | ||
| CloseModalCommand = new Command(async () => await CloseModalAsync()); | ||
|
|
||
| var btnClose = new Button { Text = "Close Modal Page", AutomationId = "CloseModalButton", Command = CloseModalCommand }; | ||
|
|
||
| Content = new VerticalStackLayout | ||
| { | ||
| Padding = 20, | ||
| Spacing = 20, | ||
| Children = { new Label { Text = "This is a Modal Page" }, btnClose } | ||
| }; | ||
| } | ||
|
|
||
| async Task CloseModalAsync() | ||
| { | ||
| await Shell.Current.GoToAsync(".."); | ||
| } | ||
| } | ||
|
|
||
| public class Issue31961SecondPage : ContentPage | ||
| { | ||
| public Command NavigateToPage3Command { get; } | ||
|
|
||
| public Issue31961SecondPage() | ||
| { | ||
| Title = "Page 2"; | ||
|
|
||
| // Initialize command | ||
| NavigateToPage3Command = new Command(async () => await NavigateToPage3Async()); | ||
|
|
||
| var btnGoToPage3 = new Button { Text = "Go to Page 3", AutomationId = "Page2" , Command = NavigateToPage3Command }; | ||
|
|
||
| Content = new VerticalStackLayout | ||
| { | ||
| Padding = 20, | ||
| Spacing = 20, | ||
| Children = { btnGoToPage3 } | ||
| }; | ||
| } | ||
|
|
||
| async Task NavigateToPage3Async() | ||
| { | ||
| await Shell.Current.GoToAsync("Issue31961ThirdPage"); | ||
| } | ||
| } | ||
|
|
||
| public class Issue31961ThirdPage : ContentPage | ||
| { | ||
| public Issue31961ThirdPage() | ||
| { | ||
| Title = "Page 3"; | ||
|
|
||
| var label = new Label | ||
| { | ||
| Text = "Welcome to Page 3", | ||
| AutomationId = "Page3", | ||
| HorizontalOptions = LayoutOptions.Center, | ||
| VerticalOptions = LayoutOptions.Center | ||
| }; | ||
|
|
||
| Content = label; | ||
| } | ||
| } |
27 changes: 27 additions & 0 deletions
27
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue31961.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| using NUnit.Framework; | ||
| using UITest.Appium; | ||
| using UITest.Core; | ||
|
|
||
| namespace Microsoft.Maui.TestCases.Tests.Issues | ||
| { | ||
| public class Issue31961 : _IssuesUITest | ||
| { | ||
| public Issue31961(TestDevice device) : base(device) { } | ||
|
|
||
| public override string Issue => "[iOS] App crash with NullReferenceException in ShellSectionRenderer"; | ||
| [Test] | ||
| [Category(UITestCategories.Shell)] | ||
| public void VerifyShellNavigationWithModalNavigation() | ||
| { | ||
| App.WaitForElement("MainPage"); | ||
| App.Tap("MainPage"); | ||
| App.WaitForElement("OpenModalButton"); | ||
| App.Tap("OpenModalButton"); | ||
| App.WaitForElement("CloseModalButton"); | ||
| App.Tap("CloseModalButton"); | ||
| App.WaitForElement("Page2"); | ||
| App.Tap("Page2"); | ||
| App.WaitForElement("Page3"); | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only required on iOS? Because this is a cross platform code that will run same on other platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jsuarezruiz , I've added the fix only for iOS platform