Skip to content

[Android] Fix WebView.CanGoBack() returning true on first navigated page due to synthetic about:blank history entry - #35841

Merged
kubaflo merged 4 commits into
dotnet:inflight/currentfrom
praveenkumarkarunanithi:fix-35788
Jun 19, 2026
Merged

[Android] Fix WebView.CanGoBack() returning true on first navigated page due to synthetic about:blank history entry#35841
kubaflo merged 4 commits into
dotnet:inflight/currentfrom
praveenkumarkarunanithi:fix-35788

Conversation

@praveenkumarkarunanithi

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!

Root Cause

PR #32145 introduced LoadUrl("about:blank") inside WebViewExtensions.UpdateSource() to fix the layout overflow issue when WebView.Source is null (#32030).

Although the Navigated event was suppressed for this synthetic load via IsBlankNavigation(), Android's native WebView unconditionally records every LoadUrl() call into its internal history stack. This caused the history on the first real page load to become:

[0] about:blank
[1] real-url

As a result, CanGoBack() incorrectly returned true on the first real page load. Pressing back navigated to the synthetic blank page instead of a real previous page, leaving the user on an empty screen.

Description of Change

The fix introduces an Android-only IsLoadingForLayout flag on MauiWebView to track synthetic about:blank loads and safely clear them from history after the first real navigation completes.

MauiWebView.cs

Added internal bool IsLoadingForLayout property as a shared state bridge between WebViewExtensions and MauiWebViewClient.

WebViewExtensions.cs

Sets IsLoadingForLayout = true before triggering LoadUrl("about:blank") in the null-source layout path, marking the load as synthetic.

MauiWebViewClient.cs

In OnPageFinished, when a real URL completes while IsLoadingForLayout is true, calls ClearHistory() to remove the synthetic about:blank entry while preserving the current page.

The flag is then reset and UpdateCanGoBackForward() is invoked before Navigated fires, ensuring CanGoBack = false is already correct inside user handlers.

If the real navigation fails, the flag is reset immediately so stale state cannot incorrectly clear history on later navigations.

WebViewHandler.Android.cs

Resets IsLoadingForLayout = false inside DisconnectHandler to prevent stale state from surviving handler disconnect and reconnect scenarios such as Shell tab switches.

Regression Introduced By

PR #32145

Issues Fixed

Fixes #35788

Tested the behaviour in the following platforms

  • Android
  • Windows
  • iOS
  • Mac

Note: This is an Android-only regression. Android's native WebView unconditionally records every LoadUrl() call into its history stack with no API to suppress individual entries. iOS uses WKWebView and Windows uses WebView2 — both manage history differently and are unaffected. The fix is scoped entirely to Android platform files.

Screenshots

Before Issue Fix After Issue Fix
BeforeFix.40.mov
AfterFix.47.mov

@github-actions

github-actions Bot commented Jun 10, 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 -- 35841

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 35841"

@praveenkumarkarunanithi praveenkumarkarunanithi added platform/android area-controls-webview WebView i/regression This issue described a confirmed regression on a currently supported version labels Jun 10, 2026
@vishnumenon2684 vishnumenon2684 added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Jun 11, 2026
@vishnumenon2684 vishnumenon2684 changed the title [WIP] [Android] Fix WebView.CanGoBack() returning true on first navigated page due to synthetic about:blank history entry [Android] Fix WebView.CanGoBack() returning true on first navigated page due to synthetic about:blank history entry Jun 11, 2026
@vishnumenon2684
vishnumenon2684 marked this pull request as ready for review June 11, 2026 11:28
@vishnumenon2684 vishnumenon2684 added the community ✨ Community Contribution label Jun 11, 2026
@vishnumenon2684

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

@kubaflo

kubaflo commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/enhanced-reviewer -p android

MauiBot

This comment was marked as outdated.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jun 11, 2026

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Contributor

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 Jun 12, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/enhanced-reviewer -p android

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jun 12, 2026
@praveenkumarkarunanithi

Copy link
Copy Markdown
Contributor Author

Could you please check the ai's suggestions?

@kubaflo I validated this approach locally before finalizing the fix. Although Android documentation states that a null historyUrl prevents a history entry, device testing showed that WebView still creates an about:blank history entry, reproducing the same CanGoBack() regression, so this approach was not adopted.

@kubaflo

kubaflo commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/enhanced-reviewer -p android

@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/Android/WebViewExtensions.cs
Comment thread src/Core/src/Platform/Android/MauiWebViewClient.cs
@MauiBot MauiBot added the s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates label Jun 12, 2026
@kubaflo
kubaflo changed the base branch from main to inflight/current June 18, 2026 13:18

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could you please resolve conflicts?

@praveenkumarkarunanithi

Copy link
Copy Markdown
Contributor Author

Could you please resolve conflicts?

The branch conflict has been resolved.

@vishnumenon2684

Copy link
Copy Markdown
Contributor

/azp run maui-pr-uitests , maui-pr-devicetests

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 2 pipeline(s).

@kubaflo

kubaflo commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

/review tests

@github-actions

Copy link
Copy Markdown
Contributor

Tests Failure Analysis

@praveenkumarkarunanithi — test-failure review results are available based on commit 29bf655.
To request a fresh review after new comments, commits, or CI runs, comment /review tests.

Overall Likely unrelated Failures 3 Platform Android, Windows, iOS, macOS

Test Failure Review: Likely unrelated - click to expand

Overall verdict: Likely unrelated

All three failing pipelines (maui-pr, maui-pr-devicetests, maui-pr-uitests) also failed on every one of the five most recent base-branch (inflight/current) builds; none of the failure messages reference WebView, the changed Android platform files, or the new Issue35788 test.

Failure Verdict Evidence
maui-pr: Helix Windows unit tests (Debug + Release) Likely unrelated Microsoft.Maui.Controls.Xaml.UnitTests.dll and Microsoft.Maui.UnitTests.dll failed across four Helix job IDs (retried). PR changes only Android WebView platform files; no XAML or unit-test files were modified. All five recent base-branch builds (1471451, 1470893, 1468297, 1468281, 1465172) also failed.
maui-pr: Pack Windows Likely unrelated Error: Not found SourceFolder: artifacts/packages/Release/Shipping/metadata. Infrastructure packaging error in the pack step; unrelated to WebView handler changes. Pre-existing on the base branch.
maui-pr-devicetests: Android CoreCLR, Android Mono, iOS Mono, MacCatalyst Mono, Windows Build Likely unrelated Timeline issues contain only generic shell exit codes (no WebView-specific test names). Helix aggregate data returned 404 so individual device-test failures could not be verified. All five recent base-branch builds (1471453, 1470895, 1468501, 1468283, 1465320) also failed.
maui-pr-uitests: PublicAPI.Unshipped.txt RS0025 and RS0016 errors Likely unrelated Duplicate entries for TitleBar.OnBindingContextChanged() (net-android line 24) and StructuredItemsViewController2<TItemsView>.UpdateFlowDirection() (net-maccatalyst line 16, net-ios line 16); also SwipeItemView.IsEnabledCore.get RS0016. PR does not touch TitleBar, CollectionView Items2, SwipeItemView, or any PublicAPI.Unshipped.txt files. All five recent base-branch builds (1471452, 1470894, 1468347, 1468282, 1465155) also failed.

Recommended action

No action needed from the PR author. All failures are pre-existing on inflight/current; maintainers should address the base-branch CI breakage (PublicAPI.Unshipped.txt duplicate entries, Helix unit test failures, Pack Windows step) independently of this PR.

Evidence details

PR scope: 6 changed files — Android WebView platform files only (MauiWebView.cs, MauiWebViewClient.cs, WebViewExtensions.cs, WebViewHandler.Android.cs) and two UI test files for Issue35788. No PublicAPI.Unshipped.txt files modified.

maui-pr (Build 1471951)

maui-pr-devicetests (Build 1472099)

  • Helix job IDs found in context: 05ae30a2-a911-4d51-b574-fc3a3b84536a, 6e0d2644-9041-4070-a808-115f15eaf949, 41fb66c4-d985-414c-a2bc-e18495a7270b, 424a453d-0e11-4461-b86d-7db591f92c55, 69bec92f-78f5-41f1-acbc-759d10bd5d43, 5bd7406d-7b86-42ff-a68a-a2789e120af7
  • Helix aggregate check returned 404; individual device-test failures could not be verified. Hidden failures cannot be ruled out but pre-existing base failures are the primary signal.

maui-pr-uitests (Build 1472098)

  • RS0025: src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt(24,1)TitleBar.OnBindingContextChanged() appears more than once
  • RS0025: src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt(16,1)StructuredItemsViewController2<TItemsView>.UpdateFlowDirection() appears more than once
  • RS0025: src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt(16,1) — same as above
  • RS0016: SwipeItemView.IsEnabledCore.get not in declared public API

AzDO access: Unauthenticated — test-run APIs were skipped; build metadata, timelines, and log excerpts were used as the primary data source.

@kubaflo
kubaflo merged commit d1ed6d5 into dotnet:inflight/current Jun 19, 2026
9 of 25 checks passed
@github-actions github-actions Bot added this to the .NET 10 SR9 milestone Jun 19, 2026
PureWeen pushed a commit that referenced this pull request Jun 22, 2026
…age due to synthetic about:blank history entry (#35841)

<!-- 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!
 
## Root Cause

PR #32145 introduced `LoadUrl("about:blank")` inside
`WebViewExtensions.UpdateSource()` to fix the layout overflow issue when
`WebView.Source` is `null` (#32030).

Although the `Navigated` event was suppressed for this synthetic load
via `IsBlankNavigation()`, Android's native WebView unconditionally
records every `LoadUrl()` call into its internal history stack. This
caused the history on the first real page load to become:

```text
[0] about:blank
[1] real-url
```

As a result, `CanGoBack()` incorrectly returned `true` on the first real
page load. Pressing back navigated to the synthetic blank page instead
of a real previous page, leaving the user on an empty screen.

## Description of Change

The fix introduces an Android-only `IsLoadingForLayout` flag on
`MauiWebView` to track synthetic `about:blank` loads and safely clear
them from history after the first real navigation completes.

### MauiWebView.cs

Added internal `bool IsLoadingForLayout` property as a shared state
bridge between `WebViewExtensions` and `MauiWebViewClient`.

### WebViewExtensions.cs

Sets `IsLoadingForLayout = true` before triggering
`LoadUrl("about:blank")` in the null-source layout path, marking the
load as synthetic.

### MauiWebViewClient.cs

In `OnPageFinished`, when a real URL completes while
`IsLoadingForLayout` is `true`, calls `ClearHistory()` to remove the
synthetic `about:blank` entry while preserving the current page.

The flag is then reset and `UpdateCanGoBackForward()` is invoked before
`Navigated` fires, ensuring `CanGoBack = false` is already correct
inside user handlers.

If the real navigation fails, the flag is reset immediately so stale
state cannot incorrectly clear history on later navigations.

### WebViewHandler.Android.cs

Resets `IsLoadingForLayout = false` inside `DisconnectHandler` to
prevent stale state from surviving handler disconnect and reconnect
scenarios such as Shell tab switches.

## Regression Introduced By

PR #32145

### Issues Fixed
Fixes #35788 
 
Tested the behaviour in the following platforms
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac

**Note**: This is an Android-only regression. Android's native WebView
unconditionally records every LoadUrl() call into its history stack with
no API to suppress individual entries. iOS uses WKWebView and Windows
uses WebView2 — both manage history differently and are unaffected. The
fix is scoped entirely to Android platform files.

### Screenshots
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/255b4ab4-f933-4837-85c7-ffb1dbf61d3e"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/a6f9adf7-91c8-4e9c-aade-ef6e39780b7e"
/> |
kubaflo pushed a commit that referenced this pull request Jun 25, 2026
…age due to synthetic about:blank history entry (#35841)

<!-- 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!
 
## Root Cause

PR #32145 introduced `LoadUrl("about:blank")` inside
`WebViewExtensions.UpdateSource()` to fix the layout overflow issue when
`WebView.Source` is `null` (#32030).

Although the `Navigated` event was suppressed for this synthetic load
via `IsBlankNavigation()`, Android's native WebView unconditionally
records every `LoadUrl()` call into its internal history stack. This
caused the history on the first real page load to become:

```text
[0] about:blank
[1] real-url
```

As a result, `CanGoBack()` incorrectly returned `true` on the first real
page load. Pressing back navigated to the synthetic blank page instead
of a real previous page, leaving the user on an empty screen.

## Description of Change

The fix introduces an Android-only `IsLoadingForLayout` flag on
`MauiWebView` to track synthetic `about:blank` loads and safely clear
them from history after the first real navigation completes.

### MauiWebView.cs

Added internal `bool IsLoadingForLayout` property as a shared state
bridge between `WebViewExtensions` and `MauiWebViewClient`.

### WebViewExtensions.cs

Sets `IsLoadingForLayout = true` before triggering
`LoadUrl("about:blank")` in the null-source layout path, marking the
load as synthetic.

### MauiWebViewClient.cs

In `OnPageFinished`, when a real URL completes while
`IsLoadingForLayout` is `true`, calls `ClearHistory()` to remove the
synthetic `about:blank` entry while preserving the current page.

The flag is then reset and `UpdateCanGoBackForward()` is invoked before
`Navigated` fires, ensuring `CanGoBack = false` is already correct
inside user handlers.

If the real navigation fails, the flag is reset immediately so stale
state cannot incorrectly clear history on later navigations.

### WebViewHandler.Android.cs

Resets `IsLoadingForLayout = false` inside `DisconnectHandler` to
prevent stale state from surviving handler disconnect and reconnect
scenarios such as Shell tab switches.

## Regression Introduced By

PR #32145

### Issues Fixed
Fixes #35788 
 
Tested the behaviour in the following platforms
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac

**Note**: This is an Android-only regression. Android's native WebView
unconditionally records every LoadUrl() call into its history stack with
no API to suppress individual entries. iOS uses WKWebView and Windows
uses WebView2 — both manage history differently and are unaffected. The
fix is scoped entirely to Android platform files.

### Screenshots
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/255b4ab4-f933-4837-85c7-ffb1dbf61d3e"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/a6f9adf7-91c8-4e9c-aade-ef6e39780b7e"
/> |
kubaflo pushed a commit that referenced this pull request Jul 3, 2026
…age due to synthetic about:blank history entry (#35841)

<!-- 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!
 
## Root Cause

PR #32145 introduced `LoadUrl("about:blank")` inside
`WebViewExtensions.UpdateSource()` to fix the layout overflow issue when
`WebView.Source` is `null` (#32030).

Although the `Navigated` event was suppressed for this synthetic load
via `IsBlankNavigation()`, Android's native WebView unconditionally
records every `LoadUrl()` call into its internal history stack. This
caused the history on the first real page load to become:

```text
[0] about:blank
[1] real-url
```

As a result, `CanGoBack()` incorrectly returned `true` on the first real
page load. Pressing back navigated to the synthetic blank page instead
of a real previous page, leaving the user on an empty screen.

## Description of Change

The fix introduces an Android-only `IsLoadingForLayout` flag on
`MauiWebView` to track synthetic `about:blank` loads and safely clear
them from history after the first real navigation completes.

### MauiWebView.cs

Added internal `bool IsLoadingForLayout` property as a shared state
bridge between `WebViewExtensions` and `MauiWebViewClient`.

### WebViewExtensions.cs

Sets `IsLoadingForLayout = true` before triggering
`LoadUrl("about:blank")` in the null-source layout path, marking the
load as synthetic.

### MauiWebViewClient.cs

In `OnPageFinished`, when a real URL completes while
`IsLoadingForLayout` is `true`, calls `ClearHistory()` to remove the
synthetic `about:blank` entry while preserving the current page.

The flag is then reset and `UpdateCanGoBackForward()` is invoked before
`Navigated` fires, ensuring `CanGoBack = false` is already correct
inside user handlers.

If the real navigation fails, the flag is reset immediately so stale
state cannot incorrectly clear history on later navigations.

### WebViewHandler.Android.cs

Resets `IsLoadingForLayout = false` inside `DisconnectHandler` to
prevent stale state from surviving handler disconnect and reconnect
scenarios such as Shell tab switches.

## Regression Introduced By

PR #32145

### Issues Fixed
Fixes #35788 
 
Tested the behaviour in the following platforms
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac

**Note**: This is an Android-only regression. Android's native WebView
unconditionally records every LoadUrl() call into its history stack with
no API to suppress individual entries. iOS uses WKWebView and Windows
uses WebView2 — both manage history differently and are unaffected. The
fix is scoped entirely to Android platform files.

### Screenshots
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/255b4ab4-f933-4837-85c7-ffb1dbf61d3e"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/a6f9adf7-91c8-4e9c-aade-ef6e39780b7e"
/> |
@kubaflo kubaflo mentioned this pull request Jul 6, 2026
kubaflo pushed a commit that referenced this pull request Jul 6, 2026
…age due to synthetic about:blank history entry (#35841)

<!-- 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!
 
## Root Cause

PR #32145 introduced `LoadUrl("about:blank")` inside
`WebViewExtensions.UpdateSource()` to fix the layout overflow issue when
`WebView.Source` is `null` (#32030).

Although the `Navigated` event was suppressed for this synthetic load
via `IsBlankNavigation()`, Android's native WebView unconditionally
records every `LoadUrl()` call into its internal history stack. This
caused the history on the first real page load to become:

```text
[0] about:blank
[1] real-url
```

As a result, `CanGoBack()` incorrectly returned `true` on the first real
page load. Pressing back navigated to the synthetic blank page instead
of a real previous page, leaving the user on an empty screen.

## Description of Change

The fix introduces an Android-only `IsLoadingForLayout` flag on
`MauiWebView` to track synthetic `about:blank` loads and safely clear
them from history after the first real navigation completes.

### MauiWebView.cs

Added internal `bool IsLoadingForLayout` property as a shared state
bridge between `WebViewExtensions` and `MauiWebViewClient`.

### WebViewExtensions.cs

Sets `IsLoadingForLayout = true` before triggering
`LoadUrl("about:blank")` in the null-source layout path, marking the
load as synthetic.

### MauiWebViewClient.cs

In `OnPageFinished`, when a real URL completes while
`IsLoadingForLayout` is `true`, calls `ClearHistory()` to remove the
synthetic `about:blank` entry while preserving the current page.

The flag is then reset and `UpdateCanGoBackForward()` is invoked before
`Navigated` fires, ensuring `CanGoBack = false` is already correct
inside user handlers.

If the real navigation fails, the flag is reset immediately so stale
state cannot incorrectly clear history on later navigations.

### WebViewHandler.Android.cs

Resets `IsLoadingForLayout = false` inside `DisconnectHandler` to
prevent stale state from surviving handler disconnect and reconnect
scenarios such as Shell tab switches.

## Regression Introduced By

PR #32145

### Issues Fixed
Fixes #35788 
 
Tested the behaviour in the following platforms
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac

**Note**: This is an Android-only regression. Android's native WebView
unconditionally records every LoadUrl() call into its history stack with
no API to suppress individual entries. iOS uses WKWebView and Windows
uses WebView2 — both manage history differently and are unaffected. The
fix is scoped entirely to Android platform files.

### Screenshots
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/255b4ab4-f933-4837-85c7-ffb1dbf61d3e"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/a6f9adf7-91c8-4e9c-aade-ef6e39780b7e"
/> |
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
…age due to synthetic about:blank history entry (#35841)

<!-- 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!
 
## Root Cause

PR #32145 introduced `LoadUrl("about:blank")` inside
`WebViewExtensions.UpdateSource()` to fix the layout overflow issue when
`WebView.Source` is `null` (#32030).

Although the `Navigated` event was suppressed for this synthetic load
via `IsBlankNavigation()`, Android's native WebView unconditionally
records every `LoadUrl()` call into its internal history stack. This
caused the history on the first real page load to become:

```text
[0] about:blank
[1] real-url
```

As a result, `CanGoBack()` incorrectly returned `true` on the first real
page load. Pressing back navigated to the synthetic blank page instead
of a real previous page, leaving the user on an empty screen.

## Description of Change

The fix introduces an Android-only `IsLoadingForLayout` flag on
`MauiWebView` to track synthetic `about:blank` loads and safely clear
them from history after the first real navigation completes.

### MauiWebView.cs

Added internal `bool IsLoadingForLayout` property as a shared state
bridge between `WebViewExtensions` and `MauiWebViewClient`.

### WebViewExtensions.cs

Sets `IsLoadingForLayout = true` before triggering
`LoadUrl("about:blank")` in the null-source layout path, marking the
load as synthetic.

### MauiWebViewClient.cs

In `OnPageFinished`, when a real URL completes while
`IsLoadingForLayout` is `true`, calls `ClearHistory()` to remove the
synthetic `about:blank` entry while preserving the current page.

The flag is then reset and `UpdateCanGoBackForward()` is invoked before
`Navigated` fires, ensuring `CanGoBack = false` is already correct
inside user handlers.

If the real navigation fails, the flag is reset immediately so stale
state cannot incorrectly clear history on later navigations.

### WebViewHandler.Android.cs

Resets `IsLoadingForLayout = false` inside `DisconnectHandler` to
prevent stale state from surviving handler disconnect and reconnect
scenarios such as Shell tab switches.

## Regression Introduced By

PR #32145

### Issues Fixed
Fixes #35788 
 
Tested the behaviour in the following platforms
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac

**Note**: This is an Android-only regression. Android's native WebView
unconditionally records every LoadUrl() call into its history stack with
no API to suppress individual entries. iOS uses WKWebView and Windows
uses WebView2 — both manage history differently and are unaffected. The
fix is scoped entirely to Android platform files.

### Screenshots
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/255b4ab4-f933-4837-85c7-ffb1dbf61d3e"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/a6f9adf7-91c8-4e9c-aade-ef6e39780b7e"
/> |
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
…age due to synthetic about:blank history entry (#35841)

<!-- 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!
 
## Root Cause

PR #32145 introduced `LoadUrl("about:blank")` inside
`WebViewExtensions.UpdateSource()` to fix the layout overflow issue when
`WebView.Source` is `null` (#32030).

Although the `Navigated` event was suppressed for this synthetic load
via `IsBlankNavigation()`, Android's native WebView unconditionally
records every `LoadUrl()` call into its internal history stack. This
caused the history on the first real page load to become:

```text
[0] about:blank
[1] real-url
```

As a result, `CanGoBack()` incorrectly returned `true` on the first real
page load. Pressing back navigated to the synthetic blank page instead
of a real previous page, leaving the user on an empty screen.

## Description of Change

The fix introduces an Android-only `IsLoadingForLayout` flag on
`MauiWebView` to track synthetic `about:blank` loads and safely clear
them from history after the first real navigation completes.

### MauiWebView.cs

Added internal `bool IsLoadingForLayout` property as a shared state
bridge between `WebViewExtensions` and `MauiWebViewClient`.

### WebViewExtensions.cs

Sets `IsLoadingForLayout = true` before triggering
`LoadUrl("about:blank")` in the null-source layout path, marking the
load as synthetic.

### MauiWebViewClient.cs

In `OnPageFinished`, when a real URL completes while
`IsLoadingForLayout` is `true`, calls `ClearHistory()` to remove the
synthetic `about:blank` entry while preserving the current page.

The flag is then reset and `UpdateCanGoBackForward()` is invoked before
`Navigated` fires, ensuring `CanGoBack = false` is already correct
inside user handlers.

If the real navigation fails, the flag is reset immediately so stale
state cannot incorrectly clear history on later navigations.

### WebViewHandler.Android.cs

Resets `IsLoadingForLayout = false` inside `DisconnectHandler` to
prevent stale state from surviving handler disconnect and reconnect
scenarios such as Shell tab switches.

## Regression Introduced By

PR #32145

### Issues Fixed
Fixes #35788 
 
Tested the behaviour in the following platforms
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac

**Note**: This is an Android-only regression. Android's native WebView
unconditionally records every LoadUrl() call into its history stack with
no API to suppress individual entries. iOS uses WKWebView and Windows
uses WebView2 — both manage history differently and are unaffected. The
fix is scoped entirely to Android platform files.

### Screenshots
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/255b4ab4-f933-4837-85c7-ffb1dbf61d3e"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/a6f9adf7-91c8-4e9c-aade-ef6e39780b7e"
/> |
kubaflo pushed a commit that referenced this pull request Jul 10, 2026
…age due to synthetic about:blank history entry (#35841)

<!-- 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!
 
## Root Cause

PR #32145 introduced `LoadUrl("about:blank")` inside
`WebViewExtensions.UpdateSource()` to fix the layout overflow issue when
`WebView.Source` is `null` (#32030).

Although the `Navigated` event was suppressed for this synthetic load
via `IsBlankNavigation()`, Android's native WebView unconditionally
records every `LoadUrl()` call into its internal history stack. This
caused the history on the first real page load to become:

```text
[0] about:blank
[1] real-url
```

As a result, `CanGoBack()` incorrectly returned `true` on the first real
page load. Pressing back navigated to the synthetic blank page instead
of a real previous page, leaving the user on an empty screen.

## Description of Change

The fix introduces an Android-only `IsLoadingForLayout` flag on
`MauiWebView` to track synthetic `about:blank` loads and safely clear
them from history after the first real navigation completes.

### MauiWebView.cs

Added internal `bool IsLoadingForLayout` property as a shared state
bridge between `WebViewExtensions` and `MauiWebViewClient`.

### WebViewExtensions.cs

Sets `IsLoadingForLayout = true` before triggering
`LoadUrl("about:blank")` in the null-source layout path, marking the
load as synthetic.

### MauiWebViewClient.cs

In `OnPageFinished`, when a real URL completes while
`IsLoadingForLayout` is `true`, calls `ClearHistory()` to remove the
synthetic `about:blank` entry while preserving the current page.

The flag is then reset and `UpdateCanGoBackForward()` is invoked before
`Navigated` fires, ensuring `CanGoBack = false` is already correct
inside user handlers.

If the real navigation fails, the flag is reset immediately so stale
state cannot incorrectly clear history on later navigations.

### WebViewHandler.Android.cs

Resets `IsLoadingForLayout = false` inside `DisconnectHandler` to
prevent stale state from surviving handler disconnect and reconnect
scenarios such as Shell tab switches.

## Regression Introduced By

PR #32145

### Issues Fixed
Fixes #35788 
 
Tested the behaviour in the following platforms
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac

**Note**: This is an Android-only regression. Android's native WebView
unconditionally records every LoadUrl() call into its history stack with
no API to suppress individual entries. iOS uses WKWebView and Windows
uses WebView2 — both manage history differently and are unaffected. The
fix is scoped entirely to Android platform files.

### Screenshots
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/255b4ab4-f933-4837-85c7-ffb1dbf61d3e"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/a6f9adf7-91c8-4e9c-aade-ef6e39780b7e"
/> |
kubaflo pushed a commit that referenced this pull request Jul 15, 2026
…age due to synthetic about:blank history entry (#35841)

<!-- 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!
 
## Root Cause

PR #32145 introduced `LoadUrl("about:blank")` inside
`WebViewExtensions.UpdateSource()` to fix the layout overflow issue when
`WebView.Source` is `null` (#32030).

Although the `Navigated` event was suppressed for this synthetic load
via `IsBlankNavigation()`, Android's native WebView unconditionally
records every `LoadUrl()` call into its internal history stack. This
caused the history on the first real page load to become:

```text
[0] about:blank
[1] real-url
```

As a result, `CanGoBack()` incorrectly returned `true` on the first real
page load. Pressing back navigated to the synthetic blank page instead
of a real previous page, leaving the user on an empty screen.

## Description of Change

The fix introduces an Android-only `IsLoadingForLayout` flag on
`MauiWebView` to track synthetic `about:blank` loads and safely clear
them from history after the first real navigation completes.

### MauiWebView.cs

Added internal `bool IsLoadingForLayout` property as a shared state
bridge between `WebViewExtensions` and `MauiWebViewClient`.

### WebViewExtensions.cs

Sets `IsLoadingForLayout = true` before triggering
`LoadUrl("about:blank")` in the null-source layout path, marking the
load as synthetic.

### MauiWebViewClient.cs

In `OnPageFinished`, when a real URL completes while
`IsLoadingForLayout` is `true`, calls `ClearHistory()` to remove the
synthetic `about:blank` entry while preserving the current page.

The flag is then reset and `UpdateCanGoBackForward()` is invoked before
`Navigated` fires, ensuring `CanGoBack = false` is already correct
inside user handlers.

If the real navigation fails, the flag is reset immediately so stale
state cannot incorrectly clear history on later navigations.

### WebViewHandler.Android.cs

Resets `IsLoadingForLayout = false` inside `DisconnectHandler` to
prevent stale state from surviving handler disconnect and reconnect
scenarios such as Shell tab switches.

## Regression Introduced By

PR #32145

### Issues Fixed
Fixes #35788 
 
Tested the behaviour in the following platforms
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac

**Note**: This is an Android-only regression. Android's native WebView
unconditionally records every LoadUrl() call into its history stack with
no API to suppress individual entries. iOS uses WKWebView and Windows
uses WebView2 — both manage history differently and are unaffected. The
fix is scoped entirely to Android platform files.

### Screenshots
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/255b4ab4-f933-4837-85c7-ffb1dbf61d3e"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/a6f9adf7-91c8-4e9c-aade-ef6e39780b7e"
/> |
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 20, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-controls-webview WebView community ✨ Community Contribution i/regression This issue described a confirmed regression on a currently supported version partner/syncfusion Issues / PR's with Syncfusion collaboration platform/android s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WebView on Android Sometimes Inserts 'about:blank' Page

4 participants