Skip to content

Commit

Permalink
[Windows] Fix crash on Windows WebView updating the Html Source more …
Browse files Browse the repository at this point in the history
…than once (#13222)

* Fix crash on Windows WebView updating the Html Source more than once

* Fixed build error

* Update src/Core/src/Platform/Windows/WebViewExtensions.cs

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

---------

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>
  • Loading branch information
jsuarezruiz and mandel-macaque authored Feb 14, 2023
1 parent 8e32da6 commit 236a60a
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
Text="HtmlWebViewSource (String)"
Style="{StaticResource Headline}"/>
<WebView
x:Name="HtmlSourceWebView"
HeightRequest="150"
HorizontalOptions="FillAndExpand">
<WebView.Source>
Expand All @@ -31,6 +32,9 @@
</HtmlWebViewSource>
</WebView.Source>
</WebView>
<Button
Text="Update Source"
Clicked="OnUpdateHtmlSourceClicked"/>
<Label
Text="HtmlWebViewSource (File)"
Style="{StaticResource Headline}"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ protected override void OnDisappearing()
MauiWebView.Navigated -= OnMauiWebViewNavigated;
}

void OnUpdateHtmlSourceClicked(object sender, EventArgs args)
{
Random rnd = new();
HtmlWebViewSource htmlWebViewSource = new();
HtmlSourceWebView.Source = htmlWebViewSource;
htmlWebViewSource.Html += $"<h1>Updated Content {rnd.Next()}!</h1><br>";
}

void OnGoBackClicked(object sender, EventArgs args)
{
Debug.WriteLine($"CanGoBack {MauiWebView.CanGoBack}");
Expand Down
9 changes: 7 additions & 2 deletions src/Core/src/Platform/Windows/MauiWebView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,16 @@ public async void LoadHtml(string? html, string? baseUrl)
NavigateToString(!string.IsNullOrEmpty(htmlWithBaseTag) ? htmlWithBaseTag : html);
// Free up memory after we're done with _internalWebView
_internalWebView = null;
if (_internalWebView.IsValid())
{
_internalWebView.Close();
_internalWebView = null;
}
};

// Kick off the initial navigation
_internalWebView.NavigateToString(html);
if (_internalWebView.IsValid())
_internalWebView.NavigateToString(html);
}

public async void LoadUrl(string? url)
Expand Down
13 changes: 12 additions & 1 deletion src/Core/src/Platform/Windows/WebViewExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Threading.Tasks;
using Microsoft.UI.Xaml.Controls;

namespace Microsoft.Maui.Platform
Expand Down Expand Up @@ -80,5 +79,17 @@ public static void EvaluateJavaScript(this WebView2 webView, EvaluateJavaScriptA
{
request.RunAndReport(webView.ExecuteScriptAsync(request.Script));
}

internal static bool IsValid(this WebView2 webView)
{
try
{
return webView is not null && webView.CoreWebView2 is not null;
}
catch (Exception ex) when (ex is ObjectDisposedException || ex is InvalidOperationException)
{
return false;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Threading.Tasks;
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Maui.Controls;
using Microsoft.Maui.DeviceTests.Stubs;
Expand All @@ -9,6 +11,52 @@ namespace Microsoft.Maui.DeviceTests
{
public partial class WebViewHandlerTests
{
[Theory(DisplayName = "UrlSource Updates Correctly")]
[InlineData("<h1>Old Source</h1><br>", "<p>New Source</p>\"")]
[InlineData("<p>Old Source</p><br>", "<h1>New Source</h1>\"")]
public async Task HtmlSourceUpdatesCorrectly(string oldSource, string newSource)
{
var pageLoadTimeout = TimeSpan.FromSeconds(2);

await InvokeOnMainThreadAsync(async () =>
{
var webView = new WebViewStub()
{
Width = 100,
Height = 100,
Source = new HtmlWebViewSourceStub { Html = oldSource }
};
var handler = CreateHandler(webView);
var platformView = handler.PlatformView;
// Setup the view to be displayed/parented and run our tests on it
await platformView.AttachAndRun(async () =>
{
// Wait for the page to load
var tcsLoaded = new TaskCompletionSource<bool>();
var ctsTimeout = new CancellationTokenSource(pageLoadTimeout);
ctsTimeout.Token.Register(() => tcsLoaded.TrySetException(new TimeoutException($"Failed to load HTML")));
webView.NavigatedDelegate = (evnt, url, result) =>
{
// Set success when we have a successful nav result
if (result == WebNavigationResult.Success)
tcsLoaded.TrySetResult(result == WebNavigationResult.Success);
};
// Load the new Source
webView.Source = new HtmlWebViewSourceStub { Html = newSource };
handler.UpdateValue(nameof(IWebView.Source));
// If the new source is loaded without exceptions, the test has passed
Assert.True(await tcsLoaded.Task);
});
});
}

[Fact(DisplayName = "Closing Window With WebView Doesnt Crash")]
public async Task ClosingWindowWithWebViewDoesntCrash()
{
Expand Down
12 changes: 12 additions & 0 deletions src/Core/tests/DeviceTests/Stubs/HtmlWebViewSourceStub.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Microsoft.Maui.DeviceTests.Stubs
{
class HtmlWebViewSourceStub : IWebViewSource
{
public string Html { get; set; }

public void Load(IWebViewDelegate webViewDelegate)
{
webViewDelegate.LoadHtml(Html, null);
}
}
}

0 comments on commit 236a60a

Please sign in to comment.