Skip to content

Commit dafe489

Browse files
[Android] Fix for WebView Fails to Load URLs with Certain Encoded Characters (#27003)
* Fix code and test case commit * test case code updated * removed ui tests as it used user name included url * updated unit test case * updated fix and unit test case * updated the new class access specifier. * Removed unit test descriptions * Fix updated * updated the unit test case * Reverted unit test and added UI test case * updated test case description * updating ui test case with ignore windows comment * updated windows issue url * updating test case with comments. * updated the test case as device test * removed ui test * Fix build error * updated device test with conditional skip code * updating test case with internet connectivity checks. --------- Co-authored-by: Gerald Versluis <gerald@verslu.is>
1 parent b0e6b60 commit dafe489

File tree

3 files changed

+71
-1
lines changed

3 files changed

+71
-1
lines changed

src/Core/src/Platform/Android/MauiWebView.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ void IWebViewDelegate.LoadUrl(string? url)
3232
_handler.CurrentNavigationEvent = WebNavigationEvent.NewPage;
3333
}
3434

35-
if (url != null && !url.StartsWith('/') && !Uri.IsWellFormedUriString(url, UriKind.Absolute))
35+
if (url is not null && !url.StartsWith('/') && !Uri.TryCreate(url, UriKind.Absolute, out _))
3636
{
3737
// URLs like "index.html" can't possibly load, so try "file:///android_asset/index.html"
3838
url = AssetBaseUrl + url;

src/Core/tests/DeviceTests/Handlers/WebView/WebViewHandlerTests.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,5 +113,40 @@ await img.AssertContainsColor(expectedColorInPlayingVideo, imageRect =>
113113
});
114114
});
115115
}
116+
117+
[Theory(DisplayName = "WebView loads non-Western character encoded URLs correctly"
118+
#if WINDOWS
119+
, Skip = "Skipping this test on Windows due to WebView's OnNavigated event returning WebNavigationResult.Failure for URLs with non-Western characters. More information: https://github.com/dotnet/maui/issues/27425"
120+
#endif
121+
)]
122+
[InlineData("https://example.com/test-Ağ-Sistem%20Bilgi%20Güvenliği%20Md/Guide.pdf")] // Non-ASCII character + space (%20) (Outside IRI range)
123+
[InlineData("https://google.com/[]")] // Reserved set (`;/?:@&=+$,#[]!'()*%`)
124+
[InlineData("https://example.com/test/%3Cvalue%3E")] // Escaped character from " <>`^{|} set (e.g., < >)
125+
[InlineData("https://example.com/path/%09text")] // Escaped character from [0, 1F] range (e.g., tab %09)
126+
[InlineData("https://example.com/test?query=%26value")] // Another escaped character from reserved set (e.g., & as %26)
127+
public async Task WebViewShouldLoadEncodedUrl(string encodedUrl)
128+
{
129+
if (await AssertionExtensions.SkipTestIfNoInternetConnection())
130+
{
131+
return;
132+
}
133+
var webView = new WebView();
134+
var tcs = new TaskCompletionSource<WebNavigationResult>();
135+
136+
webView.Navigated += (sender, args) =>
137+
{
138+
tcs.TrySetResult(args.Result);
139+
};
140+
141+
await InvokeOnMainThreadAsync(() =>
142+
{
143+
var handler = CreateHandler<WebViewHandler>(webView);
144+
(handler.PlatformView as IWebViewDelegate)?.LoadUrl(encodedUrl);
145+
});
146+
147+
var navigationResult = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5));
148+
149+
Assert.Equal(WebNavigationResult.Success, navigationResult);
150+
}
116151
}
117152
}

src/TestUtils/src/DeviceTests/AssertionExtensions.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Text;
44
using System.Threading;
55
using System.Threading.Tasks;
6+
using System.Net.Http;
67
using Microsoft.Extensions.DependencyInjection;
78
using Microsoft.Maui.Dispatching;
89
using Microsoft.Maui.Platform;
@@ -266,5 +267,39 @@ public static async Task AssertEventually(this Func<bool> assertion, int timeout
266267
throw new XunitException(message);
267268
}
268269
}
270+
// Add these methods to AssertionExtensions class
271+
/// <summary>
272+
/// Checks if internet connection is available by making an HTTP request
273+
/// </summary>
274+
/// <returns>True if internet connection is available</returns>
275+
public static async Task<bool> HasInternetConnection()
276+
{
277+
try
278+
{
279+
using var httpClient = new HttpClient();
280+
httpClient.Timeout = TimeSpan.FromSeconds(5);
281+
using var response = await httpClient.GetAsync("https://1.1.1.1");
282+
return response.IsSuccessStatusCode;
283+
}
284+
catch
285+
{
286+
return false;
287+
}
288+
}
289+
290+
/// <summary>
291+
/// Skips the current test if no internet connection is available
292+
/// </summary>
293+
/// <param name="message">Custom message to display when skipping the test</param>
294+
/// <returns>True if test should be skipped (no internet), false if test can continue</returns>
295+
public static async Task<bool> SkipTestIfNoInternetConnection(string message = "Test requires internet connection")
296+
{
297+
if (!await HasInternetConnection())
298+
{
299+
Assert.True(true, $"TEST SKIPPED: {message}");
300+
return true; // Test should be skipped
301+
}
302+
return false; // Test can proceed
303+
}
269304
}
270305
}

0 commit comments

Comments
 (0)