Skip to content

Fix MauiView leaks detached platform views when SafeAreaEdges includes SoftInput - #35586

Merged
kubaflo merged 5 commits into
dotnet:inflight/currentfrom
KarthikRajaKalaimani:fix-35386
Jun 3, 2026
Merged

Fix MauiView leaks detached platform views when SafeAreaEdges includes SoftInput#35586
kubaflo merged 5 commits into
dotnet:inflight/currentfrom
KarthikRajaKalaimani:fix-35386

Conversation

@KarthikRajaKalaimani

@KarthikRajaKalaimani KarthikRajaKalaimani commented May 22, 2026

Copy link
Copy Markdown
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Issue Details:

Every MauiView that uses SafeAreaEdges.SoftInput stays alive in memory after being removed from the screen. Users saw platform=12/12 views never getting released in iOS and Mac platform.

Root Cause:

When a MAUI view is configured with SafeAreaEdges.SoftInput on iOS or MacCatalyst, MauiView.SubscribeToKeyboardNotifications() registers two observers with NSNotificationCenter.DefaultCenter — one for UIKeyboard.WillShowNotification and one for UIKeyboard.WillHideNotification. Each call to AddObserver returns an NSObject token that the notification center holds strongly. Because the callbacks (OnKeyboardWillShow, OnKeyboardWillHide) are instance methods, the delegate objects capture a strong reference to this — the MauiView instance. This creates an unbroken retain chain: NSNotificationCenter → NSObject token → delegate → MauiView. As long as those observer tokens are registered, the notification center transitively keeps every subscribed MauiView alive, regardless of whether the view has been removed from the visual tree, its handler disconnected, and all MAUI-side references dropped.

The reason the tokens were never removed on detach comes down to a single guard condition in UpdateKeyboardSubscription(). The method was structured as if (Window != null) { ... }, meaning all subscription management — both subscribe and unsubscribe — was gated on the view being attached to a window. When MovedToWindow() fires with Window == null (the standard UIKit signal that a view has been removed from the hierarchy), UpdateKeyboardSubscription() was called but immediately fell through without doing anything. UnsubscribeFromKeyboardNotifications() was never reached, leaving the observer tokens live in the notification center indefinitely. The result, confirmed by the sandbox repro, was platform=12/12 alive after 12 forced GC cycles for views using SafeAreaEdges.SoftInput, versus platform=0/12 for the control case.

Description of Change:

The fix flattens the conditional in UpdateKeyboardSubscription() so that the else branch — which calls UnsubscribeFromKeyboardNotifications() — fires for all cases where the view should not be actively subscribed, including detach. The original nested structure if (Window != null) { if (ShouldSubscribe) subscribe; else unsubscribe; } is replaced with if (Window != null && ShouldSubscribeToKeyboardNotifications()) { SubscribeToKeyboardNotifications(); } else { UnsubscribeFromKeyboardNotifications(); }. Now when MovedToWindow() fires with Window == null, the condition evaluates to false and UnsubscribeFromKeyboardNotifications() is called, issuing NSNotificationCenter.DefaultCenter.RemoveObserver(token) for both keyboard observers. This severs the retain chain and allows the MauiView to be collected normally by the GC. The change is 9 lines, touches a single method, and introduces no new state or lifecycle hooks.

Tested the behavior in the following platforms:

  • Android
  • Windows
  • iOS
  • Mac

Reference:

N/A

Issues Fixed:

Fixes #35386

Screenshots

Before After
@github-actions

github-actions Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 35586

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 35586"
@dotnet-policy-service dotnet-policy-service Bot added the community ✨ Community Contribution label May 22, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Hey there @@KarthikRajaKalaimani! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@dotnet-policy-service dotnet-policy-service Bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label May 22, 2026
@github-actions github-actions Bot added area-safearea Issues/PRs that have to do with the SafeArea functionality platform/ios labels May 22, 2026
@sheiksyedm
sheiksyedm marked this pull request as ready for review May 22, 2026 12:51
@kubaflo

kubaflo commented May 22, 2026

Copy link
Copy Markdown
Collaborator

/review -b feature/refactor-copilot-yml

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expert Review — 2 findings

See inline comments for details.

Comment thread src/Core/src/Platform/iOS/MauiView.cs
{
App.WaitForElement("statusLabel");
Assert.That(
App.WaitForTextToBePresentInElement("statusLabel", "Suspect SafeAreaEdges.SoftInput: virtual=0/12, handler=0/12, platform=0/12", timeout: TimeSpan.FromSeconds(25)),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[moderate] Test Quality — The 25s timeout is tight for this page: it runs two 12-cycle scenarios with fixed waits plus repeated forced GC/finalizer cycles. On iOS CI/device runs, GC and UI scheduling can easily push this past 25s even when the fix is correct. Increase the timeout or signal completion more deterministically to avoid flaking unrelated to the leak.

@MauiBot MauiBot added s/agent-review-incomplete s/agent-fix-win AI found a better alternative fix than the PR s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels May 22, 2026
@MauiBot

This comment has been minimized.

@kubaflo

kubaflo commented May 23, 2026

Copy link
Copy Markdown
Collaborator

/review -b feature/refactor-copilot-yml

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expert Review — 1 findings

See inline comments for details.

Comment thread src/Core/src/Platform/iOS/MauiView.cs

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please check the ai's suggestions?

@kubaflo

kubaflo commented May 24, 2026

Copy link
Copy Markdown
Collaborator

/review -b feature/refactor-copilot-yml

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expert Review — 1 findings

See inline comments for details.

Comment thread src/Core/src/Platform/iOS/MauiView.cs

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please check the ai's suggestions?

… it) (dotnet#35714)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

Follow-up to @kubaflo's review on dotnet#35687.

## What

In `eng/pipelines/ci-copilot.yml`, when `parameters.Platform ==
'android'`, the Android AVD was being created twice:

1. **First**, via `common/provision.yml` running the
`ProvisionAndroidSdkAvdCreateAvds` MSBuild target — because
`skipAndroidCreateAvds: ${{ ne(parameters.Platform, 'android') }}`
evaluated to `false` for Android. That target invokes `dotnet android
avd create --name "Emulator_30" … --force`.
2. **Then**, the inline `Create AVD and boot Android Emulator` script
ran `avdmanager create avd -n Emulator_30 -k
"system-images;android-30;google_apis_playstore;x86_64" --device "Nexus
5X" --force`.

Both create the same AVD name with `--force`, so the second silently
overwrites the first — no error, just ~30–60s wasted on every Copilot
review pipeline run for Android.

The inline script is the canonical source of truth: it pins the
`google_apis_playstore` image variant, the `Nexus 5X` device profile,
the `disk.dataPartition.size=2048m` shrink, and ADB key pre-auth. None
of those are applied by `ProvisionAndroidSdkAvdCreateAvds`. So the right
fix is to skip the provision step entirely and let the inline script own
AVD creation.

## Change

Pinned `skipAndroidCreateAvds: true` (with an explanatory comment) at
both call sites of `common/provision.yml` in `ci-copilot.yml` (the
ReviewPR stage and the Deep stage). The inline `avdmanager` blocks are
untouched.

This is the AVD-creation portion of dotnet#35376 being reverted — the inline
script that same PR added already handles AVD creation, so the
provision-step AVD creation was redundant.

## Scope

This change is scoped to **`ci-copilot.yml`** only — the Copilot review
pipeline. It does **not** touch the required gating pipelines:
- `maui-pr`
- `maui-pr-devicetests`
- `maui-pr-uitests`

## Follow-up

Needs to be ported to `net11.0` afterward via the automated
`merge/main-to-net11.0` flow.

Co-authored-by: bot <bot@test>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@KarthikRajaKalaimani

Copy link
Copy Markdown
Contributor Author

Could you please check the ai's suggestions?

addressed Ai summary concerns

@kubaflo

kubaflo commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

/review -b feature/enhanced-reviewer

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expert Review — 1 findings

See inline comments for details.

}
else
{
UnsubscribeFromKeyboardNotifications();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[major] Safe Area and Window Insets - This unsubscribe path now handles both detached views and attached runtime transitions away from SoftInput, but UnsubscribeFromKeyboardNotifications() clears _isKeyboardShowing without scheduling layout. In the attached case, for example when keyboard is open and SafeAreaEdges changes from SoftInput or All to Container or None, the old keyboard safe-area padding can remain applied until some unrelated layout pass, regressing the stale-padding fix from issue 34846 and PR 35083. Please distinguish the detach case, where Window is null and clearing without layout avoids retaining detached views, from the attached no-SoftInput case, which should clear through ClearKeyboardState()/SetNeedsLayout().

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review Summary

@KarthikRajaKalaimani — new AI review results are available based on this last commit: 7e43412.
Improved fix and test case To request a fresh review after new comments or commits, comment /review rerun.

Gate Passed Code Review In Review Confidence Medium Platform iOS

Review Sessions — click to expand
Gate — Test Before & After Fix

Gate Result: ✅ PASSED

Platform: IOS · Base: main · Merge base: e904e900

Test Without Fix (expect FAIL) With Fix (expect PASS)
🖥️ Issue35386 Issue35386 ✅ FAIL — 352s ✅ PASS — 132s
🔴 Without fix — 🖥️ Issue35386: FAIL ✅ · 352s
  Determining projects to restore...
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 533 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 623 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 6.06 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 6.22 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/maps/src/Maps.csproj (in 6.23 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 6.24 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 6.24 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 6.24 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 6.24 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 6.26 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 6.27 sec).
/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0-ios26.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0-ios26.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0-ios26.0/Microsoft.Maui.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Maps.dll
  Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Controls.Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Maps.dll
  Controls.Foldable -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Foldable.dll
  Controls.Xaml -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Xaml.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Microsoft.AspNetCore.Components.WebView.Maui -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-ios26.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Detected signing identity:
    Code Signing Key: "" (-)
    Provisioning Profile: "" () - no entitlements
    Bundle Id: com.microsoft.maui.uitests
    App Id: com.microsoft.maui.uitests
  Controls.TestCases.HostApp -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-ios/iossimulator-arm64/Controls.TestCases.HostApp.dll
  Optimizing assemblies for size may change the behavior of the app. Be sure to test after publishing. See: https://aka.ms/dotnet-illink
  Optimizing assemblies for size. This process might take a while.

Build succeeded.

/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
    1 Warning(s)
    0 Error(s)

Time Elapsed 00:02:38.84
  Determining projects to restore...
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 733 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj (in 733 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Core/UITest.Core.csproj (in 733 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 758 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 754 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/VisualTestUtils/VisualTestUtils.csproj (in 3 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 829 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 857 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 1.48 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Appium/UITest.Appium.csproj (in 1.95 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Analyzers/UITest.Analyzers.csproj (in 2.3 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/VisualTestUtils.MagickNet/VisualTestUtils.MagickNet.csproj (in 3.75 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.iOS.Tests/Controls.TestCases.iOS.Tests.csproj (in 3.78 sec).
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  Controls.CustomAttributes -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  UITest.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
  VisualTestUtils -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
  VisualTestUtils.MagickNet -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
  UITest.NUnit -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
  UITest.Appium -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
  UITest.Analyzers -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
  Controls.TestCases.iOS.Tests -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
Test run for /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (arm64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.07]   Discovering: Controls.TestCases.iOS.Tests
[xUnit.net 00:00:00.19]   Discovered:  Controls.TestCases.iOS.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
   NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 6/3/2026 5:01:50 AM FixtureSetup for Issue35386(iOS)
>>>>> 6/3/2026 5:01:54 AM SoftInputSafeArea_DetachedPlatformViews_DoNotLeak Start
>>>>> 6/3/2026 5:02:55 AM SoftInputSafeArea_DetachedPlatformViews_DoNotLeak Stop
>>>>> 6/3/2026 5:02:55 AM Log types: syslog, crashlog, performance, safariConsole, safariNetwork, server
  Failed SoftInputSafeArea_DetachedPlatformViews_DoNotLeak [1 m 1 s]
  Error Message:
     The status label did not reach the expected SoftInput summary text.
Assert.That(App.WaitForTextToBePresentInElement("statusLabel", "Suspect SafeAreaEdges.SoftInput: virtual=0/12, handler=0/12, platform=0/12", timeout: TimeSpan.FromSeconds(60)), Is.True)
  Expected: True
  But was:  False

  Stack Trace:
     at Microsoft.Maui.TestCases.Tests.Issues.Issue35386.SoftInputSafeArea_DetachedPlatformViews_DoNotLeak() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35386.cs:line 19

1)    at Microsoft.Maui.TestCases.Tests.Issues.Issue35386.SoftInputSafeArea_DetachedPlatformViews_DoNotLeak() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35386.cs:line 19


NUnit Adapter 4.5.0.0: Test execution complete
Results File: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35386.trx

Total tests: 1
Test Run Failed.
     Failed: 1
 Total time: 2.4051 Minutes
>>> TRX_RESULT_FILE: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35386.trx

🟢 With fix — 🖥️ Issue35386: PASS ✅ · 132s
  Determining projects to restore...
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 376 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 399 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 404 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 448 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 463 ms).
  6 of 11 projects are up-to-date for restore.
/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0-ios26.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0-ios26.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0-ios26.0/Microsoft.Maui.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Maps.dll
  Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Microsoft.AspNetCore.Components.WebView.Maui -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-ios26.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Foldable -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Foldable.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Controls.Xaml -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Xaml.dll
  Controls.Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Maps.dll
  Detected signing identity:
    Code Signing Key: "" (-)
    Provisioning Profile: "" () - no entitlements
    Bundle Id: com.microsoft.maui.uitests
    App Id: com.microsoft.maui.uitests
  Controls.TestCases.HostApp -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-ios/iossimulator-arm64/Controls.TestCases.HostApp.dll
  Optimizing assemblies for size may change the behavior of the app. Be sure to test after publishing. See: https://aka.ms/dotnet-illink
  Optimizing assemblies for size. This process might take a while.

Build succeeded.

/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
    1 Warning(s)
    0 Error(s)

Time Elapsed 00:00:55.81
  Determining projects to restore...
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 455 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 464 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 471 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 498 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 463 ms).
  8 of 13 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Controls.CustomAttributes -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14270477
  Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  UITest.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
  VisualTestUtils -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
  UITest.Appium -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
  VisualTestUtils.MagickNet -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
  UITest.NUnit -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
  UITest.Analyzers -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
  Controls.TestCases.iOS.Tests -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
Test run for /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (arm64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.05]   Discovering: Controls.TestCases.iOS.Tests
[xUnit.net 00:00:00.17]   Discovered:  Controls.TestCases.iOS.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
   NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 6/3/2026 5:04:39 AM FixtureSetup for Issue35386(iOS)
>>>>> 6/3/2026 5:04:44 AM SoftInputSafeArea_DetachedPlatformViews_DoNotLeak Start
>>>>> 6/3/2026 5:05:08 AM SoftInputSafeArea_DetachedPlatformViews_DoNotLeak Stop
  Passed SoftInputSafeArea_DetachedPlatformViews_DoNotLeak [24 s]
NUnit Adapter 4.5.0.0: Test execution complete
Results File: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35386.trx

Test Run Successful.
Total tests: 1
     Passed: 1
 Total time: 45.3598 Seconds
>>> TRX_RESULT_FILE: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35386.trx

📁 Fix files reverted (2 files)
  • eng/pipelines/ci-copilot.yml
  • src/Core/src/Platform/iOS/MauiView.cs

UI Tests — SafeAreaEdges,ViewBaseTests

Detected UI test categories: SafeAreaEdges,ViewBaseTests

Deep UI tests — 77 passed, 103 failed across 2 categories on platform-pool agent (replaces in-process counts above).

🧪 UI Test Execution Results (deep, platform pool)

Category Tests Snapshot diffs
SafeAreaEdges 64/68 (4 ❌) 4 diff PNGs
ViewBaseTests 13/112 (99 ❌) 99 diff PNGs
SafeAreaEdges — 4 failed tests
LayoutShouldBeCorrectOnFirstNavigation
System.InvalidOperationException : 
Snapshot different than baseline: LayoutShouldBeCorrectOnFirstNavigation.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.

More info: https://aka.ms/visual-test-workflow


iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
  xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0

Then run the tests targeting the new simulator.
  ----> VisualTestUtils.VisualTestFailedException : 
Snapshot different than baseline: LayoutShouldBeCorrectOnFirstNavigation.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image
...
ToolbarExtendsAllTheWayLeftAndRight_FlyoutPage
System.InvalidOperationException : 
Snapshot different than baseline: ToolbarExtendsAllTheWayLeftAndRight_FlyoutPage.png (size differs - baseline is 2436x974 pixels, actual is 2622x1056 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.

More info: https://aka.ms/visual-test-workflow


iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
  xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0

Then run the tests targeting the new simulator.
  ----> VisualTestUtils.VisualTestFailedException : 
Snapshot different than baseline: ToolbarExtendsAllTheWayLeftAndRight_FlyoutPage.png (size differs - baseline is 2436x974 pixels, actual is 2622x1056 pixels)
If the correct baseline has changed (this isn't a a bug), then update the 
...
ToolbarExtendsAllTheWayLeftAndRight_NavigationPage
System.InvalidOperationException : 
Snapshot different than baseline: ToolbarExtendsAllTheWayLeftAndRight_NavigationPage.png (size differs - baseline is 2436x974 pixels, actual is 2622x1056 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.

More info: https://aka.ms/visual-test-workflow


iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
  xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0

Then run the tests targeting the new simulator.
  ----> VisualTestUtils.VisualTestFailedException : 
Snapshot different than baseline: ToolbarExtendsAllTheWayLeftAndRight_NavigationPage.png (size differs - baseline is 2436x974 pixels, actual is 2622x1056 pixels)
If the correct baseline has changed (this isn't a a bug), then upd
...
ToolbarExtendsAllTheWayLeftAndRight_Shell
System.InvalidOperationException : 
Snapshot different than baseline: ToolbarExtendsAllTheWayLeftAndRight_Shell.png (size differs - baseline is 2436x974 pixels, actual is 2622x1056 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.

More info: https://aka.ms/visual-test-workflow


iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
  xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0

Then run the tests targeting the new simulator.
  ----> VisualTestUtils.VisualTestFailedException : 
Snapshot different than baseline: ToolbarExtendsAllTheWayLeftAndRight_Shell.png (size differs - baseline is 2436x974 pixels, actual is 2622x1056 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline i
...
ViewBaseTests — 99 failed tests
Image_ClipWithComplexPolyLineGeometry
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ClipFeatureTests.Image_ClipWithComplexPolyLineGeometry() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ClipFeatureTests.cs:line 1026
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Ref
...
Image_ClipWithRectangleGeometry
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ClipFeatureTests.Image_ClipWithRectangleGeometry() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ClipFeatureTests.cs:line 287
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection
...
BoxView_ClipWithCornerRadius
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ClipFeatureTests.BoxView_ClipWithCornerRadius() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ClipFeatureTests.cs:line 176
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.Ru
...
Border_ClipWithStrokeShapeRoundRectangle
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ClipFeatureTests.Border_ClipWithStrokeShapeRoundRectangle() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ClipFeatureTests.cs:line 109
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.R
...
DefaultContentWithFlowDirection
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ContentViewFeatureTests.DefaultContentWithFlowDirection() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ContentViewFeatureTests.cs:line 172
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at Sys
...
ImageButton_ClipWithShadow
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ClipFeatureTests.ImageButton_ClipWithShadow() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ClipFeatureTests.cs:line 662
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.Runt
...
LightTheme_EditorAndPlaceholderColor_VerifyVisualState
System.InvalidOperationException : 
Snapshot different than baseline: LightTheme_EditorAndPlaceholderColor_VerifyVisualState.png (size differs - baseline is 1124x1126 pixels, actual is 1206x1312 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.

More info: https://aka.ms/visual-test-workflow


iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
  xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0

Then run the tests targeting the new simulator.
  ----> VisualTestUtils.VisualTestFailedException : 
Snapshot different than baseline: LightTheme_EditorAndPlaceholderColor_VerifyVisualState.png (size differs - baseline is 1124x1126 pixels, actual is 1206x1312 pixels)
If the correct baseline has changed (this isn't a a bug)
...
SecondCustomPageWithFlowDirectionChanged
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ContentViewFeatureTests.SecondCustomPageWithFlowDirectionChanged() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ContentViewFeatureTests.cs:line 333
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)

...
VisualTransform_AnchorX_ScaleYWithRotation
System.InvalidOperationException : 
Snapshot different than baseline: VisualTransform_AnchorX_ScaleYWithRotation.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.

More info: https://aka.ms/visual-test-workflow


iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
  xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0

Then run the tests targeting the new simulator.
  ----> VisualTestUtils.VisualTestFailedException : 
Snapshot different than baseline: VisualTransform_AnchorX_ScaleYWithRotation.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseli
...
VisualTransform_ScaleWithAnchorXAndRotationY
System.InvalidOperationException : 
Snapshot different than baseline: VisualTransform_ScaleWithAnchorXAndRotationY.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.

More info: https://aka.ms/visual-test-workflow


iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
  xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0

Then run the tests targeting the new simulator.
  ----> VisualTestUtils.VisualTestFailedException : 
Snapshot different than baseline: VisualTransform_ScaleWithAnchorXAndRotationY.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the ba
...
VisualTransform_RotationXWithScaleX
System.InvalidOperationException : 
Snapshot different than baseline: VisualTransform_RotationXWithScaleX.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.

More info: https://aka.ms/visual-test-workflow


iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
  xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0

Then run the tests targeting the new simulator.
  ----> VisualTestUtils.VisualTestFailedException : 
Snapshot different than baseline: VisualTransform_RotationXWithScaleX.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See 
...
VisualTransform_AnchorY_ScaleWithRotationY
System.InvalidOperationException : 
Snapshot different than baseline: VisualTransform_AnchorY_ScaleWithRotationY.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.

More info: https://aka.ms/visual-test-workflow


iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
  xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0

Then run the tests targeting the new simulator.
  ----> VisualTestUtils.VisualTestFailedException : 
Snapshot different than baseline: VisualTransform_AnchorY_ScaleWithRotationY.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseli
...
ContentView_ClipNull_NoCrash
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ClipFeatureTests.ContentView_ClipNull_NoCrash() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ClipFeatureTests.cs:line 785
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.Ru
...
Border_ClipWithRotationAndScale
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ClipFeatureTests.Border_ClipWithRotationAndScale() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ClipFeatureTests.cs:line 1086
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflectio
...
Border_ClipNull_NoCrash
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ClipFeatureTests.Border_ClipNull_NoCrash() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ClipFeatureTests.cs:line 695
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.Runtime
...
Image_ClipWithBezierSegmentPath
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ClipFeatureTests.Image_ClipWithBezierSegmentPath() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ClipFeatureTests.cs:line 383
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection
...
ImageButton_ClipWithRoundRectangleGeometry
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ClipFeatureTests.ImageButton_ClipWithRoundRectangleGeometry() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ClipFeatureTests.cs:line 641
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System
...
DarkTheme_EditorAndPlaceholderColor_VerifyVisualState
System.InvalidOperationException : 
Snapshot different than baseline: DarkTheme_EditorAndPlaceholderColor_VerifyVisualState.png (size differs - baseline is 1124x1126 pixels, actual is 1206x1312 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.

More info: https://aka.ms/visual-test-workflow


iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
  xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0

Then run the tests targeting the new simulator.
  ----> VisualTestUtils.VisualTestFailedException : 
Snapshot different than baseline: DarkTheme_EditorAndPlaceholderColor_VerifyVisualState.png (size differs - baseline is 1124x1126 pixels, actual is 1206x1312 pixels)
If the correct baseline has changed (this isn't a a bug), 
...
VisualTransform_RotationWithRotationX
System.InvalidOperationException : 
Snapshot different than baseline: VisualTransform_RotationWithRotationX.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.

More info: https://aka.ms/visual-test-workflow


iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
  xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0

Then run the tests targeting the new simulator.
  ----> VisualTestUtils.VisualTestFailedException : 
Snapshot different than baseline: VisualTransform_RotationWithRotationX.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.

...
LightTheme_Editor_VerifyVisualState
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.AppThemeFeatureTests.LightTheme_Editor_VerifyVisualState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/AppThemeFeatureTests.cs:line 276
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at Syste
...
LightTheme_VerifyVisualState
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.AppThemeFeatureTests.LightTheme_VerifyVisualState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/AppThemeFeatureTests.cs:line 31
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
Image_ClipWithLineSegmentPath
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ClipFeatureTests.Image_ClipWithLineSegmentPath() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ClipFeatureTests.cs:line 351
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.R
...
Button_ClipWithText
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ClipFeatureTests.Button_ClipWithText() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ClipFeatureTests.cs:line 243
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.RuntimeMeth
...
FirstCustomPageWithFlowDirection
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ContentViewFeatureTests.FirstCustomPageWithFlowDirection() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ContentViewFeatureTests.cs:line 245
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at Sy
...
DarkTheme_CheckBox_VerifyVisualState
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.AppThemeFeatureTests.DarkTheme_CheckBox_VerifyVisualState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/AppThemeFeatureTests.cs:line 67
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
VisualTransform_IsVisible
System.InvalidOperationException : 
Snapshot different than baseline: VisualTransform_IsVisible.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.

More info: https://aka.ms/visual-test-workflow


iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
  xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0

Then run the tests targeting the new simulator.
  ----> VisualTestUtils.VisualTestFailedException : 
Snapshot different than baseline: VisualTransform_IsVisible.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or d
...
DarkTheme_Slider_VerifyVisualState
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.AppThemeFeatureTests.DarkTheme_Slider_VerifyVisualState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/AppThemeFeatureTests.cs:line 174
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System
...
Image_ClipWithPolyQuadraticBezierSegmentPath
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ClipFeatureTests.Image_ClipWithPolyQuadraticBezierSegmentPath() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ClipFeatureTests.cs:line 447
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at Syst
...
Border_ClipWithShadow
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ClipFeatureTests.Border_ClipWithShadow() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ClipFeatureTests.cs:line 130
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.RuntimeMe
...
DefaultContentWithHeightRequest
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.ContentViewFeatureTests.DefaultContentWithHeightRequest() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/ContentViewFeatureTests.cs:line 119
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at Sys
...

(+69 more — see TRX in artifact)

📎 Download drop-deep-uitests artifact (TRX + snapshot diffs)


Regression Cross-Reference

🔍 Regression Cross-Reference

🟡 Overlaps with prior bug-fix PRs — same files modified, but no exact line revert detected.

File Fix PR Fixed issue(s)
src/Core/src/Platform/iOS/MauiView.cs #34024 #32586, #33934, #33595, #34042

🧪 Regression Tests to Verify

These tests were added by the overlapping fix PRs. Running them to verify no side-effect regressions:

Fix PR Type Test Filter
#34024 UITest Issue28986_ParentChildTest Issue28986_ParentChildTest
#34024 UITest Issue32586 Issue32586
#34024 UITest Issue33595 Issue33595
#34024 UITest Issue33934 Issue33934

🧪 Regression Test Results

FAILED — 0 passed, 4 failed, 0 skipped

Fix PR Test Type Result
#34024 Issue28986_ParentChildTest UITest ❌ FAILED
#34024 Issue32586 UITest ❌ FAILED
#34024 Issue33595 UITest ❌ FAILED
#34024 Issue33934 UITest ❌ FAILED

Pre-Flight — Context & Validation

Issue: #35386 - MauiView leaks detached platform views when SafeAreaEdges includes SoftInput
PR: #35586 - Fix MauiView leaks detached platform views when SafeAreaEdges includes SoftInput
Platforms Affected: iOS, MacCatalyst
Files Changed: 1 implementation, 2 test

Key Findings

  • MauiView subscribes to UIKeyboard.WillShowNotification and UIKeyboard.WillHideNotification when SafeAreaEdges includes SoftInput; observer callbacks can retain detached MauiView instances if tokens are not removed.
  • The PR fix unsubscribes when Window == null, which breaks the notification-center retain chain on detach.
  • The PR also clears keyboard state without calling SetNeedsLayout(), which is correct for detached views but less precise for attached runtime transitions away from SoftInput.
  • GitHub CLI authentication was unavailable, so PR metadata/comments were gathered from public PR HTML and local branch diff instead of authenticated gh pr view/review-comment APIs.

Code Review Summary

Verdict: NEEDS_DISCUSSION
Confidence: medium
Errors: 0 | Warnings: 1 | Suggestions: 0

Key code review findings:
src/Core/src/Platform/iOS/MauiView.cs:329- attached unsubscribe no longer requests layout when clearing visible-keyboard state; detach and attached runtime changes should use different cleanup semantics.367 -

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #35586 Flatten so unsubscribes keyboard observers; clear stale keyboard state without layout. PASSED (Gate pre-run) src/Core/src/Platform/iOS/MauiView.cs Fixes leak, but uses the same no-layout cleanup for detached and attached unsubscribe paths.

Code Review — Deep Analysis

Code PR #35586Review

Independent Assessment

What this changes: MauiView removes iOS/MacCatalyst keyboard notification observers when a view using SafeAreaEdges.SoftInput is no longer eligible for keyboard-aware safe-area adjustment, and the PR adds a UI leak regression test.
Inferred motivation: NSNotificationCenter observer tokens can retain callbacks that retain the MauiView; if detach does not remove those tokens, detached platform views stay alive.

Reconciliation with PR Narrative

Author claims: Detached MauiView instances leak because UpdateKeyboardSubscription() previously skipped all subscription management when Window == null; flattening the condition makes detach unsubscribe. The PR also clears keyboard state without scheduling layout while detached.
Agreement/disagreement: The leak root cause matches the code and the PR fix addresses it. The main tradeoff is that the PR's unconditional unsubscribe path suppresses SetNeedsLayout() for attached runtime transitions away from SoftInput, which can leave attached views with stale keyboard padding until another layout occurs.

Findings

Attached unsubscribe no longer requests layout when keyboard state is clearedWarning ####
src/Core/src/Platform/iOS/MauiView.cs:329-367

The PR changed UnsubscribeFromKeyboardNotifications() so clearing _isKeyboardShowing only sets _safeAreaInvalidated and no longer calls SetNeedsLayout(). That is appropriate for detached views, but for an attached view whose SafeAreaEdges changes away from SoftInput while the keyboard is visible, the old ClearKeyboardState() behavior requested layout immediately. A reason-aware detach path would preserve no-layout cleanup for detached views while keeping layout invalidation for attached runtime changes.

Devil's Advocate

The PR's existing tests and gate pass, and detached views should not schedule layout. The warning matters only for attached runtime SafeAreaEdges transitions while the keyboard is visible; however, this code already supports runtime subscription updates, and preserving attached layout invalidation is safer with minimal extra complexity.

Verdict: NEEDS_DISCUSSION

Confidence: medium
Summary: The PR fix resolves the leak, but a slightly more explicit attached-vs-detached unsubscribe model is more robust and avoids changing attached runtime layout behavior. No GitHub comments were posted because this run only writes local PR-agent artifacts.


Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix-1 Reason-aware unsubscribe: detached cleanup removes keyboard observers and clears stale state without layout; attached cleanup preserves and . PASS 1 file Better than PR fix because it preserves attached runtime layout behavior while still fixing the detach leak.
PR PR #35586 Flatten so any non-subscribed state, including detach, unsubscribes keyboard observers. PASSED (Gate) 1 implementation file, 2 test files Original PR fix is correct for the leak but less precise about detached vs attached cleanup semantics.

Cross-Pollination

Model Round New Ideas? Details
maui-expert-reviewer 1 Yes Recommended reason-aware unsubscribe as the best surgical alternative; other options included explicit MovedToWindow() cleanup, weak notification callbacks, and a subscription state machine.

Exhausted: stopped because Candidate #1 passed the primary test and all mandatory regressions and is demonstrably better than the PR fix.No
Selected Fix: Candidate # preserves the PR's leak fix while retaining correct attached-view layout invalidation semantics.1


Report — Final Recommendation

Comparative Report — PR #35586

Candidate Ranking

Rank Candidate Result Assessment
1 pr-plus-reviewer PASS by equivalence to try-fix-1 evidence Best candidate. It keeps the PR's observer-unsubscribe leak fix and applies expert feedback to distinguish detached cleanup from attached runtime SoftInput cleanup.
2 try-fix-1 PASS Functionally equivalent to pr-plus-reviewer and passed the primary Issue35386 test plus mandatory iOS safe-area regressions. Ranked below pr-plus-reviewer only because the requested expert-review phase applies this improvement as a PR-fix candidate.
3 pr Gate PASS, regression FAIL Fixes the detached observer leak, but failed saved overlapping regression checks and has an expert finding: attached runtime unsubscribe clears keyboard state without SetNeedsLayout(), risking stale safe-area padding regressions.

Analysis

pr correctly identifies the leak root cause: MauiView subscribes to UIKeyboard.WillShowNotification and WillHideNotification for SafeAreaEdges.SoftInput, and detached views must remove those notification observers to break the retain chain. The gate result confirms the raw PR makes the new Issue35386 leak test pass after failing without the fix.

The problem with pr is that it flattens all unsubscribe reasons into the same cleanup behavior. That is safe for detached views, where layout should not be scheduled, but less safe for attached views that stop using SoftInput while the keyboard is visible. Those attached views still need ClearKeyboardState() to request layout and remove keyboard-derived safe-area padding promptly. The saved regression-check result ranks pr lower because overlapping safe-area regression tests failed.

try-fix-1 implements the expert recommendation: reason-aware unsubscribe. Detached cleanup clears _keyboardFrame, _isKeyboardShowing, and _safeAreaInvalidated without layout; attached cleanup calls ClearKeyboardState(). Its saved result is PASS, including Issue35386, Issue28986_ParentChildTest, Issue32586, Issue33595, and Issue33934.

pr-plus-reviewer is the same reason-aware improvement applied as expert-review feedback to the PR fix. It is the single winning candidate because it preserves the submitted PR's intent, addresses the expert review finding, and inherits the passing regression evidence from the equivalent try-fix-1 candidate.

Winner

pr-plus-reviewer


Future Action — review latest findings

No alternative fix was selected for this run. Review the session findings and CI results before merging.

@kubaflo
kubaflo changed the base branch from main to inflight/current June 3, 2026 17:17
@kubaflo
kubaflo merged commit 1087eb3 into dotnet:inflight/current Jun 3, 2026
32 checks passed
@github-actions github-actions Bot added this to the .NET 10.0 SR8 milestone Jun 3, 2026
PureWeen pushed a commit that referenced this pull request Jun 11, 2026
…s SoftInput (#35586)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details:

Every MauiView that uses SafeAreaEdges.SoftInput stays alive in memory
after being removed from the screen. Users saw platform=12/12 views
never getting released in iOS and Mac platform.
       
### Root Cause:

When a MAUI view is configured with SafeAreaEdges.SoftInput on iOS or
MacCatalyst, MauiView.SubscribeToKeyboardNotifications() registers two
observers with NSNotificationCenter.DefaultCenter — one for
UIKeyboard.WillShowNotification and one for
UIKeyboard.WillHideNotification. Each call to AddObserver returns an
NSObject token that the notification center holds strongly. Because the
callbacks (OnKeyboardWillShow, OnKeyboardWillHide) are instance methods,
the delegate objects capture a strong reference to this — the MauiView
instance. This creates an unbroken retain chain: NSNotificationCenter →
NSObject token → delegate → MauiView. As long as those observer tokens
are registered, the notification center transitively keeps every
subscribed MauiView alive, regardless of whether the view has been
removed from the visual tree, its handler disconnected, and all
MAUI-side references dropped.
 
The reason the tokens were never removed on detach comes down to a
single guard condition in UpdateKeyboardSubscription(). The method was
structured as if (Window != null) { ... }, meaning all subscription
management — both subscribe and unsubscribe — was gated on the view
being attached to a window. When MovedToWindow() fires with Window ==
null (the standard UIKit signal that a view has been removed from the
hierarchy), UpdateKeyboardSubscription() was called but immediately fell
through without doing anything. UnsubscribeFromKeyboardNotifications()
was never reached, leaving the observer tokens live in the notification
center indefinitely. The result, confirmed by the sandbox repro, was
platform=12/12 alive after 12 forced GC cycles for views using
SafeAreaEdges.SoftInput, versus platform=0/12 for the control case.

### Description of Change:

The fix flattens the conditional in UpdateKeyboardSubscription() so that
the else branch — which calls UnsubscribeFromKeyboardNotifications() —
fires for all cases where the view should not be actively subscribed,
including detach. The original nested structure if (Window != null) { if
(ShouldSubscribe) subscribe; else unsubscribe; } is replaced with if
(Window != null && ShouldSubscribeToKeyboardNotifications()) {
SubscribeToKeyboardNotifications(); } else {
UnsubscribeFromKeyboardNotifications(); }. Now when MovedToWindow()
fires with Window == null, the condition evaluates to false and
UnsubscribeFromKeyboardNotifications() is called, issuing
NSNotificationCenter.DefaultCenter.RemoveObserver(token) for both
keyboard observers. This severs the retain chain and allows the MauiView
to be collected normally by the GC. The change is 9 lines, touches a
single method, and introduces no new state or lifecycle hooks.

**Tested the behavior in the following platforms:**

- [x] Android
- [ ] Windows
- [x] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #35386         

### Screenshots
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/cbbd452a-6565-4e0b-a17d-12c83204bfe5"
Width="400" Height="600"/> | <img
src="https://github.com/user-attachments/assets/3ebbeba2-9fd1-42ac-a4d5-06d5184f2cc7"
Width="400" Height="600"/> |

---------
@sheiksyedm sheiksyedm modified the milestones: .NET 10 SR8, .NET 10 SR9 Jun 18, 2026
PureWeen pushed a commit that referenced this pull request Jun 22, 2026
…s SoftInput (#35586)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details:

Every MauiView that uses SafeAreaEdges.SoftInput stays alive in memory
after being removed from the screen. Users saw platform=12/12 views
never getting released in iOS and Mac platform.
       
### Root Cause:

When a MAUI view is configured with SafeAreaEdges.SoftInput on iOS or
MacCatalyst, MauiView.SubscribeToKeyboardNotifications() registers two
observers with NSNotificationCenter.DefaultCenter — one for
UIKeyboard.WillShowNotification and one for
UIKeyboard.WillHideNotification. Each call to AddObserver returns an
NSObject token that the notification center holds strongly. Because the
callbacks (OnKeyboardWillShow, OnKeyboardWillHide) are instance methods,
the delegate objects capture a strong reference to this — the MauiView
instance. This creates an unbroken retain chain: NSNotificationCenter →
NSObject token → delegate → MauiView. As long as those observer tokens
are registered, the notification center transitively keeps every
subscribed MauiView alive, regardless of whether the view has been
removed from the visual tree, its handler disconnected, and all
MAUI-side references dropped.
 
The reason the tokens were never removed on detach comes down to a
single guard condition in UpdateKeyboardSubscription(). The method was
structured as if (Window != null) { ... }, meaning all subscription
management — both subscribe and unsubscribe — was gated on the view
being attached to a window. When MovedToWindow() fires with Window ==
null (the standard UIKit signal that a view has been removed from the
hierarchy), UpdateKeyboardSubscription() was called but immediately fell
through without doing anything. UnsubscribeFromKeyboardNotifications()
was never reached, leaving the observer tokens live in the notification
center indefinitely. The result, confirmed by the sandbox repro, was
platform=12/12 alive after 12 forced GC cycles for views using
SafeAreaEdges.SoftInput, versus platform=0/12 for the control case.

### Description of Change:

The fix flattens the conditional in UpdateKeyboardSubscription() so that
the else branch — which calls UnsubscribeFromKeyboardNotifications() —
fires for all cases where the view should not be actively subscribed,
including detach. The original nested structure if (Window != null) { if
(ShouldSubscribe) subscribe; else unsubscribe; } is replaced with if
(Window != null && ShouldSubscribeToKeyboardNotifications()) {
SubscribeToKeyboardNotifications(); } else {
UnsubscribeFromKeyboardNotifications(); }. Now when MovedToWindow()
fires with Window == null, the condition evaluates to false and
UnsubscribeFromKeyboardNotifications() is called, issuing
NSNotificationCenter.DefaultCenter.RemoveObserver(token) for both
keyboard observers. This severs the retain chain and allows the MauiView
to be collected normally by the GC. The change is 9 lines, touches a
single method, and introduces no new state or lifecycle hooks.

**Tested the behavior in the following platforms:**

- [x] Android
- [ ] Windows
- [x] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #35386         

### Screenshots
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/cbbd452a-6565-4e0b-a17d-12c83204bfe5"
Width="400" Height="600"/> | <img
src="https://github.com/user-attachments/assets/3ebbeba2-9fd1-42ac-a4d5-06d5184f2cc7"
Width="400" Height="600"/> |

---------
kubaflo pushed a commit that referenced this pull request Jun 25, 2026
…s SoftInput (#35586)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details:

Every MauiView that uses SafeAreaEdges.SoftInput stays alive in memory
after being removed from the screen. Users saw platform=12/12 views
never getting released in iOS and Mac platform.
       
### Root Cause:

When a MAUI view is configured with SafeAreaEdges.SoftInput on iOS or
MacCatalyst, MauiView.SubscribeToKeyboardNotifications() registers two
observers with NSNotificationCenter.DefaultCenter — one for
UIKeyboard.WillShowNotification and one for
UIKeyboard.WillHideNotification. Each call to AddObserver returns an
NSObject token that the notification center holds strongly. Because the
callbacks (OnKeyboardWillShow, OnKeyboardWillHide) are instance methods,
the delegate objects capture a strong reference to this — the MauiView
instance. This creates an unbroken retain chain: NSNotificationCenter →
NSObject token → delegate → MauiView. As long as those observer tokens
are registered, the notification center transitively keeps every
subscribed MauiView alive, regardless of whether the view has been
removed from the visual tree, its handler disconnected, and all
MAUI-side references dropped.
 
The reason the tokens were never removed on detach comes down to a
single guard condition in UpdateKeyboardSubscription(). The method was
structured as if (Window != null) { ... }, meaning all subscription
management — both subscribe and unsubscribe — was gated on the view
being attached to a window. When MovedToWindow() fires with Window ==
null (the standard UIKit signal that a view has been removed from the
hierarchy), UpdateKeyboardSubscription() was called but immediately fell
through without doing anything. UnsubscribeFromKeyboardNotifications()
was never reached, leaving the observer tokens live in the notification
center indefinitely. The result, confirmed by the sandbox repro, was
platform=12/12 alive after 12 forced GC cycles for views using
SafeAreaEdges.SoftInput, versus platform=0/12 for the control case.

### Description of Change:

The fix flattens the conditional in UpdateKeyboardSubscription() so that
the else branch — which calls UnsubscribeFromKeyboardNotifications() —
fires for all cases where the view should not be actively subscribed,
including detach. The original nested structure if (Window != null) { if
(ShouldSubscribe) subscribe; else unsubscribe; } is replaced with if
(Window != null && ShouldSubscribeToKeyboardNotifications()) {
SubscribeToKeyboardNotifications(); } else {
UnsubscribeFromKeyboardNotifications(); }. Now when MovedToWindow()
fires with Window == null, the condition evaluates to false and
UnsubscribeFromKeyboardNotifications() is called, issuing
NSNotificationCenter.DefaultCenter.RemoveObserver(token) for both
keyboard observers. This severs the retain chain and allows the MauiView
to be collected normally by the GC. The change is 9 lines, touches a
single method, and introduces no new state or lifecycle hooks.

**Tested the behavior in the following platforms:**

- [x] Android
- [ ] Windows
- [x] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #35386         

### Screenshots
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/cbbd452a-6565-4e0b-a17d-12c83204bfe5"
Width="400" Height="600"/> | <img
src="https://github.com/user-attachments/assets/3ebbeba2-9fd1-42ac-a4d5-06d5184f2cc7"
Width="400" Height="600"/> |

---------
kubaflo pushed a commit that referenced this pull request Jul 3, 2026
…s SoftInput (#35586)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details:

Every MauiView that uses SafeAreaEdges.SoftInput stays alive in memory
after being removed from the screen. Users saw platform=12/12 views
never getting released in iOS and Mac platform.
       
### Root Cause:

When a MAUI view is configured with SafeAreaEdges.SoftInput on iOS or
MacCatalyst, MauiView.SubscribeToKeyboardNotifications() registers two
observers with NSNotificationCenter.DefaultCenter — one for
UIKeyboard.WillShowNotification and one for
UIKeyboard.WillHideNotification. Each call to AddObserver returns an
NSObject token that the notification center holds strongly. Because the
callbacks (OnKeyboardWillShow, OnKeyboardWillHide) are instance methods,
the delegate objects capture a strong reference to this — the MauiView
instance. This creates an unbroken retain chain: NSNotificationCenter →
NSObject token → delegate → MauiView. As long as those observer tokens
are registered, the notification center transitively keeps every
subscribed MauiView alive, regardless of whether the view has been
removed from the visual tree, its handler disconnected, and all
MAUI-side references dropped.
 
The reason the tokens were never removed on detach comes down to a
single guard condition in UpdateKeyboardSubscription(). The method was
structured as if (Window != null) { ... }, meaning all subscription
management — both subscribe and unsubscribe — was gated on the view
being attached to a window. When MovedToWindow() fires with Window ==
null (the standard UIKit signal that a view has been removed from the
hierarchy), UpdateKeyboardSubscription() was called but immediately fell
through without doing anything. UnsubscribeFromKeyboardNotifications()
was never reached, leaving the observer tokens live in the notification
center indefinitely. The result, confirmed by the sandbox repro, was
platform=12/12 alive after 12 forced GC cycles for views using
SafeAreaEdges.SoftInput, versus platform=0/12 for the control case.

### Description of Change:

The fix flattens the conditional in UpdateKeyboardSubscription() so that
the else branch — which calls UnsubscribeFromKeyboardNotifications() —
fires for all cases where the view should not be actively subscribed,
including detach. The original nested structure if (Window != null) { if
(ShouldSubscribe) subscribe; else unsubscribe; } is replaced with if
(Window != null && ShouldSubscribeToKeyboardNotifications()) {
SubscribeToKeyboardNotifications(); } else {
UnsubscribeFromKeyboardNotifications(); }. Now when MovedToWindow()
fires with Window == null, the condition evaluates to false and
UnsubscribeFromKeyboardNotifications() is called, issuing
NSNotificationCenter.DefaultCenter.RemoveObserver(token) for both
keyboard observers. This severs the retain chain and allows the MauiView
to be collected normally by the GC. The change is 9 lines, touches a
single method, and introduces no new state or lifecycle hooks.

**Tested the behavior in the following platforms:**

- [x] Android
- [ ] Windows
- [x] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #35386         

### Screenshots
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/cbbd452a-6565-4e0b-a17d-12c83204bfe5"
Width="400" Height="600"/> | <img
src="https://github.com/user-attachments/assets/3ebbeba2-9fd1-42ac-a4d5-06d5184f2cc7"
Width="400" Height="600"/> |

---------
@kubaflo kubaflo mentioned this pull request Jul 6, 2026
kubaflo pushed a commit that referenced this pull request Jul 6, 2026
…s SoftInput (#35586)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details:

Every MauiView that uses SafeAreaEdges.SoftInput stays alive in memory
after being removed from the screen. Users saw platform=12/12 views
never getting released in iOS and Mac platform.
       
### Root Cause:

When a MAUI view is configured with SafeAreaEdges.SoftInput on iOS or
MacCatalyst, MauiView.SubscribeToKeyboardNotifications() registers two
observers with NSNotificationCenter.DefaultCenter — one for
UIKeyboard.WillShowNotification and one for
UIKeyboard.WillHideNotification. Each call to AddObserver returns an
NSObject token that the notification center holds strongly. Because the
callbacks (OnKeyboardWillShow, OnKeyboardWillHide) are instance methods,
the delegate objects capture a strong reference to this — the MauiView
instance. This creates an unbroken retain chain: NSNotificationCenter →
NSObject token → delegate → MauiView. As long as those observer tokens
are registered, the notification center transitively keeps every
subscribed MauiView alive, regardless of whether the view has been
removed from the visual tree, its handler disconnected, and all
MAUI-side references dropped.
 
The reason the tokens were never removed on detach comes down to a
single guard condition in UpdateKeyboardSubscription(). The method was
structured as if (Window != null) { ... }, meaning all subscription
management — both subscribe and unsubscribe — was gated on the view
being attached to a window. When MovedToWindow() fires with Window ==
null (the standard UIKit signal that a view has been removed from the
hierarchy), UpdateKeyboardSubscription() was called but immediately fell
through without doing anything. UnsubscribeFromKeyboardNotifications()
was never reached, leaving the observer tokens live in the notification
center indefinitely. The result, confirmed by the sandbox repro, was
platform=12/12 alive after 12 forced GC cycles for views using
SafeAreaEdges.SoftInput, versus platform=0/12 for the control case.

### Description of Change:

The fix flattens the conditional in UpdateKeyboardSubscription() so that
the else branch — which calls UnsubscribeFromKeyboardNotifications() —
fires for all cases where the view should not be actively subscribed,
including detach. The original nested structure if (Window != null) { if
(ShouldSubscribe) subscribe; else unsubscribe; } is replaced with if
(Window != null && ShouldSubscribeToKeyboardNotifications()) {
SubscribeToKeyboardNotifications(); } else {
UnsubscribeFromKeyboardNotifications(); }. Now when MovedToWindow()
fires with Window == null, the condition evaluates to false and
UnsubscribeFromKeyboardNotifications() is called, issuing
NSNotificationCenter.DefaultCenter.RemoveObserver(token) for both
keyboard observers. This severs the retain chain and allows the MauiView
to be collected normally by the GC. The change is 9 lines, touches a
single method, and introduces no new state or lifecycle hooks.

**Tested the behavior in the following platforms:**

- [x] Android
- [ ] Windows
- [x] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #35386         

### Screenshots
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/cbbd452a-6565-4e0b-a17d-12c83204bfe5"
Width="400" Height="600"/> | <img
src="https://github.com/user-attachments/assets/3ebbeba2-9fd1-42ac-a4d5-06d5184f2cc7"
Width="400" Height="600"/> |

---------
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
…s SoftInput (#35586)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details:

Every MauiView that uses SafeAreaEdges.SoftInput stays alive in memory
after being removed from the screen. Users saw platform=12/12 views
never getting released in iOS and Mac platform.
       
### Root Cause:

When a MAUI view is configured with SafeAreaEdges.SoftInput on iOS or
MacCatalyst, MauiView.SubscribeToKeyboardNotifications() registers two
observers with NSNotificationCenter.DefaultCenter — one for
UIKeyboard.WillShowNotification and one for
UIKeyboard.WillHideNotification. Each call to AddObserver returns an
NSObject token that the notification center holds strongly. Because the
callbacks (OnKeyboardWillShow, OnKeyboardWillHide) are instance methods,
the delegate objects capture a strong reference to this — the MauiView
instance. This creates an unbroken retain chain: NSNotificationCenter →
NSObject token → delegate → MauiView. As long as those observer tokens
are registered, the notification center transitively keeps every
subscribed MauiView alive, regardless of whether the view has been
removed from the visual tree, its handler disconnected, and all
MAUI-side references dropped.
 
The reason the tokens were never removed on detach comes down to a
single guard condition in UpdateKeyboardSubscription(). The method was
structured as if (Window != null) { ... }, meaning all subscription
management — both subscribe and unsubscribe — was gated on the view
being attached to a window. When MovedToWindow() fires with Window ==
null (the standard UIKit signal that a view has been removed from the
hierarchy), UpdateKeyboardSubscription() was called but immediately fell
through without doing anything. UnsubscribeFromKeyboardNotifications()
was never reached, leaving the observer tokens live in the notification
center indefinitely. The result, confirmed by the sandbox repro, was
platform=12/12 alive after 12 forced GC cycles for views using
SafeAreaEdges.SoftInput, versus platform=0/12 for the control case.

### Description of Change:

The fix flattens the conditional in UpdateKeyboardSubscription() so that
the else branch — which calls UnsubscribeFromKeyboardNotifications() —
fires for all cases where the view should not be actively subscribed,
including detach. The original nested structure if (Window != null) { if
(ShouldSubscribe) subscribe; else unsubscribe; } is replaced with if
(Window != null && ShouldSubscribeToKeyboardNotifications()) {
SubscribeToKeyboardNotifications(); } else {
UnsubscribeFromKeyboardNotifications(); }. Now when MovedToWindow()
fires with Window == null, the condition evaluates to false and
UnsubscribeFromKeyboardNotifications() is called, issuing
NSNotificationCenter.DefaultCenter.RemoveObserver(token) for both
keyboard observers. This severs the retain chain and allows the MauiView
to be collected normally by the GC. The change is 9 lines, touches a
single method, and introduces no new state or lifecycle hooks.

**Tested the behavior in the following platforms:**

- [x] Android
- [ ] Windows
- [x] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #35386         

### Screenshots
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/cbbd452a-6565-4e0b-a17d-12c83204bfe5"
Width="400" Height="600"/> | <img
src="https://github.com/user-attachments/assets/3ebbeba2-9fd1-42ac-a4d5-06d5184f2cc7"
Width="400" Height="600"/> |

---------
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
…s SoftInput (#35586)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details:

Every MauiView that uses SafeAreaEdges.SoftInput stays alive in memory
after being removed from the screen. Users saw platform=12/12 views
never getting released in iOS and Mac platform.
       
### Root Cause:

When a MAUI view is configured with SafeAreaEdges.SoftInput on iOS or
MacCatalyst, MauiView.SubscribeToKeyboardNotifications() registers two
observers with NSNotificationCenter.DefaultCenter — one for
UIKeyboard.WillShowNotification and one for
UIKeyboard.WillHideNotification. Each call to AddObserver returns an
NSObject token that the notification center holds strongly. Because the
callbacks (OnKeyboardWillShow, OnKeyboardWillHide) are instance methods,
the delegate objects capture a strong reference to this — the MauiView
instance. This creates an unbroken retain chain: NSNotificationCenter →
NSObject token → delegate → MauiView. As long as those observer tokens
are registered, the notification center transitively keeps every
subscribed MauiView alive, regardless of whether the view has been
removed from the visual tree, its handler disconnected, and all
MAUI-side references dropped.
 
The reason the tokens were never removed on detach comes down to a
single guard condition in UpdateKeyboardSubscription(). The method was
structured as if (Window != null) { ... }, meaning all subscription
management — both subscribe and unsubscribe — was gated on the view
being attached to a window. When MovedToWindow() fires with Window ==
null (the standard UIKit signal that a view has been removed from the
hierarchy), UpdateKeyboardSubscription() was called but immediately fell
through without doing anything. UnsubscribeFromKeyboardNotifications()
was never reached, leaving the observer tokens live in the notification
center indefinitely. The result, confirmed by the sandbox repro, was
platform=12/12 alive after 12 forced GC cycles for views using
SafeAreaEdges.SoftInput, versus platform=0/12 for the control case.

### Description of Change:

The fix flattens the conditional in UpdateKeyboardSubscription() so that
the else branch — which calls UnsubscribeFromKeyboardNotifications() —
fires for all cases where the view should not be actively subscribed,
including detach. The original nested structure if (Window != null) { if
(ShouldSubscribe) subscribe; else unsubscribe; } is replaced with if
(Window != null && ShouldSubscribeToKeyboardNotifications()) {
SubscribeToKeyboardNotifications(); } else {
UnsubscribeFromKeyboardNotifications(); }. Now when MovedToWindow()
fires with Window == null, the condition evaluates to false and
UnsubscribeFromKeyboardNotifications() is called, issuing
NSNotificationCenter.DefaultCenter.RemoveObserver(token) for both
keyboard observers. This severs the retain chain and allows the MauiView
to be collected normally by the GC. The change is 9 lines, touches a
single method, and introduces no new state or lifecycle hooks.

**Tested the behavior in the following platforms:**

- [x] Android
- [ ] Windows
- [x] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #35386         

### Screenshots
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/cbbd452a-6565-4e0b-a17d-12c83204bfe5"
Width="400" Height="600"/> | <img
src="https://github.com/user-attachments/assets/3ebbeba2-9fd1-42ac-a4d5-06d5184f2cc7"
Width="400" Height="600"/> |

---------
kubaflo pushed a commit that referenced this pull request Jul 10, 2026
…s SoftInput (#35586)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details:

Every MauiView that uses SafeAreaEdges.SoftInput stays alive in memory
after being removed from the screen. Users saw platform=12/12 views
never getting released in iOS and Mac platform.
       
### Root Cause:

When a MAUI view is configured with SafeAreaEdges.SoftInput on iOS or
MacCatalyst, MauiView.SubscribeToKeyboardNotifications() registers two
observers with NSNotificationCenter.DefaultCenter — one for
UIKeyboard.WillShowNotification and one for
UIKeyboard.WillHideNotification. Each call to AddObserver returns an
NSObject token that the notification center holds strongly. Because the
callbacks (OnKeyboardWillShow, OnKeyboardWillHide) are instance methods,
the delegate objects capture a strong reference to this — the MauiView
instance. This creates an unbroken retain chain: NSNotificationCenter →
NSObject token → delegate → MauiView. As long as those observer tokens
are registered, the notification center transitively keeps every
subscribed MauiView alive, regardless of whether the view has been
removed from the visual tree, its handler disconnected, and all
MAUI-side references dropped.
 
The reason the tokens were never removed on detach comes down to a
single guard condition in UpdateKeyboardSubscription(). The method was
structured as if (Window != null) { ... }, meaning all subscription
management — both subscribe and unsubscribe — was gated on the view
being attached to a window. When MovedToWindow() fires with Window ==
null (the standard UIKit signal that a view has been removed from the
hierarchy), UpdateKeyboardSubscription() was called but immediately fell
through without doing anything. UnsubscribeFromKeyboardNotifications()
was never reached, leaving the observer tokens live in the notification
center indefinitely. The result, confirmed by the sandbox repro, was
platform=12/12 alive after 12 forced GC cycles for views using
SafeAreaEdges.SoftInput, versus platform=0/12 for the control case.

### Description of Change:

The fix flattens the conditional in UpdateKeyboardSubscription() so that
the else branch — which calls UnsubscribeFromKeyboardNotifications() —
fires for all cases where the view should not be actively subscribed,
including detach. The original nested structure if (Window != null) { if
(ShouldSubscribe) subscribe; else unsubscribe; } is replaced with if
(Window != null && ShouldSubscribeToKeyboardNotifications()) {
SubscribeToKeyboardNotifications(); } else {
UnsubscribeFromKeyboardNotifications(); }. Now when MovedToWindow()
fires with Window == null, the condition evaluates to false and
UnsubscribeFromKeyboardNotifications() is called, issuing
NSNotificationCenter.DefaultCenter.RemoveObserver(token) for both
keyboard observers. This severs the retain chain and allows the MauiView
to be collected normally by the GC. The change is 9 lines, touches a
single method, and introduces no new state or lifecycle hooks.

**Tested the behavior in the following platforms:**

- [x] Android
- [ ] Windows
- [x] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #35386         

### Screenshots
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/cbbd452a-6565-4e0b-a17d-12c83204bfe5"
Width="400" Height="600"/> | <img
src="https://github.com/user-attachments/assets/3ebbeba2-9fd1-42ac-a4d5-06d5184f2cc7"
Width="400" Height="600"/> |

---------
kubaflo pushed a commit that referenced this pull request Jul 15, 2026
…s SoftInput (#35586)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details:

Every MauiView that uses SafeAreaEdges.SoftInput stays alive in memory
after being removed from the screen. Users saw platform=12/12 views
never getting released in iOS and Mac platform.
       
### Root Cause:

When a MAUI view is configured with SafeAreaEdges.SoftInput on iOS or
MacCatalyst, MauiView.SubscribeToKeyboardNotifications() registers two
observers with NSNotificationCenter.DefaultCenter — one for
UIKeyboard.WillShowNotification and one for
UIKeyboard.WillHideNotification. Each call to AddObserver returns an
NSObject token that the notification center holds strongly. Because the
callbacks (OnKeyboardWillShow, OnKeyboardWillHide) are instance methods,
the delegate objects capture a strong reference to this — the MauiView
instance. This creates an unbroken retain chain: NSNotificationCenter →
NSObject token → delegate → MauiView. As long as those observer tokens
are registered, the notification center transitively keeps every
subscribed MauiView alive, regardless of whether the view has been
removed from the visual tree, its handler disconnected, and all
MAUI-side references dropped.
 
The reason the tokens were never removed on detach comes down to a
single guard condition in UpdateKeyboardSubscription(). The method was
structured as if (Window != null) { ... }, meaning all subscription
management — both subscribe and unsubscribe — was gated on the view
being attached to a window. When MovedToWindow() fires with Window ==
null (the standard UIKit signal that a view has been removed from the
hierarchy), UpdateKeyboardSubscription() was called but immediately fell
through without doing anything. UnsubscribeFromKeyboardNotifications()
was never reached, leaving the observer tokens live in the notification
center indefinitely. The result, confirmed by the sandbox repro, was
platform=12/12 alive after 12 forced GC cycles for views using
SafeAreaEdges.SoftInput, versus platform=0/12 for the control case.

### Description of Change:

The fix flattens the conditional in UpdateKeyboardSubscription() so that
the else branch — which calls UnsubscribeFromKeyboardNotifications() —
fires for all cases where the view should not be actively subscribed,
including detach. The original nested structure if (Window != null) { if
(ShouldSubscribe) subscribe; else unsubscribe; } is replaced with if
(Window != null && ShouldSubscribeToKeyboardNotifications()) {
SubscribeToKeyboardNotifications(); } else {
UnsubscribeFromKeyboardNotifications(); }. Now when MovedToWindow()
fires with Window == null, the condition evaluates to false and
UnsubscribeFromKeyboardNotifications() is called, issuing
NSNotificationCenter.DefaultCenter.RemoveObserver(token) for both
keyboard observers. This severs the retain chain and allows the MauiView
to be collected normally by the GC. The change is 9 lines, touches a
single method, and introduces no new state or lifecycle hooks.

**Tested the behavior in the following platforms:**

- [x] Android
- [ ] Windows
- [x] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #35386         

### Screenshots
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/cbbd452a-6565-4e0b-a17d-12c83204bfe5"
Width="400" Height="600"/> | <img
src="https://github.com/user-attachments/assets/3ebbeba2-9fd1-42ac-a4d5-06d5184f2cc7"
Width="400" Height="600"/> |

---------
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-safearea Issues/PRs that have to do with the SafeArea functionality community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/ios s/agent-fix-win AI found a better alternative fix than the PR s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

6 participants