Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
using WebViewCore.Enums;
using Android.Graphics;
using WebViewCore.Enums;

namespace Avalonia.WebView.Android.Clients;

[SupportedOSPlatform("android23.0")]
internal class AvaloniaWebViewClient : WebViewClient
{
public AvaloniaWebViewClient(AndroidWebViewCore webViewHandler, IVirtualWebViewControlCallBack callBack, IVirtualBlazorWebViewProvider provider, WebScheme webScheme)
public AvaloniaWebViewClient(
AndroidWebViewCore webViewHandler,
IVirtualWebViewControlCallBack callBack
)
{
ArgumentNullException.ThrowIfNull(webViewHandler);
ArgumentNullException.ThrowIfNull(callBack);
ArgumentNullException.ThrowIfNull(provider);
ArgumentNullException.ThrowIfNull(webScheme);
_callBack = callBack;
_webViewCore = webViewHandler;
_provider = provider;
_webView = webViewHandler.WebView;
_webScheme = webScheme;
}


protected AvaloniaWebViewClient(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
protected AvaloniaWebViewClient(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
// This constructor is called whenever the .NET proxy was disposed, and it was recreated by Java. It also
// happens when overridden methods are called between execution of this constructor and the one above.
Expand All @@ -29,74 +29,44 @@ protected AvaloniaWebViewClient(IntPtr javaReference, JniHandleOwnership transfe
readonly AndroidWebViewCore? _webViewCore;
readonly AndroidWebView? _webView;
readonly IVirtualWebViewControlCallBack? _callBack;
readonly IVirtualBlazorWebViewProvider? _provider;
readonly WebScheme? _webScheme;

bool _isStarted = false;

public override bool ShouldOverrideUrlLoading(AndroidWebView? view, IWebResourceRequest? request)
public override bool ShouldOverrideUrlLoading(
AndroidWebView? view,
IWebResourceRequest? request
)
#pragma warning disable CA1416
=> ShouldOverrideUrlLoadingCore(request) || base.ShouldOverrideUrlLoading(view, request);
=>
ShouldOverrideUrlLoadingCore(view, request) || base.ShouldOverrideUrlLoading(view, request);
#pragma warning restore CA1416

public override AndroidWebResourceResponse? ShouldInterceptRequest(AndroidWebView? view, IWebResourceRequest? request)
{
ArgumentException.ThrowIfNullOrEmpty(nameof(request));
Func<AndroidWebResourceResponse?> func = () =>
{
if (_webScheme is null || _provider is null)
return default;

var requestUri = request?.Url?.ToString();
if (requestUri == null)
return default;

var allowFallbackOnHostPage = _webScheme.BaseUri.IsBaseOfPage(requestUri);

var webRequest = new WebResourceRequest
{
RequestUri = requestUri!,
AllowFallbackOnHostPage = allowFallbackOnHostPage
};

if (!_provider.PlatformWebViewResourceRequested(_webViewCore, webRequest, out var webResponse))
return default;

if (webResponse is null)
return default;

var contentType = webResponse.Headers[QueryStringHelper.ContentTypeKey];

return new AndroidWebResourceResponse(contentType, "UTF-8", webResponse.StatusCode, webResponse.StatusMessage, webResponse.Headers, webResponse.Content);
};
var ret = func.Invoke();

if (ret is null)
return base.ShouldInterceptRequest(view, request);
else
return ret;
}

public override void OnPageFinished(AndroidWebView? view, string? url)
{
base.OnPageFinished(view, url);

if (view is null)
return;

if (string.IsNullOrWhiteSpace(url))
return;

if (_webScheme is null)
System.Diagnostics.Debug.WriteLine($"OnPageFinished: {url}");
if (_callBack is null || !Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out var uri))
return;

if (_webScheme.BaseUri.IsBaseOfPage(url))
RunBlazorStarupScripts();
_callBack.PlatformWebViewNavigationCompleted(
_webViewCore,
new WebViewUrlLoadedEventArg { IsSuccess = true }
);
}

bool ShouldOverrideUrlLoadingCore(IWebResourceRequest? request)
bool ShouldOverrideUrlLoadingCore(AndroidWebView? view, IWebResourceRequest? request)
{
if (_callBack is null || !Uri.TryCreate(request?.Url?.ToString(), UriKind.RelativeOrAbsolute, out var uri))
if (view is null)
{
return false;
}
System.Diagnostics.Debug.WriteLine(
$"ShouldOverrideUrlLoadingCore: {request?.Url?.ToString()}"
);
if (
_callBack is null
|| !Uri.TryCreate(request?.Url?.ToString(), UriKind.RelativeOrAbsolute, out var uri)
)
return false;
WebViewUrlLoadingEventArg args = new() { Url = uri, RawArgs = request };
_callBack.PlatformWebViewNavigationStarting(_webViewCore, args);
Expand Down Expand Up @@ -125,71 +95,15 @@ bool ShouldOverrideUrlLoadingCore(IWebResourceRequest? request)
_webView?.LoadUrl(uri.OriginalString);
isSucceed = true;
break;
case UrlRequestStrategy.CancelLoad:
case UrlRequestStrategy.CancelLoad:
break;
default:
break;
}

_callBack.PlatformWebViewNavigationCompleted(_webViewCore, new WebViewUrlLoadedEventArg() {IsSuccess = isSucceed });

_callBack.PlatformWebViewNavigationCompleted(
_webViewCore,
new WebViewUrlLoadedEventArg { IsSuccess = isSucceed }
);
return true;
}

void RunBlazorStarupScripts()
{
if (_webView is null)
return;

_webView.EvaluateJavascript(BlazorScriptHelper.BlazorStartedScript, new JavaScriptValueCallback(blazorStarted =>
{
var result = blazorStarted?.ToString();

if (result != BlazorScriptHelper.UndefinedString)
return;

_webView.EvaluateJavascript(BlazorScriptHelper.BlazorMessageScript, new JavaScriptValueCallback(_ =>
{
_isStarted = true;
BlazorMessageChannel(_webView, _provider!);

_webView.EvaluateJavascript(BlazorScriptHelper.BlazorStartingScript, new JavaScriptValueCallback(_ =>
{

}));

}));
}));
}

void BlazorMessageChannel(AndroidWebView webView, IVirtualBlazorWebViewProvider provider)
{
if (webView is null)
return;

if (provider is null)
return;

if (_webScheme is null)
return;

var nativeToJSPorts = webView.CreateWebMessageChannel();
var nativeToJs = new BlazorWebMessageCallback(message =>
{
if (string.IsNullOrWhiteSpace(message))
return;

provider.PlatformWebViewMessageReceived(_webViewCore, new WebViewMessageReceivedEventArgs()
{
Source = _webScheme.BaseUri,
Message = message
});
});

var destPort = new[] { nativeToJSPorts[1] };
nativeToJSPorts[0].SetWebMessageCallback(nativeToJs);

webView.PostWebMessage(new WebMessage("capturePort", destPort), AndroidUri.Parse(_webScheme.BaseUri.AbsoluteUri)!);
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
namespace Avalonia.WebView.Android.Clients;
namespace Avalonia.WebView.Android.Clients.Blazor;

internal class AvaloniaWebChromeClient : WebChromeClient
internal class AvaloniaBlazorWebChromeClient : WebChromeClient
{
public AvaloniaWebChromeClient(AndroidWebViewCore androidWebViewCore)
public AvaloniaBlazorWebChromeClient(AndroidWebViewCore androidWebViewCore)
{
_androidWebViewCore = androidWebViewCore;
var topLevel = androidWebViewCore.GetTopLevel();
Expand All @@ -15,7 +15,12 @@ public AvaloniaWebChromeClient(AndroidWebViewCore androidWebViewCore)
readonly AndroidWebViewCore _androidWebViewCore;
readonly TopLevel _topLevel;

public override bool OnCreateWindow(AndroidWebView? view, bool isDialog, bool isUserGesture, Message? resultMsg)
public override bool OnCreateWindow(
AndroidWebView? view,
bool isDialog,
bool isUserGesture,
Message? resultMsg
)
{
if (view?.Context is not null)
{
Expand All @@ -28,7 +33,11 @@ public override bool OnCreateWindow(AndroidWebView? view, bool isDialog, bool is
return false;
}

public override bool OnShowFileChooser(AndroidWebView? webView, IValueCallback? filePathCallback, FileChooserParams? fileChooserParams)
public override bool OnShowFileChooser(
AndroidWebView? webView,
IValueCallback? filePathCallback,
FileChooserParams? fileChooserParams
)
{
if (filePathCallback is null)
return base.OnShowFileChooser(webView, filePathCallback, fileChooserParams);
Expand All @@ -37,7 +46,10 @@ public override bool OnShowFileChooser(AndroidWebView? webView, IValueCallback?
return true;
}

private async Task CallFilePickerAsync(IValueCallback filePathCallback, FileChooserParams? fileChooserParams)
private async Task CallFilePickerAsync(
IValueCallback filePathCallback,
FileChooserParams? fileChooserParams
)
{
var pickOptions = GetPickOptions(fileChooserParams);
if (pickOptions is null)
Expand Down Expand Up @@ -76,7 +88,10 @@ private async Task CallFilePickerAsync(IValueCallback filePathCallback, FileChoo
return default;

var acceptedFileTypes = fileChooserParams.GetAcceptTypes();
if (acceptedFileTypes is null || (acceptedFileTypes.Length == 1 && string.IsNullOrEmpty(acceptedFileTypes[0])))
if (
acceptedFileTypes is null
|| (acceptedFileTypes.Length == 1 && string.IsNullOrEmpty(acceptedFileTypes[0]))
)
return null;

bool allowMultiple = fileChooserParams.Mode == ChromeFileChooserMode.OpenMultiple;
Expand All @@ -86,15 +101,14 @@ private async Task CallFilePickerAsync(IValueCallback filePathCallback, FileChoo
AllowMultiple = allowMultiple,
FileTypeFilter = new List<FilePickerFileType>()
{
new FilePickerFileType("Accepted File")
{
Patterns = acceptedFileTypes,
AppleUniformTypeIdentifiers = new string[1] { "public.accepted"},
MimeTypes = new string[1] { "accepted/*" }
}
new FilePickerFileType("Accepted File")
{
Patterns = acceptedFileTypes,
AppleUniformTypeIdentifiers = new string[1] { "public.accepted" },
MimeTypes = new string[1] { "accepted/*" }
}
}
};
return pickOptions;
}
}

Loading