diff --git a/CHANGELOG.md b/CHANGELOG.md index a0382cbb90..5423bedd29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ### Fixes - Work around iOS SHA1 bug ([#4143](https://github.com/getsentry/sentry-dotnet/pull/4143)) +- Prevent Auto Breadcrumbs Event Binder from leaking and rebinding events ([#4159](https://github.com/getsentry/sentry-dotnet/pull/4159)) - Fixes build error when building .NET Framework applications using Sentry 5.6.0: `MSB4185 :The function "IsWindows" on type "System.OperatingSystem" is not available` ([#4160](https://github.com/getsentry/sentry-dotnet/pull/4160)) ### Dependencies diff --git a/src/Sentry.Maui/Internal/MauiEventsBinder.cs b/src/Sentry.Maui/Internal/MauiEventsBinder.cs index dbd297ae27..dd35058015 100644 --- a/src/Sentry.Maui/Internal/MauiEventsBinder.cs +++ b/src/Sentry.Maui/Internal/MauiEventsBinder.cs @@ -34,6 +34,9 @@ public MauiEventsBinder(IHub hub, IOptions options, IEnumerab public void HandleApplicationEvents(Application application, bool bind = true) { + // we always unbind first to ensure no previous hooks + UnbindApplication(application); + if (bind) { // Attach element events to all existing descendants (skip the application itself) @@ -65,22 +68,23 @@ public void HandleApplicationEvents(Application application, bool bind = true) // https://docs.microsoft.com/dotnet/maui/user-interface/system-theme-changes#react-to-theme-changes application.RequestedThemeChanged += OnApplicationOnRequestedThemeChanged; } - else - { - application.DescendantAdded -= OnApplicationOnDescendantAdded; - application.DescendantRemoved -= OnApplicationOnDescendantRemoved; + } - HandleElementEvents(application, bind: false); + private void UnbindApplication(Application application) + { + application.DescendantAdded -= OnApplicationOnDescendantAdded; + application.DescendantRemoved -= OnApplicationOnDescendantRemoved; - // Navigation events - application.PageAppearing -= OnApplicationOnPageAppearing; - application.PageDisappearing -= OnApplicationOnPageDisappearing; - application.ModalPushed -= OnApplicationOnModalPushed; - application.ModalPopped -= OnApplicationOnModalPopped; + HandleElementEvents(application, bind: false); - // Theme changed event - application.RequestedThemeChanged -= OnApplicationOnRequestedThemeChanged; - } + // Navigation events + application.PageAppearing -= OnApplicationOnPageAppearing; + application.PageDisappearing -= OnApplicationOnPageDisappearing; + application.ModalPushed -= OnApplicationOnModalPushed; + application.ModalPopped -= OnApplicationOnModalPopped; + + // Theme changed event + application.RequestedThemeChanged -= OnApplicationOnRequestedThemeChanged; } internal void OnApplicationOnDescendantAdded(object? _, ElementEventArgs e) @@ -169,6 +173,7 @@ internal void OnApplicationOnDescendantRemoved(object? _, ElementEventArgs e) internal void HandleWindowEvents(Window window, bool bind = true) { + UnhookWindow(window); if (bind) { // Lifecycle Events @@ -192,29 +197,39 @@ internal void HandleWindowEvents(Window window, bool bind = true) window.ModalPopped += OnWindowOnModalPopped; window.PopCanceled += OnWindowOnPopCanceled; } - else - { - // Lifecycle events caused by user action - window.Activated -= OnWindowOnActivated; - window.Deactivated -= OnWindowOnDeactivated; - window.Stopped -= OnWindowOnStopped; - window.Resumed -= OnWindowOnResumed; - - // System generated lifecycle events - window.Created -= OnWindowOnCreated; - window.Destroying -= OnWindowOnDestroying; - window.Backgrounding -= OnWindowOnBackgrounding; - window.DisplayDensityChanged -= OnWindowOnDisplayDensityChanged; + } - // Navigation events - window.ModalPushed -= OnWindowOnModalPushed; - window.ModalPopped -= OnWindowOnModalPopped; - window.PopCanceled -= OnWindowOnPopCanceled; - } + private void UnhookWindow(Window window) + { + // Lifecycle events caused by user action + window.Activated -= OnWindowOnActivated; + window.Deactivated -= OnWindowOnDeactivated; + window.Stopped -= OnWindowOnStopped; + window.Resumed -= OnWindowOnResumed; + + // System generated lifecycle events + window.Created -= OnWindowOnCreated; + window.Destroying -= OnWindowOnDestroying; + window.Backgrounding -= OnWindowOnBackgrounding; + window.DisplayDensityChanged -= OnWindowOnDisplayDensityChanged; + + // Navigation events + window.ModalPushed -= OnWindowOnModalPushed; + window.ModalPopped -= OnWindowOnModalPopped; + window.PopCanceled -= OnWindowOnPopCanceled; } internal void HandleElementEvents(Element element, bool bind = true) { + // we always unbind the element first to ensure we don't have any sticky or repeat hooks + // Rendering events + element.ChildAdded -= OnElementOnChildAdded; + element.ChildRemoved -= OnElementOnChildRemoved; + element.ParentChanged -= OnElementOnParentChanged; + + // BindableObject events + element.BindingContextChanged -= OnElementOnBindingContextChanged; + if (bind) { // Rendering events @@ -229,34 +244,30 @@ internal void HandleElementEvents(Element element, bool bind = true) // BindableObject events element.BindingContextChanged += OnElementOnBindingContextChanged; } - else - { - // Rendering events - element.ChildAdded -= OnElementOnChildAdded; - element.ChildRemoved -= OnElementOnChildRemoved; - element.ParentChanged -= OnElementOnParentChanged; - - // BindableObject events - element.BindingContextChanged -= OnElementOnBindingContextChanged; - } } internal void HandleVisualElementEvents(VisualElement element, bool bind = true) { + element.Focused -= OnElementOnFocused; + element.Unfocused -= OnElementOnUnfocused; + if (bind) { element.Focused += OnElementOnFocused; element.Unfocused += OnElementOnUnfocused; } - else - { - element.Focused -= OnElementOnFocused; - element.Unfocused -= OnElementOnUnfocused; - } } internal void HandleShellEvents(Shell shell, bool bind = true) { + // Navigation events + // https://docs.microsoft.com/dotnet/maui/fundamentals/shell/navigation + shell.Navigating -= OnShellOnNavigating; + shell.Navigated -= OnShellOnNavigated; + + // A Shell is also a Page + HandlePageEvents(shell, bind: false); + if (bind) { // Navigation events @@ -267,20 +278,23 @@ internal void HandleShellEvents(Shell shell, bool bind = true) // A Shell is also a Page HandlePageEvents(shell); } - else - { - // Navigation events - // https://docs.microsoft.com/dotnet/maui/fundamentals/shell/navigation - shell.Navigating -= OnShellOnNavigating; - shell.Navigated -= OnShellOnNavigated; - - // A Shell is also a Page - HandlePageEvents(shell, bind: false); - } } internal void HandlePageEvents(Page page, bool bind = true) { + // Lifecycle events + // https://docs.microsoft.com/dotnet/maui/fundamentals/shell/lifecycle + page.Appearing -= OnPageOnAppearing; + page.Disappearing -= OnPageOnDisappearing; + + // Navigation events + // https://github.com/dotnet/docs-maui/issues/583 + page.NavigatedTo -= OnPageOnNavigatedTo; + + // Layout changed event + // https://docs.microsoft.com/dotnet/api/xamarin.forms.ilayout.layoutchanged + page.LayoutChanged -= OnPageOnLayoutChanged; + if (bind) { // Lifecycle events @@ -296,21 +310,6 @@ internal void HandlePageEvents(Page page, bool bind = true) // https://docs.microsoft.com/dotnet/api/xamarin.forms.ilayout.layoutchanged page.LayoutChanged += OnPageOnLayoutChanged; } - else - { - // Lifecycle events - // https://docs.microsoft.com/dotnet/maui/fundamentals/shell/lifecycle - page.Appearing -= OnPageOnAppearing; - page.Disappearing -= OnPageOnDisappearing; - - // Navigation events - // https://github.com/dotnet/docs-maui/issues/583 - page.NavigatedTo -= OnPageOnNavigatedTo; - - // Layout changed event - // https://docs.microsoft.com/dotnet/api/xamarin.forms.ilayout.layoutchanged - page.LayoutChanged -= OnPageOnLayoutChanged; - } } // Application Events