From 74272dd3d803c33cf7ea8c0aa8f116710d5401f5 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Thu, 15 Feb 2024 13:22:51 +0100 Subject: [PATCH 1/5] chore: Ensure we don't crash when MainPage does not use SampleChooser --- src/SamplesApp/SamplesApp.Shared/App.xaml.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SamplesApp/SamplesApp.Shared/App.xaml.cs b/src/SamplesApp/SamplesApp.Shared/App.xaml.cs index 82cc89b9571e..56720c0a71df 100644 --- a/src/SamplesApp/SamplesApp.Shared/App.xaml.cs +++ b/src/SamplesApp/SamplesApp.Shared/App.xaml.cs @@ -160,9 +160,9 @@ override void OnLaunched(LaunchActivatedEventArgs e) HandleLaunchArguments(e); - if (SampleControl.Presentation.SampleChooserViewModel.Instance.CurrentSelectedSample is null) + if (SampleControl.Presentation.SampleChooserViewModel.Instance is { } vm && vm.CurrentSelectedSample is null) { - SampleControl.Presentation.SampleChooserViewModel.Instance.SetSelectedSample(CancellationToken.None, "Playground", "Playground"); + vm.SetSelectedSample(CancellationToken.None, "Playground", "Playground"); } Console.WriteLine("Done loading " + sw.Elapsed); From 72f03e211c374a54984307601acbec053425953e Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Thu, 15 Feb 2024 13:24:58 +0100 Subject: [PATCH 2/5] fix: Ensure NavigationStarting is executed reliably on Android --- .../Android/InternalWebClient.Android.cs | 4 +--- .../Android/NativeWebViewWrapper.Android.cs | 24 +++++++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/InternalWebClient.Android.cs b/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/InternalWebClient.Android.cs index b05311026449..fc8d8393c886 100644 --- a/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/InternalWebClient.Android.cs +++ b/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/InternalWebClient.Android.cs @@ -44,9 +44,7 @@ public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, strin return true; } - _coreWebView.RaiseNavigationStarting(url, out var cancel); - - return cancel; + return false; } public override void OnPageStarted(Android.Webkit.WebView view, string url, Bitmap favicon) diff --git a/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/NativeWebViewWrapper.Android.cs b/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/NativeWebViewWrapper.Android.cs index 8f14c1d81472..bdaf761dadb3 100644 --- a/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/NativeWebViewWrapper.Android.cs +++ b/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/NativeWebViewWrapper.Android.cs @@ -126,13 +126,13 @@ public void ProcessNavigation(Uri uri) if (uri.Scheme.Equals("local", StringComparison.OrdinalIgnoreCase)) { var path = $"file:///android_asset/{uri.PathAndQuery}"; - _webView.LoadUrl(path); + ScheduleNavigationStarting(path, () => _webView.LoadUrl(path)); return; } if (uri.Scheme.Equals(Uri.UriSchemeMailto, StringComparison.OrdinalIgnoreCase)) { - CreateAndLaunchMailtoIntent(_webView.Context, uri.AbsoluteUri); + ScheduleNavigationStarting(uri.AbsoluteUri, () => CreateAndLaunchMailtoIntent(_webView.Context, uri.AbsoluteUri)); return; } @@ -155,7 +155,8 @@ public void ProcessNavigation(Uri uri) //The replace is present because the URI cuts off any slashes that are more than two when it creates the URI. //Therefore we add the final forward slash manually in Android because the file:/// requires 3 slashes. - _webView.LoadUrl(uri.AbsoluteUri.Replace("file://", "file:///")); + var actualUri = uri.AbsoluteUri.Replace("file://", "file:///"); + ScheduleNavigationStarting(actualUri, () => _webView.LoadUrl(actualUri)); } public void ProcessNavigation(HttpRequestMessage requestMessage) @@ -169,14 +170,27 @@ public void ProcessNavigation(HttpRequestMessage requestMessage) ); _wasLoadedFromString = false; - _webView.LoadUrl(uri.AbsoluteUri, headers); + ScheduleNavigationStarting(uri.AbsoluteUri, () => _webView.LoadUrl(uri.AbsoluteUri, headers)); } public void ProcessNavigation(string html) { _wasLoadedFromString = true; //Note : _webView.LoadData does not work properly on Android 10 even when we encode to base64. - _webView.LoadDataWithBaseURL(null, html, "text/html; charset=utf-8", "utf-8", null); + ScheduleNavigationStarting(null, () => _webView.LoadDataWithBaseURL(null, html, "text/html; charset=utf-8", "utf-8", null)); + } + + private void ScheduleNavigationStarting(string url, Action loadAction) + { + _ = _coreWebView.Owner.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () => + { + _coreWebView.RaiseNavigationStarting(url, out var cancel); + + if (!cancel) + { + loadAction?.Invoke(); + } + }); } async Task INativeWebView.ExecuteScriptAsync(string script, CancellationToken token) From 0f2626731a9de70de1facf93d2fa80e04c0570cf Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Thu, 15 Feb 2024 13:28:48 +0100 Subject: [PATCH 3/5] chore: Ensure NavigationStarting occurs on non-programmatic navigations --- .../WebView/Native/Android/InternalWebClient.Android.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/InternalWebClient.Android.cs b/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/InternalWebClient.Android.cs index fc8d8393c886..b05311026449 100644 --- a/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/InternalWebClient.Android.cs +++ b/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/InternalWebClient.Android.cs @@ -44,7 +44,9 @@ public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, strin return true; } - return false; + _coreWebView.RaiseNavigationStarting(url, out var cancel); + + return cancel; } public override void OnPageStarted(Android.Webkit.WebView view, string url, Bitmap favicon) From 52260ac0fe52a723709d7d691e48fde422099b92 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Thu, 15 Feb 2024 13:29:03 +0100 Subject: [PATCH 4/5] test: Verify NavigationStarting is called --- .../Tests/Microsoft_UI_Xaml_Controls/Given_WebView2.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_WebView2.cs b/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_WebView2.cs index 7337c0029db1..219ea153a3ca 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_WebView2.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_WebView2.cs @@ -42,10 +42,13 @@ public async Task When_Navigate() await TestServices.WindowHelper.WaitForLoaded(border); var uri = new Uri("https://example.com/"); await webView.EnsureCoreWebView2Async(); + bool navigationStarting = false; bool navigationDone = false; + webView.NavigationStarting += (s, e) => navigationStarting = true; webView.NavigationCompleted += (s, e) => navigationDone = true; webView.CoreWebView2.Navigate(uri.ToString()); Assert.IsNull(webView.Source); + await TestServices.WindowHelper.WaitFor(() => navigationStarting, 1000); await TestServices.WindowHelper.WaitFor(() => navigationDone, 3000); Assert.IsNotNull(webView.Source); Assert.IsTrue(webView.Source.OriginalString.StartsWith("https://example.com/", StringComparison.OrdinalIgnoreCase)); @@ -63,10 +66,13 @@ public async Task When_NavigateToString() await TestServices.WindowHelper.WaitForLoaded(border); var uri = new Uri("https://example.com/"); await webView.EnsureCoreWebView2Async(); + bool navigationStarting = false; bool navigationDone = false; + webView.NavigationStarting += (s, e) => navigationStarting = true; webView.NavigationCompleted += (s, e) => navigationDone = true; webView.Source = uri; Assert.IsNotNull(webView.Source); + await TestServices.WindowHelper.WaitFor(() => navigationStarting, 1000); await TestServices.WindowHelper.WaitFor(() => navigationDone, 3000); Assert.IsNotNull(webView.Source); navigationDone = false; From 7f79610709e6df9b868df6ee1057530c4ccac4e4 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Thu, 15 Feb 2024 13:45:47 +0100 Subject: [PATCH 5/5] chore: Explain the new behavior --- .../WebView/Native/Android/NativeWebViewWrapper.Android.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/NativeWebViewWrapper.Android.cs b/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/NativeWebViewWrapper.Android.cs index bdaf761dadb3..2c7e9bd8314d 100644 --- a/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/NativeWebViewWrapper.Android.cs +++ b/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/NativeWebViewWrapper.Android.cs @@ -182,6 +182,9 @@ public void ProcessNavigation(string html) private void ScheduleNavigationStarting(string url, Action loadAction) { + // For programmatically-triggered navigations the ShouldOverrideUrlLoading method is not called, + // to workaround this, we raise the NavigationStarting event here, asynchronously to be in line with + // the WinUI behavior. _ = _coreWebView.Owner.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () => { _coreWebView.RaiseNavigationStarting(url, out var cancel);