Skip to content

Commit f6079e7

Browse files
authored
Expose _framework/hybridwebview.js to the html (#29794)
* Expose _framework/hybridwebview.js Now that the _framework/hybridwebview.js file is embedded, we can make it available for consumption by the app. It is not required to use this URL, but it is now available. This being embedded makes things easier to update and keep in sync with the implementation of the HybridWebView. * Fix the path matching in HWV
1 parent e106339 commit f6079e7

File tree

9 files changed

+68
-17
lines changed

9 files changed

+68
-17
lines changed

src/Controls/samples/Controls.Sample/Maui.Controls.Sample.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@
7777
<ItemGroup>
7878
<EmbeddedResource Include="Resources\Embedded\*" />
7979
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
80-
<MauiAsset Include="..\..\..\Core\src\Handlers\HybridWebView\HybridWebView.js" LogicalName="HybridSamplePage\scripts\HybridWebView.js" />
8180
<MauiImage Include="Resources\Images\*" />
8281
<MauiImage Update="Resources\Images\*.gif" Resize="false" />
8382
<MauiIcon Include="Resources\AppIcons\appicon.svg" ForegroundFile="Resources\AppIcons\appicon_foreground.svg" />

src/Controls/samples/Controls.Sample/Resources/Raw/HybridSamplePage/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<title></title>
77
<link rel="icon" href="data:,">
88
<link rel="stylesheet" href="styles/app.css">
9-
<script src="scripts/HybridWebView.js"></script>
9+
<script src="_framework/hybridwebview.js"></script>
1010
<script>
1111
function LogMessage(msg) {
1212
var messageLog = document.getElementById("messageLog");

src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
<!-- Raw Assets for HybridWebView tests (removes the "Resources\Raw" prefix, to mimic what project templates do) -->
3535
<None Remove="Resources\Raw\**" />
3636
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
37-
<MauiAsset Include="..\..\..\Core\src\Handlers\HybridWebView\HybridWebView.js" LogicalName="HybridTestRoot\scripts\HybridWebView.js" />
3837
</ItemGroup>
3938

4039
<PropertyGroup>

src/Controls/tests/DeviceTests/Resources/Raw/HybridTestRoot/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<meta charset="utf-8" />
66
<title></title>
77
<link rel="icon" href="data:,">
8-
<script src="scripts/HybridWebView.js"></script>
8+
<script src="_framework/hybridwebview.js"></script>
99

1010
<!-- test helper functions-->
1111
<script>

src/Controls/tests/DeviceTests/Resources/Raw/HybridTestRoot/invokedotnettests.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<meta charset="utf-8" />
66
<title></title>
77
<link rel="icon" href="data:,">
8-
<script src="scripts/HybridWebView.js"></script>
8+
<script src="_framework/hybridwebview.js"></script>
99
<script>
1010
window.addEventListener(
1111
"HybridWebViewMessageReceived",

src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.Windows.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,21 @@ private async void OnWebResourceRequested(CoreWebView2 sender, CoreWebView2WebRe
171171

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

176-
// 1. Try special InvokeDotNet path
176+
// 1.a. Try the special "_framework/hybridwebview.js" path
177+
if (relativePath == HybridWebViewDotJsPath)
178+
{
179+
logger?.LogDebug("Request for {Url} will return the hybrid web view script.", url);
180+
var jsStream = GetEmbeddedStream(HybridWebViewDotJsPath);
181+
if (jsStream is not null)
182+
{
183+
var ras = await CopyContentToRandomAccessStreamAsync(jsStream);
184+
return (Stream: ras, ContentType: "application/javascript", StatusCode: 200, Reason: "OK");
185+
}
186+
}
187+
188+
// 1.b. Try special InvokeDotNet path
177189
if (relativePath == InvokeDotNetPath)
178190
{
179191
logger?.LogDebug("Request for {Url} will be handled by the .NET method invoker.", url);

src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public partial class HybridWebViewHandler : IHybridWebViewHandler
6666
internal static readonly Uri AppOriginUri = new(AppOrigin);
6767

6868
internal const string InvokeDotNetPath = "__hwvInvokeDotNet";
69+
internal const string HybridWebViewDotJsPath = "_framework/hybridwebview.js";
6970

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

497+
internal static Stream? GetEmbeddedStream(string embeddedPath)
498+
{
499+
var assembly = typeof(HybridWebViewHandler).Assembly;
500+
501+
var resourceName = assembly
502+
.GetManifestResourceNames()
503+
.FirstOrDefault(name => name.Equals(embeddedPath.Replace('\\', '/'), StringComparison.OrdinalIgnoreCase));
504+
505+
if (resourceName is null)
506+
{
507+
return null;
508+
}
509+
510+
return assembly.GetManifestResourceStream(resourceName);
511+
}
512+
496513
#if !NETSTANDARD
497514
internal static readonly FileExtensionContentTypeProvider ContentTypeProvider = new();
498515
#endif

src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.iOS.cs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Web;
88
using Foundation;
99
using Microsoft.Extensions.Logging;
10+
using Microsoft.Maui.Storage;
1011
using UIKit;
1112
using WebKit;
1213
using RectangleF = CoreGraphics.CGRect;
@@ -203,7 +204,7 @@ public async void StartUrlSchemeTask(WKWebView webView, IWKUrlSchemeTask urlSche
203204
// 2.c. Return the body
204205
if (bytes?.Length > 0)
205206
{
206-
urlSchemeTask.DidReceiveData(NSData.FromArray(bytes));
207+
urlSchemeTask.DidReceiveData(bytes);
207208
}
208209

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

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

230231
if (new Uri(url) is Uri uri && AppOriginUri.IsBaseOf(uri))
231232
{
232-
var relativePath = AppOriginUri.MakeRelativeUri(uri).ToString().Replace('\\', '/');
233+
var relativePath = AppOriginUri.MakeRelativeUri(uri).ToString();
233234

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

236-
// 1. Try special InvokeDotNet path
237+
// 1.a. Try the special "_framework/hybridwebview.js" path
238+
if (relativePath == HybridWebViewDotJsPath)
239+
{
240+
logger?.LogDebug("Request for {Url} will return the hybrid web view script.", url);
241+
var jsStream = GetEmbeddedStream(HybridWebViewDotJsPath);
242+
if (jsStream is not null)
243+
{
244+
return (NSData.FromStream(jsStream), ContentType: "application/javascript", StatusCode: 200);
245+
}
246+
}
247+
248+
// 1.b. Try special InvokeDotNet path
237249
if (relativePath == InvokeDotNetPath)
238250
{
239251
logger?.LogDebug("Request for {Url} will be handled by the .NET method invoker.", url);
@@ -243,7 +255,7 @@ public async void StartUrlSchemeTask(WKWebView webView, IWKUrlSchemeTask urlSche
243255
var contentBytes = await Handler.InvokeDotNetAsync(invokeQueryString);
244256
if (contentBytes is not null)
245257
{
246-
return (contentBytes, "application/json", StatusCode: 200);
258+
return (NSData.FromArray(contentBytes), "application/json", StatusCode: 200);
247259
}
248260
}
249261

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

267-
var assetPath = Path.Combine(bundleRootDir, relativePath);
279+
var assetPath = Path.Combine(bundleRootDir, relativePath!);
280+
assetPath = FileSystemUtils.NormalizePath(assetPath);
268281

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

274-
return (File.ReadAllBytes(assetPath), contentType, StatusCode: 200);
287+
return (NSData.FromFile(assetPath), contentType, StatusCode: 200);
275288
}
276289
}
277290

src/Core/src/Platform/Android/MauiHybridWebViewClient.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,20 @@ public MauiHybridWebViewClient(HybridWebViewHandler handler)
9999

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

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

104-
// 1. Try special InvokeDotNet path
104+
// 1.a. Try the special "_framework/hybridwebview.js" path
105+
if (relativePath == HybridWebViewHandler.HybridWebViewDotJsPath)
106+
{
107+
logger?.LogDebug("Request for {Url} will return the hybrid web view script.", fullUrl);
108+
var jsStream = HybridWebViewHandler.GetEmbeddedStream(HybridWebViewHandler.HybridWebViewDotJsPath);
109+
if (jsStream is not null)
110+
{
111+
return new WebResourceResponse("application/json", "UTF-8", 200, "OK", GetHeaders("application/json"), jsStream);
112+
}
113+
}
114+
115+
// 1.b. Try special InvokeDotNet path
105116
if (relativePath == HybridWebViewHandler.InvokeDotNetPath)
106117
{
107118
logger?.LogDebug("Request for {Url} will be handled by the .NET method invoker.", fullUrl);

0 commit comments

Comments
 (0)