HybridWebView
HybridWebView .NET Multi-platform App UI (.NET MAUI) permet d’héberger du contenu HTML/JS/CSS arbitraire dans une vue web et permet une communication entre le code de la vue web (JavaScript) et le code qui héberge la vue web (C#/.NET). Par exemple, si vous disposez d’une application JS React existante, vous pouvez l’héberger dans une application .NET MAUI native multiplateforme et générer le back-end de l’application à l’aide de C# et .NET.
HybridWebView définit les propriétés suivantes :
- DefaultFile, de type
string?
, qui spécifie le fichier dans HybridRoot, qui doit être utilisé comme fichier par défaut. La valeur par défaut est index.html. - HybridRoot, de type
string?
, qui est le chemin d’accès dans les ressources brutes de l’application et qui contient le contenu de l’application web. La valeur par défaut est wwwroot, qui est mappée à Resources/Raw/wwwroot.
De plus, HybridWebView définit un événement RawMessageReceived déclenché lorsqu’un message brut est reçu. L’objet HybridWebViewRawMessageReceivedEventArgs qui accompagne l’événement définit une propriété Message qui contient le message.
Le code C# de votre application peut appeler des méthodes JavaScript synchrones et asynchrones dans HybridWebView à l’aide des méthodes InvokeJavaScriptAsync et EvaluateJavaScriptAsync. Le code JavaScript de votre application peut également appeler de manière synchrone des méthodes C#. Pour plus d’informations, consultez Appeler JavaScript à partir de C# et Appeler C# à partir de JavaScript.
Pour créer une application .NET MAUI avec HybridWebView, vous avez besoin des éléments suivants :
- Le contenu web de l’application, qui se compose de HTML statique, de JavaScript, de CSS, d’images et autres fichiers.
- Un contrôle HybridWebView faisant partie de l’interface utilisateur de l’application. Pour ce faire, référencez-le dans le code XAML de l’application.
- Du code dans le contenu web, ainsi que dans C#/.NET, qui utilise les API HybridWebView pour envoyer des messages entre les deux composants.
L’ensemble de l’application, y compris le contenu web, est empaqueté et s’exécute localement sur un appareil et peut être publié dans les magasins d’applications applicables. Le contenu web est hébergé dans un contrôle de vue web natif et s’exécute dans le contexte de l’application. Toute partie de l’application peut accéder aux services web externes, mais n’y est pas obligée.
Important
Par défaut, le contrôle ne sera pas disponible lorsque le HybridWebView découpage complet ou l’AOT natif est activé. Pour modifier ce comportement, consultez Les commutateurs de fonctionnalités de découpage.
Créer une application .NET MAUI HybridWebView
Pour créer une application .NET MAUI avec HybridWebView :
Ouvrez un projet d’application .NET MAUI existant ou créez-en un nouveau.
Ajoutez votre contenu web au projet d’application .NET MAUI.
Le contenu web de votre application doit être inclus au projet .NET MAUI sous la forme de ressources brutes. Une ressource brute est n’importe quel fichier présent dans le dossier Resources\Raw de l’application, sous-dossiers compris. Pour un HybridWebView configuré par défaut, le contenu web doit être placé dans le dossier Resources\Raw\wwwroot, et le fichier principal doit être nommé index.html.
Une application simple peut, par exemple, comporter les fichiers et le contenu suivants :
Resources\Raw\wwwroot\index.html avec le contenu suivant correspondant à l’interface utilisateur principale :
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title></title> <link rel="icon" href="data:,"> <link rel="stylesheet" href="styles/app.css"> <script src="scripts/HybridWebView.js"></script> <script> function LogMessage(msg) { var messageLog = document.getElementById("messageLog"); messageLog.value += '\r\n' + msg; } window.addEventListener( "HybridWebViewMessageReceived", function (e) { LogMessage("Raw message: " + e.detail.message); }); function AddNumbers(a, b) { var result = { "result": a + b, "operationName": "Addition" }; return result; } var count = 0; async function EvaluateMeWithParamsAndAsyncReturn(s1, s2) { const response = await fetch("/asyncdata.txt"); if (!response.ok) { throw new Error(`HTTP error: ${response.status}`); } var jsonData = await response.json(); jsonData[s1] = s2; const msg = 'JSON data is available: ' + JSON.stringify(jsonData); window.HybridWebView.SendRawMessage(msg) return jsonData; } async function InvokeDoSyncWork() { LogMessage("Invoking DoSyncWork"); await window.HybridWebView.InvokeDotNet('DoSyncWork'); LogMessage("Invoked DoSyncWork"); } async function InvokeDoSyncWorkParams() { LogMessage("Invoking DoSyncWorkParams"); await window.HybridWebView.InvokeDotNet('DoSyncWorkParams', [123, 'hello']); LogMessage("Invoked DoSyncWorkParams"); } async function InvokeDoSyncWorkReturn() { LogMessage("Invoking DoSyncWorkReturn"); const retValue = await window.HybridWebView.InvokeDotNet('DoSyncWorkReturn'); LogMessage("Invoked DoSyncWorkReturn, return value: " + retValue); } async function InvokeDoSyncWorkParamsReturn() { LogMessage("Invoking DoSyncWorkParamsReturn"); const retValue = await window.HybridWebView.InvokeDotNet('DoSyncWorkParamsReturn', [123, 'hello']); LogMessage("Invoked DoSyncWorkParamsReturn, return value: message=" + retValue.Message + ", value=" + retValue.Value); } </script> </head> <body> <div> Hybrid sample! </div> <div> <button onclick="window.HybridWebView.SendRawMessage('Message from JS! ' + (count++))">Send message to C#</button> </div> <div> <button onclick="InvokeDoSyncWork()">Call C# sync method (no params)</button> <button onclick="InvokeDoSyncWorkParams()">Call C# sync method (params)</button> <button onclick="InvokeDoSyncWorkReturn()">Call C# method (no params) and get simple return value</button> <button onclick="InvokeDoSyncWorkParamsReturn()">Call C# method (params) and get complex return value</button> </div> <div> Log: <textarea readonly id="messageLog" style="width: 80%; height: 10em;"></textarea> </div> <div> Consider checking out this PDF: <a href="docs/sample.pdf">sample.pdf</a> </div> </body> </html>
Resources\Raw\wwwroot\scripts\HybridWebView.js avec la bibliothèque JavaScript HybridWebView standard :
window.HybridWebView = { "Init": function Init() { function DispatchHybridWebViewMessage(message) { const event = new CustomEvent("HybridWebViewMessageReceived", { detail: { message: message } }); window.dispatchEvent(event); } if (window.chrome && window.chrome.webview) { // Windows WebView2 window.chrome.webview.addEventListener('message', arg => { DispatchHybridWebViewMessage(arg.data); }); } else if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.webwindowinterop) { // iOS and MacCatalyst WKWebView window.external = { "receiveMessage": message => { DispatchHybridWebViewMessage(message); } }; } else { // Android WebView window.addEventListener('message', arg => { DispatchHybridWebViewMessage(arg.data); }); } }, "SendRawMessage": function SendRawMessage(message) { window.HybridWebView.__SendMessageInternal('__RawMessage', message); }, "InvokeDotNet": async function InvokeDotNetAsync(methodName, paramValues) { const body = { MethodName: methodName }; if (typeof paramValues !== 'undefined') { if (!Array.isArray(paramValues)) { paramValues = [paramValues]; } for (var i = 0; i < paramValues.length; i++) { paramValues[i] = JSON.stringify(paramValues[i]); } if (paramValues.length > 0) { body.ParamValues = paramValues; } } const message = JSON.stringify(body); var requestUrl = `${window.location.origin}/__hwvInvokeDotNet?data=${encodeURIComponent(message)}`; const rawResponse = await fetch(requestUrl, { method: 'GET', headers: { 'Accept': 'application/json' } }); const response = await rawResponse.json(); if (response) { if (response.IsJson) { return JSON.parse(response.Result); } return response.Result; } return null; }, "__SendMessageInternal": function __SendMessageInternal(type, message) { const messageToSend = type + '|' + message; if (window.chrome && window.chrome.webview) { // Windows WebView2 window.chrome.webview.postMessage(messageToSend); } else if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.webwindowinterop) { // iOS and MacCatalyst WKWebView window.webkit.messageHandlers.webwindowinterop.postMessage(messageToSend); } else { // Android WebView hybridWebViewHost.sendMessage(messageToSend); } }, "__InvokeJavaScript": function __InvokeJavaScript(taskId, methodName, args) { if (methodName[Symbol.toStringTag] === 'AsyncFunction') { // For async methods, we need to call the method and then trigger the callback when it's done const asyncPromise = methodName(...args); asyncPromise .then(asyncResult => { window.HybridWebView.__TriggerAsyncCallback(taskId, asyncResult); }) .catch(error => console.error(error)); } else { // For sync methods, we can call the method and trigger the callback immediately const syncResult = methodName(...args); window.HybridWebView.__TriggerAsyncCallback(taskId, syncResult); } }, "__TriggerAsyncCallback": function __TriggerAsyncCallback(taskId, result) { // Make sure the result is a string if (result && typeof (result) !== 'string') { result = JSON.stringify(result); } window.HybridWebView.__SendMessageInternal('__InvokeJavaScriptCompleted', taskId + '|' + result); } } window.HybridWebView.Init();
Ensuite, ajoutez tout contenu web supplémentaire à votre projet.
Avertissement
Dans certains cas, Visual Studio peut ajouter des entrées incorrectes au fichier .csproj du projet. Si vous utilisez l’emplacement par défaut pour les ressources brutes, aucune entrée correspondant à ces fichiers ou dossiers ne devrait se trouver dans le fichier .csproj.
Ajoutez le contrôle HybridWebView à votre application :
<Grid RowDefinitions="Auto,*" ColumnDefinitions="*"> <Button Text="Send message to JavaScript" Clicked="OnSendMessageButtonClicked" /> <HybridWebView x:Name="hybridWebView" RawMessageReceived="OnHybridWebViewRawMessageReceived" Grid.Row="1" /> </Grid>
Modifiez la
CreateMauiApp
méthode de votreMauiProgram
classe pour activer les outils de développement sur les contrôles WebView sous-jacents lorsque votre application s’exécute dans la configuration du débogage. Pour ce faire, appelez la AddHybridWebViewDeveloperTools méthode sur l’objet IServiceCollection :using Microsoft.Extensions.Logging; public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); #if DEBUG builder.Services.AddHybridWebViewDeveloperTools(); builder.Logging.AddDebug(); #endif // Register any app services on the IServiceCollection object return builder.Build(); } }
Utilisez les API HybridWebView pour envoyer des messages entre le code JavaScript et le code C# :
private void OnSendMessageButtonClicked(object sender, EventArgs e) { hybridWebView.SendRawMessage($"Hello from C#!"); } private async void OnHybridWebViewRawMessageReceived(object sender, HybridWebViewRawMessageReceivedEventArgs e) { await DisplayAlert("Raw Message Received", e.Message, "OK"); }
Les messages ci-dessus sont classés comme bruts, car aucun traitement supplémentaire n’est effectué. Vous pouvez également encoder des données dans le message si vous souhaitez effectuer des tâches de messagerie plus avancées.
Appeler JavaScript à partir de C#
Le code C# de votre application peut appeler de manière synchrone et asynchrone des méthodes JavaScript dans HybridWebView, avec des paramètres facultatifs et une valeur de retour facultative. Cela peut être réalisé avec les méthodes EvaluateJavaScriptAsync et InvokeJavaScriptAsync :
- La méthode EvaluateJavaScriptAsync exécute le code JavaScript fourni via un paramètre et retourne le résultat sous forme de chaîne.
- La InvokeJavaScriptAsync méthode appelle une méthode JavaScript spécifiée, en passant éventuellement des valeurs de paramètre et spécifie un argument générique qui indique le type de la valeur de retour. Elle retourne un objet du type d’argument générique qui contient la valeur de retour de la méthode JavaScript appelée. En interne, les paramètres et les valeurs de retour sont encodés au format JSON.
Appeler des méthodes JavaScript synchrones
Les méthodes JavaScript synchrones peuvent être appelées avec les méthodes EvaluateJavaScriptAsync et InvokeJavaScriptAsync. Dans l’exemple suivant, la méthode InvokeJavaScriptAsync est utilisée pour illustrer l’appel de JavaScript incorporé dans le contenu web d’une application. Par exemple, une méthode Javascript simple pour ajouter deux nombres peut être définie dans votre contenu web :
function AddNumbers(a, b) {
return a + b;
}
La méthode JavaScript AddNumbers
peut être appelée à partir de C# avec la méthode InvokeJavaScriptAsync :
double x = 123d;
double y = 321d;
double result = await hybridWebView.InvokeJavaScriptAsync<double>(
"AddNumbers", // JavaScript method name
HybridSampleJSContext.Default.Double, // JSON serialization info for return type
[x, y], // Parameter values
[HybridSampleJSContext.Default.Double, HybridSampleJSContext.Default.Double]); // JSON serialization info for each parameter
L’appel de méthode nécessite la spécification d’objets JsonTypeInfo
qui incluent des informations de sérialisation pour les types utilisés dans l’opération. Ces objets sont créés automatiquement en incluant la classe partial
suivante dans votre projet :
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(double))]
internal partial class HybridSampleJsContext : JsonSerializerContext
{
// This type's attributes specify JSON serialization info to preserve type structure
// for trimmed builds.
}
Important
La classe HybridSampleJsContext
doit être partial
de sorte que la génération de code puisse fournir l’implémentation lorsque le projet est compilé. Si le type est imbriqué dans un autre type, ce type doit également être partial
.
Appeler des méthodes JavaScript asynchrones
Les méthodes JavaScript asynchrones peuvent être appelées avec les méthodes EvaluateJavaScriptAsync et InvokeJavaScriptAsync. Dans l’exemple suivant, la méthode InvokeJavaScriptAsync est utilisée pour illustrer l’appel de JavaScript incorporé dans le contenu web d’une application. Par exemple, une méthode Javascript qui récupère de façon asynchrone des données peut être définie dans votre contenu web :
async function EvaluateMeWithParamsAndAsyncReturn(s1, s2) {
const response = await fetch("/asyncdata.txt");
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
var jsonData = await response.json();
jsonData[s1] = s2;
return jsonData;
}
La méthode JavaScript EvaluateMeWithParamsAndAsyncReturn
peut être appelée à partir de C# avec la méthode InvokeJavaScriptAsync :
Dictionary<string, string> asyncResult = await hybridWebView.InvokeJavaScriptAsync<Dictionary<string, string>>(
"EvaluateMeWithParamsAndAsyncReturn", // JavaScript method name
HybridSampleJSContext.Default.DictionaryStringString, // JSON serialization info for return type
["new_key", "new_value"], // Parameter values
[HybridSampleJSContext.Default.String, HybridSampleJSContext.Default.String]); // JSON serialization info for each parameter
Dans cet exemple, asyncResult
il s’agit d’un Dictionary<string, string>
qui contient les données JSON de la requête web.
L’appel de méthode nécessite la spécification d’objets JsonTypeInfo
qui incluent des informations de sérialisation pour les types utilisés dans l’opération. Ces objets sont créés automatiquement en incluant la classe partial
suivante dans votre projet :
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Dictionary<string, string>))]
[JsonSerializable(typeof(string))]
internal partial class HybridSampleJSContext : JsonSerializerContext
{
// This type's attributes specify JSON serialization info to preserve type structure
// for trimmed builds.
}
Important
La classe HybridSampleJsContext
doit être partial
de sorte que la génération de code puisse fournir l’implémentation lorsque le projet est compilé. Si le type est imbriqué dans un autre type, ce type doit également être partial
.
Appeler C# à partir de JavaScript
Le code JavaScript de votre application au sein de l’application HybridWebView peut appeler de manière synchrone des méthodes C#, avec des paramètres facultatifs et une valeur de retour facultative. Voici ce qu’il faut faire pour y parvenir :
- Définition des méthodes C# publiques qui seront appelées à partir de JavaScript.
- Appel de la SetInvokeJavaScriptTarget méthode pour définir l’objet qui sera la cible des appels JavaScript à partir du HybridWebView.
- Appel des méthodes C# à partir de JavaScript.
Important
L’appel asynchrone de méthodes C# à partir de JavaScript n’est actuellement pas pris en charge.
L’exemple suivant définit quatre méthodes publiques pour l’appel à partir de JavaScript :
public partial class MainPage : ContentPage
{
...
public void DoSyncWork()
{
Debug.WriteLine("DoSyncWork");
}
public void DoSyncWorkParams(int i, string s)
{
Debug.WriteLine($"DoSyncWorkParams: {i}, {s}");
}
public string DoSyncWorkReturn()
{
Debug.WriteLine("DoSyncWorkReturn");
return "Hello from C#!";
}
public SyncReturn DoSyncWorkParamsReturn(int i, string s)
{
Debug.WriteLine($"DoSyncWorkParamReturn: {i}, {s}");
return new SyncReturn
{
Message = "Hello from C#!" + s,
Value = i
};
}
public class SyncReturn
{
public string? Message { get; set; }
public int Value { get; set; }
}
}
Vous devez ensuite appeler la SetInvokeJavaScriptTarget méthode pour définir l’objet qui sera la cible des appels JavaScript à partir de :HybridWebView
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
hybridWebView.SetInvokeJavaScriptTarget(this);
}
...
}
Les méthodes publiques sur l’objet défini via la SetInvokeJavaScriptTarget méthode peuvent ensuite être appelées à partir de JavaScript avec la window.HybridWebView.InvokeDotNet
fonction :
await window.HybridWebView.InvokeDotNet('DoSyncWork');
await window.HybridWebView.InvokeDotNet('DoSyncWorkParams', [123, 'hello']);
const retValue = await window.HybridWebView.InvokeDotNet('DoSyncWorkReturn');
const retValue = await window.HybridWebView.InvokeDotNet('DoSyncWorkParamsReturn', [123, 'hello']);
La window.HybridWebView.InvokeDotNet
fonction JavaScript appelle une méthode C# spécifiée, avec des paramètres facultatifs et une valeur de retour facultative.
Remarque
L’appel de la window.HybridWebView.InvokeDotNet
fonction JavaScript nécessite que votre application inclue la bibliothèque JavaScript HybridWebView.js répertoriée précédemment dans cet article.