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:

  1. Öffnen Sie ein vorhandenes .NET MAUI-App-Projekt, oder erstellen Sie ein neues .NET MAUI-App-Projekt.

  2. 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.

  3. 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>
    
  4. 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 Methode InvokeJavaScriptAsync ruft eine angegebene JavaScript-Methode auf, übergibt optional Parameterwerte und gibt eine Zeichenfolge zurück, die den Rückgabewert der 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;

var 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:

var 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 ist asyncResult ein Dictionary<string, string>, das die JSON-Daten aus der Webanfrage 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.