-
Notifications
You must be signed in to change notification settings - Fork 333
Description
🐛 Bug Report
PopAsync & PopAllAsync causing app crash for iOS due PlatformView null exception after migrate from Xamarin to maui
Exception details :
System.InvalidOperationException: PlatformView cannot be null here
at Microsoft.Maui.Handlers.ViewHandler`2[[Microsoft.Maui.IContentView, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Platform.ContentView, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].get_PlatformView()
at RGPopup.Maui.IOS.Platform.PopupWindow.HitTest(CGPoint point, UIEvent uievent)
at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName) in /Users/builder/azdo/_work/2/s/xamarin-macios/src/UIKit/UIApplication.cs:line 61
at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass) in /Users/builder/azdo/_work/2/s/xamarin-macios/src/UIKit/UIApplication.cs:line 96
at Program.Main(String[] args) in Platforms/iOS/Program.cs:line 13
Here is code :
private static bool _isDismissingPopup = false;
private static readonly SemaphoreSlim _popupLock = new(1, 1);
// Global Safe Popup Dismiss Method
public static async Task SafeDismissAllPopups()
{
System.Diagnostics.Debug.WriteLine("SafeDismissAllPopups Called ");
if (_isDismissingPopup)
{
Debug.WriteLine("Dismiss SafeDismissAllPopups already in progress. Skipping...");
return; // Exit if another dismissal is running
}
_isDismissingPopup = true;
await _popupLock.WaitAsync(); // Lock execution (ensures only 1 thread enters)
try
{
System.Diagnostics.Debug.WriteLine("SafeDismissAllPopups try Called ");
await MainThread.InvokeOnMainThreadAsync(async () =>
{
try
{
await Task.Delay(100); // UI stabilization delay
if (PopupNavigation.Instance.PopupStack?.Any() == true)
{
System.Diagnostics.Debug.WriteLine("PopAllAsync Called ");
await PopupNavigation.Instance.PopAllAsync().ConfigureAwait(false);
System.Diagnostics.Debug.WriteLine("PopAllAsync Dismissed ");
}
}
catch (InvalidOperationException ex)
{
Debug.WriteLine($"SafeDismissAllPopups PlatformView issue: {ex.Message}");
}
catch (System.Exception ex)
{
Debug.WriteLine($"SafeDismissAllPopups Error while dismissing popup: {ex.Message}");
}
});
}
catch (ObjectDisposedException ex)
{
Debug.WriteLine($"SafeDismissAllPopups Popup already disposed: {ex.Message}");
}
catch (InvalidOperationException ex)
{
Debug.WriteLine($"SafeDismissAllPopups PlatformView issue: {ex.Message}");
}
catch (global::System.Exception ex)
{
Debug.WriteLine($"SafeDismissAllPopups Unexpected popup error: {ex.Message}");
}
finally
{
_isDismissingPopup = false;
_popupLock.Release(); // Unlock execution
}
}
public static async Task SafeDismissTopPopup()
{
Debug.WriteLine("SafeDismissTopPopup Called");
if (_isDismissingPopup)
{
Debug.WriteLine("Dismiss already in progress. Skipping...");
return;
}
await _popupLock.WaitAsync(); // Prevents re-entry
_isDismissingPopup = true;
try
{
await MainThread.InvokeOnMainThreadAsync(async () =>
{
try
{
Debug.WriteLine("Checking popup stack...");
if (PopupNavigation.Instance.PopupStack?.Any() != true)
{
Debug.WriteLine("No popups found in the stack.");
return;
}
var topPopup = PopupNavigation.Instance.PopupStack.LastOrDefault();
if (topPopup == null)
{
Debug.WriteLine("Popup already removed.");
return;
}
var popupRef = new WeakReference<RGPopup.Maui.Pages.PopupPage>(topPopup);
await Task.Delay(100); // UI stabilization delay
if (popupRef.TryGetTarget(out var popup) && PopupNavigation.Instance.PopupStack.Contains(popup))
{
if (popup.Handler?.PlatformView != null)
{
await TryPopAsync(topPopup);
}
else
{
Debug.WriteLine("Popup's PlatformView is null, possibly already removed.");
}
}
else
{
Debug.WriteLine("Popup reference is no longer valid.");
}
}
catch(System.Exception ex)
{
Debug.WriteLine($"Unexpected error while dismissing popup: {ex.Message}");
}
});
}
catch (System.Exception ex)
{
Debug.WriteLine($"Unexpected error while dismissing popup: {ex.Message}");
}
finally
{
_isDismissingPopup = false;
_popupLock.Release();
}
}
private static async Task TryPopAsync(RGPopup.Maui.Pages.PopupPage popup)
{
try
{
Debug.WriteLine("Popup TryPopAsync....");
// Check if the popup is still in the navigation stack before attempting to pop
if (PopupNavigation.Instance.PopupStack.Contains(popup))
{
if (popup.Handler?.PlatformView != null)
{
await PopupNavigation.Instance.PopAsync(false);
Debug.WriteLine("Popup dismissed successfully.");
}
else
{
Debug.WriteLine("Attempted to dismiss popup, but PlatformView is null.");
}
}
else
{
Debug.WriteLine("Popup was no longer in the stack.");
}
}
catch (InvalidOperationException ex)
{
// This could catch the specific crash related to PlatformView being invalid
Console.WriteLine($"InvalidOperationException while dismissing popup: {ex.Message}");
// Consider any additional logic to handle this error appropriately
}
catch (System.Exception ex)
{
// Catch all other exceptions for logging
Console.WriteLine($"Error while dismissing popup: {ex.Message}");
}
}
}
Expected behavior :
At least application should not crash due to this.
Reproduction steps
Configuration
Version: 1.x
Platform:
- 📱 iOS
- 🤖 Android
- 🏁 WPF
- 🌎 UWP
- 🍎 MacOS
- 📺 tvOS
- 🐒 Xamarin.Forms