diff --git a/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21631.xaml b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21631.xaml
new file mode 100644
index 000000000000..c35fc16d51e3
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21631.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21631.xaml.cs b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21631.xaml.cs
new file mode 100644
index 000000000000..b371cb4437ba
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue21631.xaml.cs
@@ -0,0 +1,15 @@
+using Microsoft.Maui.Controls;
+using Microsoft.Maui.Controls.Xaml;
+
+namespace Maui.Controls.Sample.Issues
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ [Issue(IssueTracker.Github, 21631, "Injecting base tag in Webview2 works", PlatformAffected.UWP)]
+ public partial class Issue21631 : ContentPage
+ {
+ public Issue21631()
+ {
+ InitializeComponent();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/tests/UITests/Tests/Issues/Issue21631.cs b/src/Controls/tests/UITests/Tests/Issues/Issue21631.cs
new file mode 100644
index 000000000000..c14ad533a888
--- /dev/null
+++ b/src/Controls/tests/UITests/Tests/Issues/Issue21631.cs
@@ -0,0 +1,24 @@
+using NUnit.Framework;
+using UITest.Appium;
+using UITest.Core;
+
+namespace Microsoft.Maui.AppiumTests.Issues
+{
+ public class Issue21631 : _IssuesUITest
+ {
+ public Issue21631(TestDevice device) : base(device) { }
+
+ public override string Issue =>
+ "Injecting base tag in Webview2 works";
+
+ [Test]
+ public async Task NavigateToStringWithWebviewWorks()
+ {
+ this.IgnoreIfPlatforms(new TestDevice[] { TestDevice.Android, TestDevice.Mac, TestDevice.iOS });
+
+ App.WaitForElement("WaitForWebView");
+ await Task.Delay(500);
+ VerifyScreenshot();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/tests/UITests/snapshots/windows/NavigateToStringWithWebviewWorks.png b/src/Controls/tests/UITests/snapshots/windows/NavigateToStringWithWebviewWorks.png
new file mode 100644
index 000000000000..aecb430ed3c8
Binary files /dev/null and b/src/Controls/tests/UITests/snapshots/windows/NavigateToStringWithWebviewWorks.png differ
diff --git a/src/Core/src/Platform/Windows/MauiWebView.cs b/src/Core/src/Platform/Windows/MauiWebView.cs
index e21f7586e59e..932db7b69f4d 100644
--- a/src/Core/src/Platform/Windows/MauiWebView.cs
+++ b/src/Core/src/Platform/Windows/MauiWebView.cs
@@ -1,7 +1,6 @@
using System;
using System.Diagnostics;
using System.Text;
-using System.Text.RegularExpressions;
using Microsoft.Maui.ApplicationModel;
using Microsoft.UI.Xaml.Controls;
using Windows.ApplicationModel;
@@ -28,8 +27,6 @@ public MauiWebView(WebViewHandler handler)
SetupPlatformEvents();
}
- WebView2? _internalWebView;
-
// Arbitrary local host name for virtual folder mapping
const string LocalHostName = "appdir";
const string LocalScheme = $"https://{LocalHostName}/";
@@ -48,66 +45,29 @@ public MauiWebView(WebViewHandler handler)
: AppContext.BaseDirectory;
public async void LoadHtml(string? html, string? baseUrl)
- {
+ {
var mapBaseDirectory = false;
-
if (string.IsNullOrEmpty(baseUrl))
{
baseUrl = LocalScheme;
mapBaseDirectory = true;
}
- // Generate a base tag for the document
- var baseTag = $"";
-
- string htmlWithBaseTag;
-
- // Set up an internal WebView we can use to load and parse the original HTML string
- // Make _internalWebView a field instead of local variable to avoid garbage collection
- _internalWebView = new WebView2();
-
- // TODO: For now, the CoreWebView2 won't be created without either setting Source or
- // calling EnsureCoreWebView2Async().
- await _internalWebView.EnsureCoreWebView2Async();
+ await EnsureCoreWebView2Async();
- // When the 'navigation' to the original HTML string is done, we can modify it to include our tag
- _internalWebView.NavigationCompleted += async (sender, args) =>
- {
- // Generate a version of the script with the correct tag
- var script = BaseInsertionScript.Replace("baseTag", baseTag, StringComparison.Ordinal);
-
- // Run it and retrieve the updated HTML from our WebView
- await sender.ExecuteScriptAsync(script);
- htmlWithBaseTag = await sender.ExecuteScriptAsync("document.documentElement.outerHTML;");
+ if (mapBaseDirectory)
+ {
+ CoreWebView2.SetVirtualHostNameToFolderMapping(
+ LocalHostName,
+ ApplicationPath,
+ Web.WebView2.Core.CoreWebView2HostResourceAccessKind.Allow);
+ }
- htmlWithBaseTag = Regex.Unescape(htmlWithBaseTag);
- htmlWithBaseTag = htmlWithBaseTag.Remove(0, 1);
- htmlWithBaseTag = htmlWithBaseTag.Remove(htmlWithBaseTag.Length - 1, 1);
-
- await EnsureCoreWebView2Async();
+ // Insert script to set the base tag
+ var script = GetBaseTagInsertionScript(baseUrl);
+ var htmlWithScript = $"{script}\n{html}";
- if (mapBaseDirectory)
- {
- CoreWebView2.SetVirtualHostNameToFolderMapping(
- LocalHostName,
- ApplicationPath,
- Web.WebView2.Core.CoreWebView2HostResourceAccessKind.Allow);
- }
-
- // Set the HTML for the 'real' WebView to the updated HTML
- NavigateToString(!string.IsNullOrEmpty(htmlWithBaseTag) ? htmlWithBaseTag : html);
-
- // Free up memory after we're done with _internalWebView
- if (_internalWebView.IsValid())
- {
- _internalWebView.Close();
- _internalWebView = null;
- }
- };
-
- // Kick off the initial navigation
- if (_internalWebView.IsValid())
- _internalWebView.NavigateToString(html);
+ NavigateToString(htmlWithScript);
}
public async void LoadUrl(string? url)
@@ -184,9 +144,16 @@ static bool IsWebView2DataUriWithBaseUrl(string? uri)
Convert.FromBase64String(
uri.Substring(dataUriBase64.Length)));
+ var localSchemeScript = GetBaseTagInsertionScript(LocalScheme);
return decodedHtml.Contains(
- $"";
+ return $"";
+ }
}
}