Skip to content

PopAsync & PopAllAsync causing app crash for iOS due PlatformView null exception after migrate from Xamarin to maui #770

@Upasana-parmar

Description

@Upasana-parmar

🐛 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions