Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The implementation of WebView SetVirtualHostNameToFolderMapping on Android is not aligned with WinUI3 #18930

Open
ForkBug opened this issue Nov 26, 2024 · 8 comments
Labels
difficulty/tbd Categorizes an issue for which the difficulty level needs to be defined. kind/bug Something isn't working project/core-tools 🛠️ Categorizes an issue or PR as relevant to core and tools

Comments

@ForkBug
Copy link

ForkBug commented Nov 26, 2024

Current behavior

The virtual hostname is mapped for navigation urls, but not for web resources(css, js, etc.)
For web.CoreWebView2.SetVirtualHostNameToFolderMapping( "anyhost", "Htmls", CoreWebView2HostResourceAccessKind.Allow);
A html file containing <img src="http://anyhost/img.png"> will fail to load the image on Android, but it works as expected on Windows 11.

Expected behavior

The hostname mapped by SetVirtualHostNameToFolderMapping gets resolved when loading CSS and images.

How to reproduce it (as minimally and precisely as possible)

The issue is in https://github.com/unoplatform/uno/blob/master/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/InternalWebClient.Android.cs

InternalClient needs to implement shouldInterceptRequest and then lookup _coreWebView.HostToFolderMap

Workaround

No workaround

Works on UWP/WinUI

None

Environment

Uno.WinUI / Uno.WinUI.WebAssembly / Uno.WinUI.Skia

NuGet package version(s)

"Uno.Sdk": "5.5.43"

Affected platforms

Android

IDE

Visual Studio 2022

IDE version

2022 17.12

Relevant plugins

Not relative

Anything else we need to know?

Does the issue exist on Ios and Macos? I haven't tested it yet.

@ForkBug ForkBug added difficulty/tbd Categorizes an issue for which the difficulty level needs to be defined. kind/bug Something isn't working triage/untriaged Indicates an issue requires triaging or verification labels Nov 26, 2024
@jeromelaban jeromelaban added project/core-tools 🛠️ Categorizes an issue or PR as relevant to core and tools and removed triage/untriaged Indicates an issue requires triaging or verification labels Nov 26, 2024
@Youssef1313
Copy link
Member

Youssef1313 commented Nov 26, 2024

Yes, I noticed that when I previously worked on WebView support for WPF. To me, it seemed like a limitation of the native Android API. The only way around this is that we alter the HTML ourselves, but not trivial to "correctly" support all the scenarios as in WinUI. Note: for WPF. I added a new interface, ISupportsVirtualHostMapping that signifies a "proper" support for the feature. The other platforms which don't use the interface are falling back to a "best effort" implementation which is not very correct.

@ForkBug
Copy link
Author

ForkBug commented Nov 26, 2024

Yes, I noticed that when I previously worked on WebView support for WPF. To me, it seemed like a limitation of the native Android API. The only way around this is that we alter the HTML ourselves, but not trivial to "correctly" support all the scenarios as in WinUI. Note: for WPF. I added a new interface, ISupportsVirtualHostMapping that signifies a "proper" support for the feature. The other platforms which don't use the interface are falling back to a "best effort" implementation which is not very correct.

The implementation is not complex but I'm not familiar with Uno dev process and the current architecture of Uno Webview, otherwise I will submit a patch. Some demonstration code(toy code):

        public override NSAndroid.Webkit.WebResourceResponse? ShouldInterceptRequest(NSAndroid.Webkit.WebView? view,
            NSAndroid.Webkit.IWebResourceRequest? request)
        {

            if (request?.Url?.Scheme?.Equals("file", StringComparison.OrdinalIgnoreCase) == true)
            {
                var filePath = NSAndroid.Net.Uri.Parse(request.Url.ToString())?.Path ?? "";
                filePath = Path.Combine(Mapped, filePath);
                if (File.Exists(filePath))
                {
                    string mimeType = GetMimeType(filePath);
                    using var stream = File.OpenRead(filePath);
                    return new NSAndroid.Webkit.WebResourceResponse(mimeType, null, stream);
                }
            }
            return base.ShouldInterceptRequest(view, request);
        }

@Youssef1313
Copy link
Member

I didn't came across ShouldInterceptRequest, sounds promising. cc @MartinZikmund

@jeromelaban
Copy link
Member

This like should be implemented around here:

public partial class NativeWebView : Android.Webkit.WebView

and here:

internal class NativeWebViewWrapper : INativeWebView

@ForkBug
Copy link
Author

ForkBug commented Nov 27, 2024

This like should be implemented around here:

public partial class NativeWebView : Android.Webkit.WebView

and here:

internal class NativeWebViewWrapper : INativeWebView

There are 2 scenes the hostname is used:

  1. Navigation. The web view loads an HTML/URL, or users click a link that causes the web view to load another HTML/URL. The HTML file is in the top frame of the web view.
  2. Web resources(css/js/imags...) loading. An HTML file is loaded into web view and refers to some css/img/js... files in another mapped hostname. The HTML may be in "anyhost1" but the image files may be in "anyhost2". The HTML contains some node like <img src="http://anyhost2/img.png">

WinUI3 support 1 and 2.
Uno Android only supports 1.

The root cause is in InternalClient

To support scene 1, InternalClient overrode ShouldOverrideUrlLoading and then called ProcessNavigation in uno/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Android/NativeWebViewWrapper.Android.cs

To support scene 2, InternalClient has to override shouldInterceptRequest
, and looks up _coreWebView.HostToFolderMap and returns the stream object in shouldInterceptRequest.

@ForkBug
Copy link
Author

ForkBug commented Dec 1, 2024

Due to the same issue, the HTML tag <base href="/" /> in the main HTML doesn't work either.

@ForkBug
Copy link
Author

ForkBug commented Dec 11, 2024

For IOS, setURLSchemeHandler could be used for interpreting web resource loading.
But that would bring another problem: Web resources have to be in the form of <img src="Unooo://anyhost2/img.png">

@ForkBug
Copy link
Author

ForkBug commented Dec 11, 2024

Workaround:
Create a web server by HttpListener or embedio.

A little slow but it works, with more flexibility.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
difficulty/tbd Categorizes an issue for which the difficulty level needs to be defined. kind/bug Something isn't working project/core-tools 🛠️ Categorizes an issue or PR as relevant to core and tools
Projects
None yet
Development

No branches or pull requests

3 participants