WebView completed

This commit is contained in:
2026-01-16 05:40:49 +00:00
parent a11b081510
commit bf2f380f56
2 changed files with 153 additions and 0 deletions

View File

@@ -15,6 +15,7 @@ public partial class WebViewHandler : ViewHandler<IWebView, SkiaWebView>
public static IPropertyMapper<IWebView, WebViewHandler> Mapper = new PropertyMapper<IWebView, WebViewHandler>(ViewHandler.ViewMapper) public static IPropertyMapper<IWebView, WebViewHandler> Mapper = new PropertyMapper<IWebView, WebViewHandler>(ViewHandler.ViewMapper)
{ {
[nameof(IWebView.Source)] = MapSource, [nameof(IWebView.Source)] = MapSource,
[nameof(IWebView.UserAgent)] = MapUserAgent,
}; };
public static CommandMapper<IWebView, WebViewHandler> CommandMapper = new(ViewHandler.ViewCommandMapper) public static CommandMapper<IWebView, WebViewHandler> CommandMapper = new(ViewHandler.ViewCommandMapper)
@@ -22,6 +23,8 @@ public partial class WebViewHandler : ViewHandler<IWebView, SkiaWebView>
[nameof(IWebView.GoBack)] = MapGoBack, [nameof(IWebView.GoBack)] = MapGoBack,
[nameof(IWebView.GoForward)] = MapGoForward, [nameof(IWebView.GoForward)] = MapGoForward,
[nameof(IWebView.Reload)] = MapReload, [nameof(IWebView.Reload)] = MapReload,
[nameof(IWebView.Eval)] = MapEval,
[nameof(IWebView.EvaluateJavaScriptAsync)] = MapEvaluateJavaScriptAsync,
}; };
public WebViewHandler() : base(Mapper, CommandMapper) public WebViewHandler() : base(Mapper, CommandMapper)
@@ -127,4 +130,66 @@ public partial class WebViewHandler : ViewHandler<IWebView, SkiaWebView>
{ {
handler.PlatformView?.Reload(); handler.PlatformView?.Reload();
} }
public static void MapUserAgent(WebViewHandler handler, IWebView webView)
{
if (handler.PlatformView != null && !string.IsNullOrEmpty(webView.UserAgent))
{
handler.PlatformView.UserAgent = webView.UserAgent;
}
}
public static void MapEval(WebViewHandler handler, IWebView webView, object? args)
{
if (args is string script)
{
handler.PlatformView?.Eval(script);
}
}
public static void MapEvaluateJavaScriptAsync(WebViewHandler handler, IWebView webView, object? args)
{
// Handle EvaluateJavaScriptAsyncRequest from Microsoft.Maui.Platform namespace
if (args is EvaluateJavaScriptAsyncRequest request)
{
var result = handler.PlatformView?.EvaluateJavaScriptAsync(request.Script);
if (result != null)
{
result.ContinueWith(t =>
{
request.SetResult(t.Result);
});
}
else
{
request.SetResult(null);
}
}
else if (args is string script)
{
// Direct script string
handler.PlatformView?.EvaluateJavaScriptAsync(script);
}
}
}
/// <summary>
/// Request object for async JavaScript evaluation (matches Microsoft.Maui.Platform.EvaluateJavaScriptAsyncRequest).
/// </summary>
public class EvaluateJavaScriptAsyncRequest
{
public string Script { get; }
private readonly System.Threading.Tasks.TaskCompletionSource<string?> _tcs = new();
public EvaluateJavaScriptAsyncRequest(string script)
{
Script = script;
}
public System.Threading.Tasks.Task<string?> Task => _tcs.Task;
public void SetResult(string? result)
{
_tcs.TrySetResult(result);
}
} }

View File

@@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SkiaSharp; using SkiaSharp;
@@ -33,6 +34,9 @@ public class SkiaWebView : SkiaView
private delegate void WebKitSettingsSetEnableJavascriptDelegate(IntPtr settings, bool enabled); private delegate void WebKitSettingsSetEnableJavascriptDelegate(IntPtr settings, bool enabled);
private delegate void WebKitSettingsSetHardwareAccelerationPolicyDelegate(IntPtr settings, int policy); private delegate void WebKitSettingsSetHardwareAccelerationPolicyDelegate(IntPtr settings, int policy);
private delegate void WebKitSettingsSetEnableWebglDelegate(IntPtr settings, bool enabled); private delegate void WebKitSettingsSetEnableWebglDelegate(IntPtr settings, bool enabled);
private delegate void WebKitSettingsSetUserAgentDelegate(IntPtr settings, [MarshalAs(UnmanagedType.LPStr)] string userAgent);
private delegate IntPtr WebKitSettingsGetUserAgentDelegate(IntPtr settings);
private delegate void WebKitWebViewRunJavascriptDelegate(IntPtr webView, [MarshalAs(UnmanagedType.LPStr)] string script, IntPtr cancellable, IntPtr callback, IntPtr userData);
#endregion #endregion
@@ -109,6 +113,9 @@ public class SkiaWebView : SkiaView
private static WebKitSettingsSetEnableJavascriptDelegate? _webkitSetJavascript; private static WebKitSettingsSetEnableJavascriptDelegate? _webkitSetJavascript;
private static WebKitSettingsSetHardwareAccelerationPolicyDelegate? _webkitSetHardwareAcceleration; private static WebKitSettingsSetHardwareAccelerationPolicyDelegate? _webkitSetHardwareAcceleration;
private static WebKitSettingsSetEnableWebglDelegate? _webkitSetWebgl; private static WebKitSettingsSetEnableWebglDelegate? _webkitSetWebgl;
private static WebKitSettingsSetUserAgentDelegate? _webkitSetUserAgent;
private static WebKitSettingsGetUserAgentDelegate? _webkitGetUserAgent;
private static WebKitWebViewRunJavascriptDelegate? _webkitRunJavascript;
private static readonly List<SkiaWebView> _activeWebViews = new(); private static readonly List<SkiaWebView> _activeWebViews = new();
private static readonly Dictionary<IntPtr, SkiaWebView> _webViewInstances = new(); private static readonly Dictionary<IntPtr, SkiaWebView> _webViewInstances = new();
@@ -127,6 +134,8 @@ public class SkiaWebView : SkiaView
private bool _isEmbedded; private bool _isEmbedded;
private bool _isProperlyReparented; private bool _isProperlyReparented;
private bool _javascriptEnabled = true; private bool _javascriptEnabled = true;
private string? _userAgent;
private CookieContainer _cookies = new();
private double _loadProgress; private double _loadProgress;
private SKRect _lastBounds; private SKRect _lastBounds;
private int _lastMainX; private int _lastMainX;
@@ -447,6 +456,38 @@ public class SkiaWebView : SkiaView
public double LoadProgress => _loadProgress; public double LoadProgress => _loadProgress;
public string? UserAgent
{
get
{
if (!string.IsNullOrEmpty(_userAgent))
return _userAgent;
if (_webView == IntPtr.Zero || _webkitGetSettings == null || _webkitGetUserAgent == null)
return null;
var settings = _webkitGetSettings(_webView);
if (settings == IntPtr.Zero) return null;
var ptr = _webkitGetUserAgent(settings);
return ptr != IntPtr.Zero ? Marshal.PtrToStringAnsi(ptr) : null;
}
set
{
_userAgent = value;
UpdateUserAgentSetting();
}
}
/// <summary>
/// Gets or sets the cookie container for this WebView.
/// Note: Cookies set here are available for .NET code but are not automatically
/// synchronized with WebKitGTK's internal cookie storage. For full cookie
/// integration, use JavaScript-based cookie operations.
/// </summary>
public CookieContainer Cookies
{
get => _cookies;
set => _cookies = value ?? new CookieContainer();
}
public static bool IsSupported => InitializeWebKit(); public static bool IsSupported => InitializeWebKit();
#endregion #endregion
@@ -534,6 +575,9 @@ public class SkiaWebView : SkiaView
_webkitSetJavascript = LoadFunction<WebKitSettingsSetEnableJavascriptDelegate>("webkit_settings_set_enable_javascript"); _webkitSetJavascript = LoadFunction<WebKitSettingsSetEnableJavascriptDelegate>("webkit_settings_set_enable_javascript");
_webkitSetHardwareAcceleration = LoadFunction<WebKitSettingsSetHardwareAccelerationPolicyDelegate>("webkit_settings_set_hardware_acceleration_policy"); _webkitSetHardwareAcceleration = LoadFunction<WebKitSettingsSetHardwareAccelerationPolicyDelegate>("webkit_settings_set_hardware_acceleration_policy");
_webkitSetWebgl = LoadFunction<WebKitSettingsSetEnableWebglDelegate>("webkit_settings_set_enable_webgl"); _webkitSetWebgl = LoadFunction<WebKitSettingsSetEnableWebglDelegate>("webkit_settings_set_enable_webgl");
_webkitSetUserAgent = LoadFunction<WebKitSettingsSetUserAgentDelegate>("webkit_settings_set_user_agent");
_webkitGetUserAgent = LoadFunction<WebKitSettingsGetUserAgentDelegate>("webkit_settings_get_user_agent");
_webkitRunJavascript = LoadFunction<WebKitWebViewRunJavascriptDelegate>("webkit_web_view_run_javascript");
Console.WriteLine($"[WebView] Using {_webkitLib}"); Console.WriteLine($"[WebView] Using {_webkitLib}");
return _webkitWebViewNew != null; return _webkitWebViewNew != null;
@@ -663,6 +707,7 @@ public class SkiaWebView : SkiaView
ConfigureWebKitSettings(); ConfigureWebKitSettings();
UpdateJavaScriptSetting(); UpdateJavaScriptSetting();
UpdateUserAgentSetting();
_isInitialized = true; _isInitialized = true;
lock (_activeWebViews) lock (_activeWebViews)
@@ -740,6 +785,18 @@ public class SkiaWebView : SkiaView
} }
} }
private void UpdateUserAgentSetting()
{
if (_webView == IntPtr.Zero || _webkitGetSettings == null || _webkitSetUserAgent == null) return;
if (string.IsNullOrEmpty(_userAgent)) return;
var settings = _webkitGetSettings(_webView);
if (settings != IntPtr.Zero)
{
_webkitSetUserAgent(settings, _userAgent);
}
}
#endregion #endregion
#region Navigation #region Navigation
@@ -802,6 +859,37 @@ public class SkiaWebView : SkiaView
_webkitStopLoading?.Invoke(_webView); _webkitStopLoading?.Invoke(_webView);
} }
/// <summary>
/// Evaluates JavaScript in the WebView. This is a fire-and-forget operation.
/// For MAUI compatibility - use EvaluateJavaScriptAsync for async results.
/// </summary>
public void Eval(string script)
{
if (_webView == IntPtr.Zero || _webkitRunJavascript == null || string.IsNullOrEmpty(script)) return;
_webkitRunJavascript(_webView, script, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
}
/// <summary>
/// Evaluates JavaScript in the WebView asynchronously.
/// Note: WebKitGTK async result handling is complex - this implementation
/// executes the script but returns null. Full async result support would
/// require GAsyncReadyCallback integration.
/// </summary>
public System.Threading.Tasks.Task<string?> EvaluateJavaScriptAsync(string script)
{
if (_webView == IntPtr.Zero || _webkitRunJavascript == null || string.IsNullOrEmpty(script))
{
return System.Threading.Tasks.Task.FromResult<string?>(null);
}
// Execute the JavaScript
_webkitRunJavascript(_webView, script, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
// Note: Full async result handling would require GAsyncReadyCallback
// For now, we execute and return null (script side effects still work)
return System.Threading.Tasks.Task.FromResult<string?>(null);
}
#endregion #endregion
#region Event Processing #region Event Processing