Skip to content
Merged
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
Expand Up @@ -77,7 +77,6 @@
<ItemGroup>
<EmbeddedResource Include="Resources\Embedded\*" />
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
<MauiAsset Include="..\..\..\Core\src\Handlers\HybridWebView\HybridWebView.js" LogicalName="HybridSamplePage\scripts\HybridWebView.js" />
<MauiImage Include="Resources\Images\*" />
<MauiImage Update="Resources\Images\*.gif" Resize="false" />
<MauiIcon Include="Resources\AppIcons\appicon.svg" ForegroundFile="Resources\AppIcons\appicon_foreground.svg" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<title></title>
<link rel="icon" href="data:,">
<link rel="stylesheet" href="styles/app.css">
<script src="scripts/HybridWebView.js"></script>
<script src="_framework/hybridwebview.js"></script>
<script>
function LogMessage(msg) {
var messageLog = document.getElementById("messageLog");
Expand Down
1 change: 0 additions & 1 deletion src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
<!-- Raw Assets for HybridWebView tests (removes the "Resources\Raw" prefix, to mimic what project templates do) -->
<None Remove="Resources\Raw\**" />
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
<MauiAsset Include="..\..\..\Core\src\Handlers\HybridWebView\HybridWebView.js" LogicalName="HybridTestRoot\scripts\HybridWebView.js" />
</ItemGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta charset="utf-8" />
<title></title>
<link rel="icon" href="data:,">
<script src="scripts/HybridWebView.js"></script>
<script src="_framework/hybridwebview.js"></script>

<!-- test helper functions-->
<script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta charset="utf-8" />
<title></title>
<link rel="icon" href="data:,">
<script src="scripts/HybridWebView.js"></script>
<script src="_framework/hybridwebview.js"></script>
<script>
window.addEventListener(
"HybridWebViewMessageReceived",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,21 @@ private async void OnWebResourceRequested(CoreWebView2 sender, CoreWebView2WebRe

if (new Uri(requestUri) is Uri uri && AppOriginUri.IsBaseOf(uri))
{
var relativePath = AppOriginUri.MakeRelativeUri(uri).ToString().Replace('/', '\\');
var relativePath = AppOriginUri.MakeRelativeUri(uri).ToString();

// 1. Try special InvokeDotNet path
// 1.a. Try the special "_framework/hybridwebview.js" path
if (relativePath == HybridWebViewDotJsPath)
{
logger?.LogDebug("Request for {Url} will return the hybrid web view script.", url);
var jsStream = GetEmbeddedStream(HybridWebViewDotJsPath);
if (jsStream is not null)
{
var ras = await CopyContentToRandomAccessStreamAsync(jsStream);
return (Stream: ras, ContentType: "application/javascript", StatusCode: 200, Reason: "OK");
}
}

// 1.b. Try special InvokeDotNet path
if (relativePath == InvokeDotNetPath)
{
logger?.LogDebug("Request for {Url} will be handled by the .NET method invoker.", url);
Expand Down
17 changes: 17 additions & 0 deletions src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public partial class HybridWebViewHandler : IHybridWebViewHandler
internal static readonly Uri AppOriginUri = new(AppOrigin);

internal const string InvokeDotNetPath = "__hwvInvokeDotNet";
internal const string HybridWebViewDotJsPath = "_framework/hybridwebview.js";

public static IPropertyMapper<IHybridWebView, IHybridWebViewHandler> Mapper = new PropertyMapper<IHybridWebView, IHybridWebViewHandler>(ViewHandler.ViewMapper)
{
Expand Down Expand Up @@ -493,6 +494,22 @@ await handler.InvokeAsync(nameof(IHybridWebView.EvaluateJavaScriptAsync),
return await FileSystem.OpenAppPackageFileAsync(assetPath);
}

internal static Stream? GetEmbeddedStream(string embeddedPath)
{
var assembly = typeof(HybridWebViewHandler).Assembly;

var resourceName = assembly
.GetManifestResourceNames()
.FirstOrDefault(name => name.Equals(embeddedPath.Replace('\\', '/'), StringComparison.OrdinalIgnoreCase));

if (resourceName is null)
{
return null;
}

return assembly.GetManifestResourceStream(resourceName);
}

#if !NETSTANDARD
internal static readonly FileExtensionContentTypeProvider ContentTypeProvider = new();
#endif
Expand Down
29 changes: 21 additions & 8 deletions src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Web;
using Foundation;
using Microsoft.Extensions.Logging;
using Microsoft.Maui.Storage;
using UIKit;
using WebKit;
using RectangleF = CoreGraphics.CGRect;
Expand Down Expand Up @@ -203,7 +204,7 @@ public async void StartUrlSchemeTask(WKWebView webView, IWKUrlSchemeTask urlSche
// 2.c. Return the body
if (bytes?.Length > 0)
{
urlSchemeTask.DidReceiveData(NSData.FromArray(bytes));
urlSchemeTask.DidReceiveData(bytes);
}

// 2.d. Finish the task
Expand All @@ -217,7 +218,7 @@ public async void StartUrlSchemeTask(WKWebView webView, IWKUrlSchemeTask urlSche
logger?.LogDebug("Request for {Url} was not handled.", url);
}

private async Task<(byte[]? ResponseBytes, string? ContentType, int StatusCode)> GetResponseBytesAsync(string url, ILogger? logger)
private async Task<(NSData? ResponseBytes, string? ContentType, int StatusCode)> GetResponseBytesAsync(string url, ILogger? logger)
{
if (Handler is null)
{
Expand All @@ -229,11 +230,22 @@ public async void StartUrlSchemeTask(WKWebView webView, IWKUrlSchemeTask urlSche

if (new Uri(url) is Uri uri && AppOriginUri.IsBaseOf(uri))
{
var relativePath = AppOriginUri.MakeRelativeUri(uri).ToString().Replace('\\', '/');
var relativePath = AppOriginUri.MakeRelativeUri(uri).ToString();

var bundleRootDir = Path.Combine(NSBundle.MainBundle.ResourcePath, Handler.VirtualView.HybridRoot!);

// 1. Try special InvokeDotNet path
// 1.a. Try the special "_framework/hybridwebview.js" path
if (relativePath == HybridWebViewDotJsPath)
{
logger?.LogDebug("Request for {Url} will return the hybrid web view script.", url);
var jsStream = GetEmbeddedStream(HybridWebViewDotJsPath);
if (jsStream is not null)
{
return (NSData.FromStream(jsStream), ContentType: "application/javascript", StatusCode: 200);
}
}

// 1.b. Try special InvokeDotNet path
if (relativePath == InvokeDotNetPath)
{
logger?.LogDebug("Request for {Url} will be handled by the .NET method invoker.", url);
Expand All @@ -243,7 +255,7 @@ public async void StartUrlSchemeTask(WKWebView webView, IWKUrlSchemeTask urlSche
var contentBytes = await Handler.InvokeDotNetAsync(invokeQueryString);
if (contentBytes is not null)
{
return (contentBytes, "application/json", StatusCode: 200);
return (NSData.FromArray(contentBytes), "application/json", StatusCode: 200);
}
}

Expand All @@ -252,7 +264,7 @@ public async void StartUrlSchemeTask(WKWebView webView, IWKUrlSchemeTask urlSche
// 2. If nothing found yet, try to get static content from the asset path
if (string.IsNullOrEmpty(relativePath))
{
relativePath = Handler.VirtualView.DefaultFile!.Replace('\\', '/');
relativePath = Handler.VirtualView.DefaultFile;
contentType = "text/html";
}
else
Expand All @@ -264,14 +276,15 @@ public async void StartUrlSchemeTask(WKWebView webView, IWKUrlSchemeTask urlSche
}
}

var assetPath = Path.Combine(bundleRootDir, relativePath);
var assetPath = Path.Combine(bundleRootDir, relativePath!);
assetPath = FileSystemUtils.NormalizePath(assetPath);

if (File.Exists(assetPath))
{
// 2.a. If something was found, return the content
logger?.LogDebug("Request for {Url} will return an app package file.", url);

return (File.ReadAllBytes(assetPath), contentType, StatusCode: 200);
return (NSData.FromFile(assetPath), contentType, StatusCode: 200);
}
}

Expand Down
15 changes: 13 additions & 2 deletions src/Core/src/Platform/Android/MauiHybridWebViewClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,20 @@ public MauiHybridWebViewClient(HybridWebViewHandler handler)

logger?.LogDebug("Request for {Url} will be handled by .NET MAUI.", fullUrl);

var relativePath = HybridWebViewHandler.AppOriginUri.MakeRelativeUri(uri).ToString().Replace('/', '\\');
var relativePath = HybridWebViewHandler.AppOriginUri.MakeRelativeUri(uri).ToString();

// 1. Try special InvokeDotNet path
// 1.a. Try the special "_framework/hybridwebview.js" path
if (relativePath == HybridWebViewHandler.HybridWebViewDotJsPath)
{
logger?.LogDebug("Request for {Url} will return the hybrid web view script.", fullUrl);
var jsStream = HybridWebViewHandler.GetEmbeddedStream(HybridWebViewHandler.HybridWebViewDotJsPath);
if (jsStream is not null)
{
return new WebResourceResponse("application/json", "UTF-8", 200, "OK", GetHeaders("application/json"), jsStream);
}
}

// 1.b. Try special InvokeDotNet path
if (relativePath == HybridWebViewHandler.InvokeDotNetPath)
{
logger?.LogDebug("Request for {Url} will be handled by the .NET method invoker.", fullUrl);
Expand Down
Loading