From 6dc546f1bf11e978411a10c3b5014b4877c3492e Mon Sep 17 00:00:00 2001 From: Reza Talebi Date: Mon, 27 Jan 2025 03:23:53 +0330 Subject: [PATCH] Upgrade to .NET 9.0 (Revert WinUI) --- {WinUI => UWP}/WebView.UserAgent.cs | 0 UWP/WebViewRenderer.cs | 123 ++++++++++++++++++++++++++++ WebView.csproj | 21 +++-- WinUI/WebViewRenderer.cs | 112 ------------------------- 4 files changed, 135 insertions(+), 121 deletions(-) rename {WinUI => UWP}/WebView.UserAgent.cs (100%) create mode 100644 UWP/WebViewRenderer.cs delete mode 100644 WinUI/WebViewRenderer.cs diff --git a/WinUI/WebView.UserAgent.cs b/UWP/WebView.UserAgent.cs similarity index 100% rename from WinUI/WebView.UserAgent.cs rename to UWP/WebView.UserAgent.cs diff --git a/UWP/WebViewRenderer.cs b/UWP/WebViewRenderer.cs new file mode 100644 index 0000000..0d4c9a7 --- /dev/null +++ b/UWP/WebViewRenderer.cs @@ -0,0 +1,123 @@ +namespace Zebble; + +using System; +using System.Threading.Tasks; +using Windows.UI.Xaml; +using controls = Windows.UI.Xaml.Controls; +using Olive; + +partial class WebViewRenderer : INativeRenderer +{ + WebView View; + controls.WebView Result; + + public async Task Render(Renderer renderer) + { + View = (WebView)renderer.View; + + View.SourceChanged.HandleOn(Thread.UI, () => Reload()); + View.EvaluatedJavascript += x => Thread.UI.Run(() => EvaluateJavascript(x)); + View.InvokeJavascriptFunction += (s, a) => Thread.UI.Post(() => EvaluateJavascriptFunction(s, a)); + CreateBrowser(); + Reload(); + + return Result; + } + + void CreateBrowser() + { + SetDefaultUserAgent(); + + Result = new controls.WebView(controls.WebViewExecutionMode.SeparateThread); + Result.Loaded += async (s, e) => await View.LoadFinished.RaiseOn(Thread.Pool); + + Result.NavigationStarting += (s, e) => + { + if (e.Uri != null && View.OnBrowserNavigating(e.Uri.ToString())) Result.Stop(); + }; + + Result.NavigationCompleted += async (s, e) => + { + if (View.BrowserNavigated.IsHandled()) + { + var html = (await EvaluateJavascript("document.documentElement.outerHTML")).ToStringOrEmpty(); + var url = e.Uri.ToStringOrEmpty(); + + Thread.Pool.RunAction(() => View.OnBrowserNavigated(url, html)); + } + }; + + Result.LoadCompleted += Browser_LoadCompleted; + Result.NavigationFailed += Browser_NavigationFailed; + } + + async void Browser_NavigationFailed(object sender, controls.WebViewNavigationFailedEventArgs args) + { + var error = args.WebErrorStatus.ToString(); + + await View.LoadingError.RaiseOn(Thread.Pool, error); + } + + void Browser_LoadCompleted(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs args) + { + // TODO: Find if it was an error, and raise the event. + } + + Task EvaluateJavascript(string script) => Result.InvokeScriptAsync("eval", new string[] { script }).AsTask(); + + async void EvaluateJavascriptFunction(string function, string[] args) + { + try + { + await Result.InvokeScriptAsync(function, args).AsTask(); + } + catch (Exception ex) + { + if (ex.Message == "Exception from HRESULT: 0x80020101") + { + Log.For(this).Error(ex, "Syntax error in the javascript invoking function '" + function + "' with params:\n" + + args.ToLinesString()); + } + else + { + Log.For(this).Error(ex, "EvaluateJavascriptFunction() failed."); + } + } + } + + public controls.WebView Render() => Result; + + void Reload() + { + if (View.Url?.Contains(":") == true) Result.Navigate(GetUri()); + else Result.NavigateToString(View.GetExecutableHtml().OrEmpty()); + } + + public Uri GetUri() + { + var path = View.Url; + + if (path.Contains(":")) return path.AsUri(); + + var notFond = Device.IO.AbsolutePath("Images/Icons/not-found.png").AsUri(); + + path = path.OrEmpty(); + + var file = Device.IO.File(path.TrimStart("/").Replace("/", "\\")); + if (!file.Exists() && file.Extension.OrEmpty().ToLower().IsAnyOf(".gif", ".png", ".jpg", ".jpeg", ".webp")) + { + Log.For(this).Error("Image file does not exist: " + file); + return notFond; + } + + return file.FullName.AsUri(); + } + + public void Dispose() + { + Result = null; + View = null; + + GC.SuppressFinalize(this); + } +} \ No newline at end of file diff --git a/WebView.csproj b/WebView.csproj index b598d72..07345b2 100644 --- a/WebView.csproj +++ b/WebView.csproj @@ -1,12 +1,12 @@  - net8.0-android;net8.0-ios - $(TargetFrameworks);net8.0-windows10.0.19041 + net9.0-android;net9.0-ios + $(TargetFrameworks);net9.0-windows10.0.26100 Zebble.WebView Zebble Zebble.WebView $(AssemblyName) ($(TargetFramework)) - 5.1.1.0 + 5.1.2.0 true en $(DefineConstants) @@ -35,9 +35,10 @@ true true - + win-x86;win-x64;win-arm64 - $(DefineConstants);WINUI + $(DefineConstants);UWP + true $(DefineConstants);ANDROID @@ -49,8 +50,10 @@ - - + + + + @@ -65,8 +68,8 @@ - - + + diff --git a/WinUI/WebViewRenderer.cs b/WinUI/WebViewRenderer.cs deleted file mode 100644 index 3363e83..0000000 --- a/WinUI/WebViewRenderer.cs +++ /dev/null @@ -1,112 +0,0 @@ -namespace Zebble; - -using System; -using System.Threading.Tasks; -using Microsoft.UI.Xaml; -using controls = Microsoft.UI.Xaml.Controls; -using Olive; -using System.Linq; - -partial class WebViewRenderer : INativeRenderer -{ - WebView View; - controls.WebView2 Result; // Use WebView2 instead of WebView - - public async Task Render(Renderer renderer) - { - View = (WebView)renderer.View; - - View.SourceChanged.HandleOn(Thread.UI, () => Reload()); - View.EvaluatedJavascript += x => Thread.UI.Run(() => EvaluateJavascript(x)); - View.InvokeJavascriptFunction += (s, a) => Thread.UI.Post(() => EvaluateJavascriptFunction(s, a)); - - Result = new controls.WebView2(); - await Result.EnsureCoreWebView2Async(); // Ensure WebView2 is initialized - - // Handle navigation events after CoreWebView2 is initialized - Result.CoreWebView2.NavigationStarting += (s, e) => - { - if (e.Uri != null && View.OnBrowserNavigating(e.Uri.ToString())) - Result.CoreWebView2.Stop(); - }; - - Result.CoreWebView2.NavigationCompleted += async (s, e) => - { - if (View.BrowserNavigated.IsHandled()) - { - var html = (await EvaluateJavascript("document.documentElement.outerHTML")).ToStringOrEmpty(); - var url = Result.Source?.ToStringOrEmpty() ?? string.Empty; // Use Result.Source for URL - - Thread.Pool.RunAction(() => View.OnBrowserNavigated(url, html)); - } - }; - - Reload(); - - return Result; - } - - Task EvaluateJavascript(string script) - { - return Result.ExecuteScriptAsync(script).AsTask(); // WebView2 ExecuteScriptAsync for JavaScript execution - } - - async void EvaluateJavascriptFunction(string function, string[] args) - { - try - { - string script = $"{function}({string.Join(",", args.Select(x => $"\"{x}\""))});"; - await Result.ExecuteScriptAsync(script); - } - catch (Exception ex) - { - if (ex.Message.Contains("0x80020101")) - { - Log.For(this).Error(ex, $"Syntax error in the JavaScript invoking function '{function}' with params:\n" + args.ToLinesString()); - } - else - { - Log.For(this).Error(ex, "EvaluateJavascriptFunction() failed."); - } - } - } - - public controls.WebView2 Render() => Result; // Return WebView2 - - void Reload() - { - var url = View.Url; - if (url.IsEmpty()) return; - - if (url.IsUrl()) - Result.Source = new Uri(url); // Use Uri object for WebView2 - else - Result.NavigateToString(View.GetExecutableHtml().OrEmpty()); - } - - public Uri GetUri() - { - var path = View.Url; - - if (path.Contains(":")) return new Uri(path); - - var notFound = new Uri(Device.IO.AbsolutePath("Images/Icons/not-found.png")); - - var file = Device.IO.File(path.TrimStart("/").Replace("/", "\\")); - if (!file.Exists() && file.Extension.OrEmpty().ToLower().IsAnyOf(".gif", ".png", ".jpg", ".jpeg", ".webp")) - { - Log.For(this).Error("Image file does not exist: " + file); - return notFound; - } - - return new Uri(file.FullName); - } - - public void Dispose() - { - Result = null; - View = null; - - GC.SuppressFinalize(this); - } -} \ No newline at end of file