HybridWebView
Die HybridWebView der .NET Multi-Platform App UI (.NET MAUI) ermöglicht das Hosten beliebiger HTML/JS/CSS-Inhalte in einer Webansicht und erlaubt die Kommunikation zwischen dem Code in der Webansicht (JavaScript) und dem Code, der die Webansicht hostet (C#/.NET). Wenn Sie beispielsweise eine React-JS-App haben, können Sie diese in einer plattformübergreifenden nativen .NET-MAUI-App hosten und das Back-End der App mit C# und .NET erstellen.
HybridWebView definiert die folgenden Eigenschaften:
- DefaultFile, vom Typ
string?
, der die Datei innerhalb von HybridRoot angibt, die als Standarddatei verwendet werden soll. Der Standardwert ist index.html. - HybridRoot, vom Typ
string?
, bei dem es sich um den Pfad innerhalb der Rohressourcen der App handelt, die den Inhalt der Web-App enthalten. Der Standardwert ist wwwroot, der auf Resources/Raw/wwwroot abgebildet wird.
Zusätzlich definiert HybridWebView ein RawMessageReceived Ereignis, das ausgelöst wird, wenn eine Rohnachricht empfangen wird. Das HybridWebViewRawMessageReceivedEventArgs-Objekt, das die Veranstaltung begleitet, definiert eine Message-Eigenschaft, die die Nachricht enthält.
Der C#-Code Ihrer App kann synchrone und asynchrone JavaScript-Methoden innerhalb von HybridWebView mit den Methoden InvokeJavaScriptAsync
und EvaluateJavaScriptAsync
aufrufen. Weitere Informationen hierzu finden Sie unter Aufrufen von JavaScript aus C#.
Um eine .NET MAUI-App mit HybridWebView zu erstellen, benötigen Sie:
- Den Webinhalt der App, der aus statischem HTML, JavaScript, CSS, Bildern und anderen Dateien besteht.
- Ein HybridWebView-Steuerelement als Teil der Benutzeroberfläche der App. Dies kann erreicht werden, indem es im XAML-Code der App referenziert wird.
- Code im Webinhalt und in C#/.NET, der die HybridWebView-APIs verwendet, um Nachrichten zwischen den beiden Komponenten zu senden.
Die gesamte App, einschließlich der Webinhalte, ist verpackt und läuft lokal auf einem Gerät und kann in den entsprechenden App-Stores veröffentlicht werden. Der Webinhalt wird in einer nativen Webansicht gehostet und läuft im Kontext der App. Jeder Teil der App kann auf externe Webdienste zugreifen, muss dies aber nicht.
Erstellen einer .NET MAUI HybridWebView-App
So erstellen Sie eine .NET MAUI-App mit einer HybridWebView:
Öffnen Sie ein vorhandenes .NET MAUI-App-Projekt, oder erstellen Sie ein neues .NET MAUI-App-Projekt.
Fügen Sie Ihren Webinhalt zum .NET MAUI-App-Projekt hinzu.
Der Webinhalt Ihrer App sollte als Teil eines .NET MAUI-Projekts als Rohressource eingebunden werden. Eine Rohressource ist jede Datei im Ordner Resources\Raw der App, einschließlich Unterordner. Bei einer Standard-HybridWebView sollten Webinhalte im Ordner Resources\Raw\wwwroot abgelegt werden, wobei die Hauptdatei index.html heißen sollte.
Eine einfache App kann die folgenden Dateien und Inhalte enthalten:
Resources\Raw\wwwroot\index.html mit Inhalten für die Hauptbenutzeroberfläche:
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title></title> <link rel="icon" href="data:,"> <script src="scripts/HybridWebView.js"></script> <script> window.addEventListener( "HybridWebViewMessageReceived", function (e) { var messageFromCSharp = document.getElementById("messageFromCSharp"); messageFromCSharp.value += '\r\n' + e.detail.message; }); </script> </head> <body> <h1>HybridWebView app!</h1> <div> <button onclick="window.HybridWebView.SendRawMessage('Message from JS!')">Send message to C#</button> </div> <div> Messages from C#: <textarea readonly id="messageFromCSharp" style="width: 80%; height: 300px;"></textarea> </div> </body> </html>
Resources\Raw\wwwroot\scripts\HybridWebView.js mit der standardmäßigen HybridWebView JavaScript-Bibliothek:
window.HybridWebView = { "Init": function () { 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 (message) { window.HybridWebView.__SendMessageInternal('RawMessage', message); }, "__SendMessageInternal": function (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); } }, "InvokeMethod": function (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 (taskId, result) { // Make sure the result is a string if (result && typeof (result) !== 'string') { result = JSON.stringify(result); } window.HybridWebView.__SendMessageInternal('InvokeMethodCompleted', taskId + '|' + result); } } window.HybridWebView.Init();
Fügen Sie dann weitere Webinhalte zu Ihrem Projekt hinzu.
Warnung
In einigen Fällen fügt Visual Studio möglicherweise falsche Einträge zur .csproj-Datei des Projekts hinzu. Wenn Sie den Standardpfad für Rohdressourcen verwenden, sollten in der Datei .csproj keine Einträge für diese Dateien oder Ordner vorhanden sein.
Fügen Sie das HybridWebView-Steuerelement zu Ihrer App hinzu:
<Grid RowDefinitions="Auto,*" ColumnDefinitions="*"> <Button Text="Send message to JavaScript" Clicked="OnSendMessageButtonClicked" /> <HybridWebView x:Name="hybridWebView" RawMessageReceived="OnHybridWebViewRawMessageReceived" Grid.Row="1" /> </Grid>
Verwenden Sie die HybridWebView-APIs, um Nachrichten zwischen dem JavaScript- und dem C#-Code zu senden:
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"); }
Die oben genannten Nachrichten werden als „roh“ eingestuft, da keine zusätzliche Verarbeitung erfolgt. Sie können auch Daten in der Nachricht verschlüsseln, um eine fortgeschrittenere Nachrichtenübermittlung durchzuführen.
Aufrufen von JavaScript aus C#
Der C#-Code Ihrer App kann JavaScript-Methoden synchron und asynchron innerhalb von HybridWebView mit optionalen Parametern und einem optionalen Rückgabewert aufrufen. Dies kann mit den Methoden InvokeJavaScriptAsync
und EvaluateJavaScriptAsync
erreicht werden:
- Die Methode
EvaluateJavaScriptAsync
führt den über einen Parameter bereitgestellten JavaScript-Code aus und gibt das Ergebnis als Zeichenfolge zurück. - Die
InvokeJavaScriptAsync
Methode ruft eine angegebene JavaScript-Methode auf, gibt optional Parameterwerte an und gibt ein generisches Argument an, das den Typ des Rückgabewerts angibt. Es gibt ein Objekt des generischen Argumenttyps zurück, der den Rückgabewert der aufgerufenen JavaScript-Methode enthält. Intern werden Parameter und Rückgabewerte JSON-codiert.
Aufrufen von synchronem JavaScript
Synchrone JavaScript-Methoden können mit den Methoden EvaluateJavaScriptAsync
und InvokeJavaScriptAsync
aufgerufen werden. Im folgenden Beispiel wird die Methode InvokeJavaScriptAsync
verwendet, um das Aufrufen von JavaScript zu veranschaulichen, das in den Webinhalt einer App eingebettet ist. Beispielsweise könnte eine einfache Javascript-Methode zum Addieren von zwei Zahlen in Ihrem Webinhalt definiert werden:
function AddNumbers(a, b) {
return a + b;
}
Die JavaScript-Methode AddNumbers
kann von C# aus mit der InvokeJavaScriptAsync
-Methode aufgerufen
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
Für den Methodenaufruf müssen JsonTypeInfo
-Objekte angegeben werden, die Serialisierungsinformationen für die in dem Vorgang verwendeten Typen enthalten. Diese Objekte werden automatisch erstellt, indem Sie die folgende partial
-Klasse in Ihr Projekt einfügen:
[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.
}
Wichtig
Die HybridSampleJsContext
-Klasse muss partial
sein, damit die Codegenerierung die Implementierung bereitstellen kann, wenn das Projekt kompiliert wird. Wenn der Typ in einen anderen Typ geschachtelt ist, muss dieser Typ ebenfalls partial
sein.
Aufrufen von asynchronem JavaScript-Code
Asynchrone JavaScript-Methoden können mit den Methoden EvaluateJavaScriptAsync
und InvokeJavaScriptAsync
aufgerufen werden. Im folgenden Beispiel wird die InvokeJavaScriptAsync
-Methode verwendet, um das Aufrufen von JavaScript zu veranschaulichen, das in den Webinhalt einer App eingebettet ist. Beispielsweise könnte eine Javascript-Methode, die Daten asynchron abruft, in Ihrem Webinhalt definiert werden:
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;
}
Die JavaScript-Methode EvaluateMeWithParamsAndAsyncReturn
kann von C# aus mit der InvokeJavaScriptAsync
-Methode aufgerufen werden:
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
In diesem Beispiel handelt es sich um eine Dictionary<string, string>
Datei, asyncResult
die die JSON-Daten aus der Webanforderung enthält.
Für den Methodenaufruf müssen JsonTypeInfo
-Objekte angegeben werden, die Serialisierungsinformationen für die in dem Vorgang verwendeten Typen enthalten. Diese Objekte werden automatisch erstellt, indem Sie die folgende partial
-Klasse in Ihr Projekt einfügen:
[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.
}
Wichtig
Die HybridSampleJsContext
-Klasse muss partial
sein, damit die Codegenerierung die Implementierung bereitstellen kann, wenn das Projekt kompiliert wird. Wenn der Typ in einen anderen Typ geschachtelt ist, muss dieser Typ ebenfalls partial
sein.