-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Very basic functionality working! (Windows and Android)
- Loading branch information
Showing
20 changed files
with
1,607 additions
and
0 deletions.
There are no files selected for viewing
21 changes: 21 additions & 0 deletions
21
src/Controls/samples/Controls.Sample/Pages/Controls/HybridWebViewPage.xaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<views:BasePage | ||
xmlns="http://schemas.microsoft.com/dotnet/2021/maui" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | ||
x:Class="Maui.Controls.Sample.Pages.HybridWebViewPage" | ||
xmlns:views="clr-namespace:Maui.Controls.Sample.Pages.Base" | ||
Title="HybridWebView"> | ||
<views:BasePage.Content> | ||
<ScrollView> | ||
<VerticalStackLayout Padding="12"> | ||
<Label Text="HybridWebView here" x:Name="statusLabel" /> | ||
<Button Text="Send message to JS" Pressed="SendMessageButton_Pressed" /> | ||
<HybridWebView | ||
x:Name="hwv" | ||
HeightRequest="150" | ||
HorizontalOptions="FillAndExpand" | ||
HybridRoot="HybridSamplePage" | ||
RawMessageReceived="hwv_RawMessageReceived"/> | ||
</VerticalStackLayout> | ||
</ScrollView> | ||
</views:BasePage.Content> | ||
</views:BasePage> |
23 changes: 23 additions & 0 deletions
23
src/Controls/samples/Controls.Sample/Pages/Controls/HybridWebViewPage.xaml.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using System; | ||
using Microsoft.Maui.Controls; | ||
|
||
namespace Maui.Controls.Sample.Pages | ||
{ | ||
public partial class HybridWebViewPage | ||
{ | ||
public HybridWebViewPage() | ||
{ | ||
InitializeComponent(); | ||
} | ||
|
||
private void SendMessageButton_Pressed(object sender, EventArgs e) | ||
{ | ||
hwv.SendRawMessage("Hello from C#!"); | ||
} | ||
|
||
private void hwv_RawMessageReceived(object sender, HybridWebView.HybridWebViewRawMessageReceivedEventArgs e) | ||
{ | ||
Dispatcher.Dispatch(() => statusLabel.Text += e.Message); | ||
} | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
src/Controls/samples/Controls.Sample/Resources/Raw/HybridSamplePage/index.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<!DOCTYPE html> | ||
|
||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<title></title> | ||
<script> | ||
function SendRawMessageToCSharp() { | ||
|
||
var message = "Message from JS!"; | ||
|
||
if (window.chrome && window.chrome.webview) { | ||
// Windows WebView2 | ||
window.chrome.webview.postMessage(message); | ||
} | ||
else if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.webwindowinterop) { | ||
// iOS and MacCatalyst WKWebView | ||
window.webkit.messageHandlers.webwindowinterop.postMessage(message); | ||
} | ||
else { | ||
// Android WebView | ||
hybridWebViewHost.sendMessage(message); | ||
} | ||
|
||
} | ||
|
||
function ReceiveRawMessageFromCSharp(message) { | ||
var messageFromCSharp = document.getElementById("messageFromCSharp"); | ||
messageFromCSharp.value += '\r\n' + message; | ||
} | ||
|
||
if (window.chrome && window.chrome.webview) { | ||
// Windows WebView2 | ||
window.chrome.webview.addEventListener('message', arg => { | ||
ReceiveRawMessageFromCSharp(arg.data); | ||
}); | ||
} | ||
else { | ||
// Android WebView | ||
window.addEventListener('message', arg => { | ||
ReceiveRawMessageFromCSharp(arg.data); | ||
}); | ||
} | ||
|
||
</script> | ||
</head> | ||
<body> | ||
<div> | ||
Hybrid sample! | ||
</div> | ||
<div> | ||
<button onclick="SendRawMessageToCSharp()">Send message to C#</button> | ||
</div> | ||
<div> | ||
Message from C#: <textarea readonly id="messageFromCSharp" style="width: 80%; height: 10em;"></textarea> | ||
</div> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Microsoft.Maui.Controls | ||
{ | ||
/// <summary> | ||
/// A <see cref="View"/> that presents local HTML content in a web view and allows JavaScript and C# code to interop using messages. | ||
/// </summary> | ||
public class HybridWebView : View, IHybridWebView | ||
{ | ||
/// <summary>Bindable property for <see cref="DefaultFile"/>.</summary> | ||
public static readonly BindableProperty DefaultFileProperty = | ||
BindableProperty.Create(nameof(DefaultFile), typeof(string), typeof(HybridWebView), defaultValue: "index.html"); | ||
/// <summary>Bindable property for <see cref="HybridRoot"/>.</summary> | ||
public static readonly BindableProperty HybridRootProperty = | ||
BindableProperty.Create(nameof(HybridRoot), typeof(string), typeof(HybridWebView), defaultValue: "HybridRoot"); | ||
|
||
|
||
/// <summary> | ||
/// Specifies the file within the <see cref="HybridRoot"/> that should be served as the default file. The | ||
/// default value is <c>index.html</c>. | ||
/// </summary> | ||
public string? DefaultFile | ||
{ | ||
get { return (string)GetValue(DefaultFileProperty); } | ||
set { SetValue(DefaultFileProperty, value); } | ||
} | ||
|
||
///// <summary> | ||
///// Gets or sets the path for initial navigation after the content is finished loading. The default value is <c>/</c>. | ||
///// </summary> | ||
//public string StartPath { get; set; } = "/"; | ||
|
||
/// <summary> | ||
/// The path within the app's "Raw" asset resources that contain the web app's contents. For example, if the | ||
/// files are located in <c>[ProjectFolder]/Resources/Raw/hybrid_root</c>, then set this property to "hybrid_root". | ||
/// The default value is <c>HybridRoot</c>, which maps to <c>[ProjectFolder]/Resources/Raw/HybridRoot</c>. | ||
/// </summary> | ||
public string? HybridRoot | ||
{ | ||
get { return (string)GetValue(HybridRootProperty); } | ||
set { SetValue(HybridRootProperty, value); } | ||
} | ||
|
||
void IHybridWebView.RawMessageReceived(string rawMessage) | ||
{ | ||
RawMessageReceived?.Invoke(this, new HybridWebViewRawMessageReceivedEventArgs(rawMessage)); | ||
} | ||
|
||
/// <summary> | ||
/// Raised when a raw message is received from the web view. Raw messages are strings that have no additional processing. | ||
/// </summary> | ||
public event EventHandler<HybridWebViewRawMessageReceivedEventArgs>? RawMessageReceived; | ||
|
||
public class HybridWebViewRawMessageReceivedEventArgs : EventArgs | ||
{ | ||
public HybridWebViewRawMessageReceivedEventArgs(string? message) | ||
{ | ||
Message = message; | ||
} | ||
|
||
public string? Message { get; } | ||
} | ||
//public void Navigate(string url) | ||
//{ | ||
// NavigateCore(url); | ||
//} | ||
|
||
// protected override async void OnHandlerChanged() | ||
// { | ||
// base.OnHandlerChanged(); | ||
|
||
// await InitializeHybridWebView(); | ||
|
||
// HybridWebViewInitialized?.Invoke(this, new HybridWebViewInitializedEventArgs() | ||
// { | ||
//#if ANDROID || IOS || MACCATALYST || WINDOWS | ||
// WebView = PlatformWebView, | ||
//#endif | ||
// }); | ||
|
||
// Navigate(StartPath); | ||
// } | ||
|
||
public void SendRawMessage(string rawMessage) | ||
{ | ||
Handler?.Invoke(nameof(IHybridWebView.SendRawMessage), rawMessage); | ||
|
||
//EvaluateJavaScriptAsync($"window.mauiBlazorWebView.receiveMessage({JsonSerializer.Serialize(message)})"); | ||
} | ||
|
||
// private partial Task InitializeHybridWebView(); | ||
|
||
// private partial void NavigateCore(string url); | ||
|
||
|
||
//#if !ANDROID && !IOS && !MACCATALYST && !WINDOWS | ||
// private partial Task InitializeHybridWebView() => throw null!; | ||
|
||
// private partial void NavigateCore(string url) => throw null!; | ||
//#endif | ||
|
||
// public virtual void OnMessageReceived(string message) | ||
// { | ||
// var messageData = JsonSerializer.Deserialize<WebMessageData>(message); | ||
// switch (messageData?.MessageType) | ||
// { | ||
// case 0: // "raw" message (just a string) | ||
// RawMessageReceived?.Invoke(this, new HybridWebViewRawMessageReceivedEventArgs(messageData.MessageContent)); | ||
// break; | ||
// default: | ||
// throw new InvalidOperationException($"Unknown message type: {messageData?.MessageType}. Message contents: {messageData?.MessageContent}"); | ||
// } | ||
|
||
// } | ||
|
||
// private sealed class WebMessageData | ||
// { | ||
// public int MessageType { get; set; } | ||
// public string? MessageContent { get; set; } | ||
// } | ||
|
||
// internal static async Task<string?> GetAssetContentAsync(string assetPath) | ||
// { | ||
// using var stream = await GetAssetStreamAsync(assetPath); | ||
// if (stream == null) | ||
// { | ||
// return null; | ||
// } | ||
// using var reader = new StreamReader(stream); | ||
|
||
// var contents = reader.ReadToEnd(); | ||
|
||
// return contents; | ||
// } | ||
|
||
// internal static async Task<Stream?> GetAssetStreamAsync(string assetPath) | ||
// { | ||
// if (!await FileSystem.AppPackageFileExistsAsync(assetPath)) | ||
// { | ||
// return null; | ||
// } | ||
// return await FileSystem.OpenAppPackageFileAsync(assetPath); | ||
// } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.Maui.Controls; | ||
using Microsoft.Maui.Handlers; | ||
using Microsoft.Maui.Hosting; | ||
using Xunit; | ||
|
||
namespace Microsoft.Maui.DeviceTests | ||
{ | ||
[Category(TestCategory.HybridWebView)] | ||
public class HybridWebViewTests : ControlsHandlerTestBase | ||
{ | ||
void SetupBuilder() | ||
{ | ||
EnsureHandlerCreated(builder => | ||
{ | ||
builder.ConfigureMauiHandlers(handlers => | ||
{ | ||
handlers.AddHandler<HybridWebView, HybridWebViewHandler>(); | ||
}); | ||
}); | ||
} | ||
|
||
[Fact] | ||
public async Task LoadsHtmlAndSendReceiveRawMessage() | ||
{ | ||
SetupBuilder(); | ||
|
||
var actual = string.Empty; | ||
|
||
var pageLoadTimeout = TimeSpan.FromSeconds(2); | ||
|
||
//string html = | ||
// @" | ||
// <!DOCTYPE html> | ||
// <html> | ||
// <head> | ||
// </head> | ||
// <body> | ||
// <script> | ||
// function test() { | ||
// return 'Test'; | ||
// } | ||
// </script> | ||
// <p> | ||
// WebView Unit Test | ||
// </p> | ||
// </body> | ||
// </html> | ||
// "; | ||
await InvokeOnMainThreadAsync(async () => | ||
{ | ||
var hybridWebView = new HybridWebView() | ||
{ | ||
WidthRequest = 100, | ||
HeightRequest = 100, | ||
//Source = new HtmlWebViewSource { Html = html } | ||
}; | ||
var handler = CreateHandler(hybridWebView); | ||
var platformView = handler.PlatformView; | ||
// Setup the view to be displayed/parented and run our tests on it | ||
await AttachAndRun(hybridWebView, async (handler) => | ||
{ | ||
await Task.Delay(5000); | ||
//// Wait for the page to load | ||
//var tcsLoaded = new TaskCompletionSource<bool>(); | ||
//var ctsTimeout = new CancellationTokenSource(pageLoadTimeout); | ||
//ctsTimeout.Token.Register(() => tcsLoaded.TrySetException(new TimeoutException($"Failed to load HTML"))); | ||
//webView.Navigated += async (source, args) => | ||
//{ | ||
// // Set success when we have a successful nav result | ||
// if (args.Result == WebNavigationResult.Success) | ||
// { | ||
// tcsLoaded.TrySetResult(args.Result == WebNavigationResult.Success); | ||
// // Evaluate JavaScript | ||
// var script = "test();"; | ||
// actual = await webView.EvaluateJavaScriptAsync(script); | ||
// // If the result is equal to the script string result, the test has passed | ||
// Assert.Equal("Test", actual); | ||
// } | ||
//}; | ||
//Assert.True(await tcsLoaded.Task); | ||
}); | ||
}); | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/Controls/tests/DeviceTests/Resources/Raw/HybridRoot/index.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<!DOCTYPE html> | ||
|
||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<title></title> | ||
</head> | ||
<body> | ||
I'm a hybrid! | ||
</body> | ||
</html> |
Oops, something went wrong.