Freigeben über


Tutorial: Senden von Pushbenachrichtigungen an .NET MAUI-Apps mit Azure Notification Hubs über einen Back-End-Dienst

Beispiel durchsuchen.Durchsuchen Sie das Beispiel

Pushbenachrichtigungen übermitteln Informationen von einem Back-End-System an eine Client-App. Apple, Google und andere Plattformen verfügen jeweils über einen eigenen Pushbenachrichtigungsdienst (PNS). Mit Azure Notification Hubs können Sie Benachrichtigungen plattformübergreifend zentralisieren, damit Ihre Back-End-App mit einem einzigen Hub kommunizieren kann, der dann die Verteilung der Benachrichtigungen an die einzelnen PNS übernimmt.

Azure Notification Hubs erfordert, dass Apps sich beim Hub registrieren und optional Vorlagen definieren und/oder Tags abonnieren:

  • Durch Ausführen einer Geräteinstallation wird ein PNS-Handle mit einem Bezeichner in Azure Notification Hubs verknüpft. Weitere Informationen zu Registrierungen finden Sie unter Registrierungsverwaltung.
  • Mit Vorlagen können Geräte parametrisierte Nachrichtenvorlagen angeben. Eingehende Nachrichten können geräteweise angepasst werden. Weitere Informationen finden Sie unter Notification Hubs-Vorlagen.
  • Tags können verwendet werden, um Nachrichtenkategorien zu abonnieren, z. B. Nachrichten, Sport und Wetter. Weitere Informationen finden Sie unter Weiterleitung und Tagausdrücke.

In diesem Tutorial verwenden Sie Azure Notification Hubs, um Pushbenachrichtigungen an eine .NET MAUI-App (.NET Multi-Platform App UI) für Android und iOS zu senden. Ein ASP.NET Core-Web-API-Back-End dient dazu, die Geräteregistrierung für den Client zu verarbeiten und eine Pushbenachrichtigung zu initiieren. Diese Vorgänge werden mithilfe des NuGet-Pakets Microsoft.Azure.NotificationHubs behandelt. Weitere Informationen zum allgemeinen Ansatz finden Sie unter Registrierungsverwaltung über ein Back-End.

In diesem Tutorial:

  • Einrichten von Pushbenachrichtigungsdiensten und Azure Notification Hubs
  • Erstellen einer ASP.NET Core-Web-API-Back-End-App
  • Erstellen Sie eine .NET MAUI-App.
  • Konfigurieren der Android-App für Pushbenachrichtigungen
  • Konfigurieren der iOS-App für Pushbenachrichtigungen
  • Testen der App.
  • Behandeln von Problemen bei der Einrichtung und Konfiguration

Voraussetzungen

Zum Durchführen dieses Tutorials benötigen Sie Folgendes:

  • Ein Azure-Konto mit einem aktiven Abonnement.
  • Einen PC oder Mac, auf dem die neueste Version von Visual Studio/Visual Studio Code ausgeführt wird und die Workload für die .NET Multi-Platform App UI-Entwicklung und die Workloads für ASP.NET- und Webentwicklung installiert sind

Für Android benötigen Sie Folgendes:

  • Ein für die Entwicklung entsperrtes physisches Gerät oder einen Emulator mit API 26 und höher und installierten Google Play Services

Für iOS benötigen Sie Folgendes:

  • Ein aktives Apple Developer-Konto
  • Einen Mac mit Xcode zusammen mit einem gültigen in Ihrer Keychain installierten Entwicklerzertifikat.

Darüber hinaus sollten Sie unter iOS Folgendes haben:

  • Einen Simulator für iOS 16 und höher, der unter macOS 13 und höher auf Mac-Computern mit Apple Silicon- oder T2-Prozessoren ausgeführt wird

    ODER

  • Ein physisches iOS-Gerät, das für Ihr Entwicklerkonto registriert ist (mit iOS 13.0 oder höher)

  • Ihr physisches Gerät, das in Ihrem Apple Developer-Konto registriert ist und Ihrem Zertifikat zugeordnet ist

Wichtig

Der iOS-Simulator unterstützt Remotebenachrichtigungen unter iOS 16 und höher bei der Ausführung auf Mac-Computern mit Apple Silicon- oder T2-Prozessoren unter macOS 13 und höher. Wenn diese Hardwareanforderungen nicht erfüllt sind, benötigen Sie ein aktives Apple Developer-Konto und ein physisches Gerät.

Für dieses Tutorial sollten Sie mit Folgendem vertraut sein:

Dieses Tutorial ist zwar auf Visual Studio ausgerichtet, Sie können es aber auch mit Visual Studio Code auf einem PC oder Mac durchführen. Es gibt jedoch einige Unterschiede, die Anpassungen erfordern. Beispielsweise weichen u. a. die Beschreibungen der Benutzeroberfläche und Workflows, die Vorlagennamen und die Umgebungskonfiguration ab.

Einrichten von Pushbenachrichtigungsdiensten und Azure Notification Hubs

In diesem Abschnitt richten Sie Firebase Cloud Messaging und Apple Push Notification Services (APNS) ein. Anschließend erstellen und konfigurieren Sie eine Instanz von Azure Notification Hubs für die Arbeit mit diesen Diensten.

Erstellen eines Firebase-Projekts

So erstellen Sie ein Firebase-Projekt

  1. Melden Sie sich in einem Webbrowser an der Firebase-Konsole an.

  2. Wählen Sie an der Firebase-Konsole die Schaltfläche Projekt hinzufügen aus, und erstellen Sie ein neues Firebase-Projekt. Geben Sie PushDemo als Projektnamen ein.

    Hinweis

    Es wird ein eindeutiger Name für Sie generiert. Standardmäßig besteht dies aus einer Variante des von Ihnen angegebenen Namens (in Kleinbuchstaben) und einer generierten Zahl, getrennt durch einen Bindestrich. Sie können dies bei Bedarf ändern, sofern Ihre Änderungen weiterhin global eindeutig sind.

  3. Nachdem Ihr Projekt erstellt wurde, wählen Sie das Android-Logo aus, um einer Android-App Firebase hinzuzufügen:

    Screenshot des Hinzufügens von Firebase zu einer Android-App an der Firebase Cloud Messaging-Konsole

  4. Geben Sie auf der Seite Add Firebase to your Android app (Firebase der Android-App hinzufügen) einen Namen für Ihr Paket und optional einen App-Spitznamen ein, und wählen Sie die Schaltfläche Register App (App registrieren) aus:

    Screenshot der Registrierung Ihrer Android-App bei Firebase

  5. Wählen Sie auf der Seite Add Firebase to your Android app (Firebase der Android-App hinzufügen) die Schaltfläche Download „google-services.json“ aus, und speichern Sie die Datei in einem lokalen Ordner, bevor Sie die Schaltfläche Weiter auswählen:

    Screenshot des Herunterladens der JSON-Datei der Google-Dienste

  6. Wählen Sie auf der Seite Add Firebase to your Android app (Firebase der Android-App hinzufügen) die Schaltfläche Weiter aus.

  7. Wählen Sie auf der Seite Add Firebase to your Android app (Firebase der Android-App hinzufügen) die Schaltfläche Continue to the console (An Konsole fortfahren) aus.

  8. Wählen Sie an der Firebase-Konsole das Symbol Project Overview (Projektübersicht) und dann Project settings (Projekteinstellungen) aus:

    Screenshot der Auswahl der Projekteinstellungen an der Firebase Cloud Messaging-Konsole

  9. Wählen Sie in den Project settings (Projekteinstellungen) die Registerkarte Cloud Messaging aus. Sie sehen, dass die Firebase Cloud Messaging-API (V1) aktiviert ist:

    Screenshot der Bestätigung, dass Firebase Cloud Messaging V1 aktiviert ist

  10. Wählen Sie in den Project settings (Projekteinstellungen) die Registerkarte Service accounts (Dienstkonten) und dann die Schaltfläche Generate new private key (Neuen privaten Schlüssel generieren) aus.

  11. Wählen Sie im Dialogfeld Generate new private key (Neuen privaten Schlüssel generieren) die Schaltfläche Generate key (Schlüssel generieren) aus:

    Screenshot des Generierens eines neuen privaten Schlüssels an der Firebase Cloud Messaging-Konsole

    Es wird eine JSON-Datei heruntergeladen, die Werte enthält, die Sie in Ihrer Azure Notification Hubs-Instanz eingeben.

Registrieren der iOS-App für Pushbenachrichtigungen

Zum Senden von Pushbenachrichtigungen an eine iOS-App registrieren Sie Ihre App bei Apple und registrieren auch für Pushbenachrichtigungen. Dazu können Sie die Schritte in der folgenden Dokumentation zu Azure Notification Hubs ausführen:

Wenn Sie Pushbenachrichtigungen auf einem physischen Gerät empfangen möchten, müssen Sie auch ein Bereitstellungsprofil erstellen.

Wichtig

Um Hintergrundbenachrichtigungen unter iOS zu empfangen, müssen Sie der App den Hintergrundmodus für Remotebenachrichtigungen hinzufügen. Weitere Informationen finden Sie unter Enable the remote notifications capability (Aktivieren der Remotebenachrichtigungsfunktion) auf developer.apple.com.

Erstellen einer Azure Notification Hubs-Instanz

So erstellen Sie einen Notification Hub im Azure-Portal

  1. Melden Sie sich in einem Webbrowser beim Azure-Portal an.
  2. Wählen Sie im Azure-Portal die Schaltfläche Ressource erstellen aus, und suchen Sie dann nach Notification Hub. Wählen Sie diese Option und danach die Schaltfläche Erstellen aus.
  3. Führen Sie auf der Seite Notification Hub die folgenden Schritte aus:
    1. Wählen Sie im Feld Abonnement den Namen des Azure-Abonnements aus, das Sie verwenden möchten, und wählen Sie dann eine vorhandene Ressourcengruppe aus, oder erstellen Sie eine neue.

    2. Geben Sie im Feld Namespacedetails einen eindeutigen Namen für den neuen Namespace ein.

    3. Geben Sie im Feld Details zum Notification Hub einen Namen für den Notification Hub ein. Dies ist erforderlich, da ein Namespace mindestens einen Notification Hub enthält.

    4. Wählen Sie in der Dropdownliste Standort einen Wert für den Standort aus, an dem Sie den Notification Hub erstellen möchten.

    5. Überprüfen Sie die Option Verfügbarkeitszonen. Wenn Sie eine Region mit Verfügbarkeitszonen ausgewählt haben, ist das Kontrollkästchen standardmäßig aktiviert.

      Hinweis

      Verfügbarkeitszonen sind ein kostenpflichtige Funktion, sodass Ihrem Tarif eine zusätzliche Gebühr hinzugefügt wird.

    6. Wählen Sie eine Option für die Notfallwiederherstellung aus: keine, gekoppelte Wiederherstellungsregion oder flexible Wiederherstellungsregion. Wenn Sie Gekoppelte Wiederherstellungsregion auswählen, wird die Failoverregion angezeigt. Wenn Sie Flexible Wiederherstellungsregion auswählen, verwenden Sie die Dropdownliste, um aus einer Liste mit Wiederherstellungsregionen auszuwählen.

    7. Wählen Sie die Schaltfläche Erstellen. Der Notification Hub wird erstellt.

  4. Navigieren Sie im Azure-Portal zum neu erstellten Notification Hub, und wechseln Sie dann zum Blatt Verwalten > Zugriffsrichtlinien.
  5. Notieren Sie sich auf dem Blatt Zugriffsrichtlinien die Verbindungszeichenfolge für die Richtlinie DefaultFullSharedAccessSignature. Diese ist später erforderlich, wenn Sie einen Back-End-Dienst erstellen, der mit Ihrem Notification Hub kommuniziert.

Weitere Informationen zum Erstellen eines Notification Hubs finden Sie unter Erstellen einer Azure Notification Hubs-Instanz im Azure-Portal.

Konfigurieren von Firebase Cloud Messaging im Notification Hub

So konfigurieren Sie Ihren Notification Hub für die Kommunikation mit Firebase Cloud Messaging

  1. Navigieren Sie im Azure-Portal zu Ihrem Notification Hub, und wählen Sie das Blatt Einstellungen > Google (FCM v1) aus.

  2. Geben Sie auf dem Blatt Google (FCM v1) Werte für die Felder Privater Schlüssel, Client-E-Mail-Adresse und Projekt-ID ein. Diese Werte finden Sie in der JSON-Datei des privaten Schlüssels, die Sie von Firebase Cloud Messaging heruntergeladen haben:

    Azure-Feld JSON-Schlüssel Beispiel für den JSON-Wert
    Privater Schlüssel private_key Dieser Wert sollte mit -----BEGIN PRIVATE KEY-----\n beginnen und mit -----END PRIVATE KEY-----\n enden.
    Client Email client_email firebase-adminsdk-55sfg@pushdemo-d6ab2.iam.gserviceaccount.com
    Projektkennung project_id pushdemo-d6ab2
  3. Wählen Sie auf dem Blatt Google (FCM v1) die Schaltfläche Speichern aus.

Konfigurieren von Apple Push Notification Service im Notification Hub

Navigieren Sie im Azure-Portal zu Ihrem Notification Hub, und wählen Sie das Blatt Einstellungen > Apple (APNS) aus. Führen Sie dann je nach Ihrer Vorgehensweise, die Sie zuvor beim Erstellen eines Zertifikats für den Notification Hub ausgewählt haben, die entsprechenden Schritte aus.

Wichtig

Wenn Sie den Anwendungsmodus festlegen, wählen Sie nur Produktion aus, wenn Sie Pushbenachrichtigungen an Benutzer senden möchten, die Ihre App im Store erworben haben.

Option 1: Verwenden eines P12-Pushzertifikats

  1. Wählen Sie auf dem Blatt Apple (APNS) den Authentifizierungsmodus Zertifikat aus.
  2. Wählen Sie auf dem Blatt Apple (APNS) das Dateisymbol neben dem Feld Zertifikat hochladen aus. Wählen Sie die zuvor exportierte P12-Datei aus, und laden Sie sie hoch.
  3. Geben Sie auf dem Blatt Apple (APNS) das Zertifikatkennwort bei Bedarf in das Feld Kennwort ein.
  4. Wählen Sie auf dem Blatt Apple (APNS) den Anwendungsmodus Sandbox aus.
  5. Wählen Sie auf dem Blatt Apple (APNS) die Schaltfläche Speichern aus.

Option 2: Verwenden der tokenbasierten Authentifizierung

  1. Wählen Sie auf dem Blatt Apple (APNS) den Authentifizierungsmodus Token aus.
  2. Geben Sie auf dem Blatt Apple (APNS) die Werte ein, die Sie zuvor für die Felder Schlüssel-ID, Bundle-ID, Team-ID und Token abgerufen haben.
  3. Wählen Sie auf dem Blatt Apple (APNS) den Anwendungsmodus Sandbox aus.
  4. Wählen Sie auf dem Blatt Apple (APNS) die Schaltfläche Speichern aus.

Erstellen einer ASP.NET Core-Web-API-Back-End-App

In diesem Abschnitt erstellen Sie ein ASP.NET Core-Web-API-Back-End, um die Geräteinstallation und das Senden von Benachrichtigungen an die .NET MAUI-App zu verarbeiten.

Erstellen eines Web-API-Projekts

So erstellen Sie ein Web-API-Projekt

  1. Erstellen Sie in Visual Studio ein ASP.NET Core-Web-API-Projekt:

    Screenshot der Erstellung eines neuen ASP.NET Core-Web-API-Projekts in Visual Studio

  2. Benennen Sie das Projekt im Dialogfeld Neues Projekt konfigurieren mit PushNotificationsAPI.

  3. Stellen Sie im Dialogfeld Zusätzliche Informationen sicher, dass die Kontrollkästchen Für HTTPS konfigurieren und Controller verwenden aktiviert sind:

    Screenshot der Konfiguration des ASP.NET Core-Web-API-Projekts in Visual Studio

  4. Nachdem das neue Projekt erstellt wurde, drücken Sie F5, um das Projekt auszuführen.

    Die App ist zurzeit so konfiguriert, dass WeatherForecastController als launchUrl verwendet wird, die in der Datei Properties\launchSettings.json festgelegt ist. Die App wird in einem Webbrowser gestartet und zeigt einige JSON-Daten an.

    Wichtig

    Wenn Sie ein ASP.NET Core-Projekt ausführen, das HTTPS verwendet, erkennt Visual Studio, ob das ASP.NET Core-HTTPS-Entwicklungszertifikat in Ihrem lokalen Benutzerzertifikatspeicher installiert ist, und bietet – falls es fehlt – an, es zu installieren und ihm zu vertrauen.

  5. Schließen Sie den Webbrowser.

  6. Erweitern Sie im Projektmappen-Explorer den Ordner Controller, und löschen Sie die Datei WeatherForecastController.cs.

  7. Löschen Sie im Projektmappen-Explorer im Stammverzeichnis des Projekts die Datei WeatherForecast.cs.

  8. Öffnen Sie ein Befehlsfenster, und navigieren Sie zu dem Verzeichnis, das die Projektdatei enthält. Führen Sie dann die folgende Befehle aus:

    dotnet user-secrets init
    dotnet user-secrets set "NotificationHub:Name" <value>
    dotnet user-secrets set "NotificationHub:ConnectionString" "<value>"
    

    Ersetzen Sie die Platzhalterwerte durch den Namen Ihrer Azure Notification Hubs-Instanz und die Werte der Verbindungszeichenfolge. Diese finden Sie an den folgenden Stellen in Ihrer Azure Notification Hubs-Instanz:

    Der Konfigurationswert Location
    NotificationHub:Name Sehen Sie unter Name in der Zusammenfassung Essentials am Anfang der Seite Übersicht nach.
    NotificationHub:ConnectinString Sehen Sie unter DefaultFullSharedAccessSignature* auf der Seite Zugriffsrichtlinien nach.

    Damit richten Sie mit dem Geheimnis-Manager-Tool lokale Konfigurationswerte ein. Dadurch werden Ihre Azure Notification Hubs-Geheimnisse von der Visual Studio-Lösung entkoppelt, um sicherzustellen, dass sie nicht in der Quellcodeverwaltung angezeigt werden.

    Tipp

    Erwägen Sie in Produktionsszenarien die Verwendung eines Diensts wie Azure KeyVault, um die Verbindungszeichenfolge sicher zu speichern.

Authentifizieren von Clients mit einem API-Schlüssel

So authentifizieren Sie Clients mit einem API-Schlüssel

  1. Öffnen Sie ein Befehlsfenster, und navigieren Sie zu dem Verzeichnis, das die Projektdatei enthält. Führen Sie dann die folgende Befehle aus:

    dotnet user-secrets set "Authentication:ApiKey" <value>
    

    Ersetzen Sie den Platzhalterwert durch Ihren API-Schlüssel, der ein beliebiger Wert sein kann.

  2. Fügen Sie Ihrem Projekt in Visual Studio einen neuen Ordner mit dem Namen Authentication und dann eine neue Klasse mit dem Namen ApiKeyAuthOptions im Ordner Authentication hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    using Microsoft.AspNetCore.Authentication;
    
    namespace PushNotificationsAPI.Authentication;
    
    public class ApiKeyAuthOptions : AuthenticationSchemeOptions
    {
        public const string DefaultScheme = "ApiKey";
        public string Scheme => DefaultScheme;
        public string ApiKey { get; set; }
    }
    
  3. Fügen Sie in Visual Studio im Ordner Authentication eine neue Klasse namens ApiKeyAuthHandler hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    using Microsoft.AspNetCore.Authentication;
    using Microsoft.Extensions.Options;
    using System.Security.Claims;
    using System.Text.Encodings.Web;
    
    namespace PushNotificationsAPI.Authentication;
    
    public class ApiKeyAuthHandler : AuthenticationHandler<ApiKeyAuthOptions>
    {
        const string ApiKeyIdentifier = "apikey";
    
        public ApiKeyAuthHandler(
            IOptionsMonitor<ApiKeyAuthOptions> options,
            ILoggerFactory logger,
            UrlEncoder encoder)
            : base(options, logger, encoder)
        {
        }
    
        protected override Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            string key = string.Empty;
    
            if (Request.Headers[ApiKeyIdentifier].Any())
            {
                key = Request.Headers[ApiKeyIdentifier].FirstOrDefault();
            }
            else if (Request.Query.ContainsKey(ApiKeyIdentifier))
            {
                if (Request.Query.TryGetValue(ApiKeyIdentifier, out var queryKey))
                    key = queryKey;
            }
    
            if (string.IsNullOrWhiteSpace(key))
                return Task.FromResult(AuthenticateResult.Fail("No api key provided"));
    
            if (!string.Equals(key, Options.ApiKey, StringComparison.Ordinal))
                return Task.FromResult(AuthenticateResult.Fail("Invalid api key."));
    
            var identities = new List<ClaimsIdentity>
            {
                new ClaimsIdentity("ApiKeyIdentity")
            };
    
            var ticket = new AuthenticationTicket(new ClaimsPrincipal(identities), Options.Scheme);
    
            return Task.FromResult(AuthenticateResult.Success(ticket));
        }
    }
    

    Ein Authentifizierungshandler ist ein Typ, der das Verhalten eines Schemas implementiert – in diesem Fall ein benutzerdefiniertes API-Schlüsselschema.

  4. Fügen Sie in Visual Studio im Ordner Authentication eine neue Klasse namens AuthenticationBuilderExtensions hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    using Microsoft.AspNetCore.Authentication;
    
    namespace PushNotificationsAPI.Authentication;
    
    public static class AuthenticationBuilderExtensions
    {
      public static AuthenticationBuilder AddApiKeyAuth(
          this AuthenticationBuilder builder,
          Action<ApiKeyAuthOptions> configureOptions)
        {
            return builder
                .AddScheme<ApiKeyAuthOptions, ApiKeyAuthHandler>(
                ApiKeyAuthOptions.DefaultScheme,
                configureOptions);
        }
    }
    

    Diese Erweiterungsmethode dient dazu, den Middleware-Konfigurationscode in der Datei Program.cs zu vereinfachen.

  5. Öffnen Sie in Visual Studio die Datei Program.cs, und ändern Sie den Code unter dem Aufruf der builder.Services.AddControllers-Methode, um die Authentifizierung per API-Schlüssel zu konfigurieren:

    using PushNotificationsAPI.Authentication;
    
    builder.Services.AddControllers();
    
    builder.Services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = ApiKeyAuthOptions.DefaultScheme;
        options.DefaultChallengeScheme = ApiKeyAuthOptions.DefaultScheme;
    }).AddApiKeyAuth(builder.Configuration.GetSection("Authentication").Bind);
    
  6. Aktualisieren Sie in der Datei Program.cs den Code unterhalb des Kommentars // Configure the HTTP request pipeline, um die Erweiterungsmethoden UseRouting, UseAuthentication und MapControllers aufzurufen:

    // Configure the HTTP request pipeline.
    
    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.MapControllers();
    
    app.Run();
    

    Die UseAuthentication-Erweiterungsmethode registriert die Middleware, die das zuvor registrierte Authentifizierungsschema verwendet. UseAuthentication muss vor jeglicher anderen Middleware aufgerufen werden, die von der Authentifizierung der Benutzer abhängig ist.

    Hinweis

    Ein API-Schlüssel ist zwar nicht so sicher wie ein Token, aber er reicht für dieses Tutorial aus und kann einfach über die ASP.NET-Middleware konfiguriert werden.

Hinzufügen und Konfigurieren von Diensten

So fügen Sie Dienste in Ihrer Web-API-Back-End-App hinzu und konfigurieren sie

  1. Fügen Sie in Visual Studio Ihrem Projekt das NuGet-Paket Microsoft.Azure.NotificationHubs hinzu. Dieses NuGet-Paket wird verwendet, um auf Ihren Notification Hub zuzugreifen, der in einem Dienst gekapselt ist.

  2. Fügen Sie Ihrem Projekt in Visual Studio einen neuen Ordner mit dem Namen Models und dann eine neue Klasse mit dem Namen PushTemplates im Ordner Models hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    namespace PushNotificationsAPI.Models;
    
    public class PushTemplates
    {
        public class Generic
        {
            public const string Android = "{ \"message\" : { \"notification\" : { \"title\" : \"PushDemo\", \"body\" : \"$(alertMessage)\"}, \"data\" : { \"action\" : \"$(alertAction)\" } } }";
            public const string iOS = "{ \"aps\" : {\"alert\" : \"$(alertMessage)\"}, \"action\" : \"$(alertAction)\" }";
        }
    
        public class Silent
        {
            public const string Android = "{ \"message\" : { \"data\" : {\"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\"} } }";
            public const string iOS = "{ \"aps\" : {\"content-available\" : 1, \"apns-priority\": 5, \"sound\" : \"\", \"badge\" : 0}, \"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\" }";
        }
    }
    

    Die PushTemplates-Klasse enthält tokenisierte Benachrichtigungsnutzdaten für generische und lautlose Pushbenachrichtigungen. Diese Nutzdaten werden außerhalb der Installation definiert, um Experimente zuzulassen, ohne vorhandene Installationen über den Dienst aktualisieren zu müssen. Die Verarbeitung von Änderungen an Installationen auf diese Weise ist nicht Gegenstand dieses Artikels. Ziehen Sie in Produktszenarien die Verwendung von benutzerdefinierten Vorlagen in Betracht.

  3. Fügen Sie in Visual Studio im Ordner Models eine neue Klasse namens DeviceInstallation hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    using System.ComponentModel.DataAnnotations;
    
    namespace PushNotificationsAPI.Models;
    
    public class DeviceInstallation
    {
        [Required]
        public string InstallationId { get; set; }
    
        [Required]
        public string Platform { get; set; }
    
        [Required]
        public string PushChannel { get; set; }
    
        public IList<string> Tags { get; set; } = Array.Empty<string>();
    }
    
  4. Fügen Sie in Visual Studio im Ordner Models eine neue Klasse namens NotificationRequest hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    namespace PushNotificationsAPI.Models;
    
    public class NotificationRequest
    {
        public string Text { get; set; }
        public string Action { get; set; }
        public string[] Tags { get; set; } = Array.Empty<string>();
        public bool Silent { get; set; }
    }
    
  5. Fügen Sie in Visual Studio im Ordner Models eine neue Klasse namens NotificationHubOptions hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    using System.ComponentModel.DataAnnotations;
    
    namespace PushNotificationsAPI.Models;
    
    public class NotificationHubOptions
    {
        [Required]
        public string Name { get; set; }
    
        [Required]
        public string ConnectionString { get; set; }
    }
    
  6. Fügen Sie Ihrem Projekt in Visual Studio einen neuen Ordner mit dem Namen Services und dann eine neue Schnittstelle mit dem Namen INotificationService im Ordner Services hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    using PushNotificationsAPI.Models;
    
    namespace PushNotificationsAPI.Services;
    
    public interface INotificationService
    {
        Task<bool> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation, CancellationToken token);
        Task<bool> DeleteInstallationByIdAsync(string installationId, CancellationToken token);
        Task<bool> RequestNotificationAsync(NotificationRequest notificationRequest, CancellationToken token);
    }
    
  7. Fügen Sie in Visual Studio im Ordner Services eine neue Klasse namens NotificationHubService hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    using Microsoft.Extensions.Options;
    using Microsoft.Azure.NotificationHubs;
    using PushNotificationsAPI.Models;
    
    namespace PushNotificationsAPI.Services;
    
    public class NotificationHubService : INotificationService
    {
        readonly NotificationHubClient _hub;
        readonly Dictionary<string, NotificationPlatform> _installationPlatform;
        readonly ILogger<NotificationHubService> _logger;
    
        public NotificationHubService(IOptions<NotificationHubOptions> options, ILogger<NotificationHubService> logger)
        {
            _logger = logger;
            _hub = NotificationHubClient.CreateClientFromConnectionString(options.Value.ConnectionString, options.Value.Name);
    
            _installationPlatform = new Dictionary<string, NotificationPlatform>
            {
                { nameof(NotificationPlatform.Apns).ToLower(), NotificationPlatform.Apns },
                { nameof(NotificationPlatform.FcmV1).ToLower(), NotificationPlatform.FcmV1 }
            };
        }
    
        public async Task<bool> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation, CancellationToken token)
        {
            if (string.IsNullOrWhiteSpace(deviceInstallation?.InstallationId) ||
                string.IsNullOrWhiteSpace(deviceInstallation?.Platform) ||
                string.IsNullOrWhiteSpace(deviceInstallation?.PushChannel))
                return false;
    
            var installation = new Installation()
            {
                InstallationId = deviceInstallation.InstallationId,
                PushChannel = deviceInstallation.PushChannel,
                Tags = deviceInstallation.Tags
            };
    
            if (_installationPlatform.TryGetValue(deviceInstallation.Platform, out var platform))
                installation.Platform = platform;
            else
                return false;
    
            try
            {
                await _hub.CreateOrUpdateInstallationAsync(installation, token);
            }
            catch
            {
                return false;
            }
    
            return true;
        }
    
        public async Task<bool> DeleteInstallationByIdAsync(string installationId, CancellationToken token)
        {
            if (string.IsNullOrWhiteSpace(installationId))
                return false;
    
            try
            {
                await _hub.DeleteInstallationAsync(installationId, token);
            }
            catch
            {
                return false;
            }
    
            return true;
        }
    
        public async Task<bool> RequestNotificationAsync(NotificationRequest notificationRequest, CancellationToken token)
        {
            if ((notificationRequest.Silent &&
                string.IsNullOrWhiteSpace(notificationRequest?.Action)) ||
                (!notificationRequest.Silent &&
                (string.IsNullOrWhiteSpace(notificationRequest?.Text)) ||
                string.IsNullOrWhiteSpace(notificationRequest?.Action)))
                return false;
    
            var androidPushTemplate = notificationRequest.Silent ?
                PushTemplates.Silent.Android :
                PushTemplates.Generic.Android;
    
            var iOSPushTemplate = notificationRequest.Silent ?
                PushTemplates.Silent.iOS :
                PushTemplates.Generic.iOS;
    
            var androidPayload = PrepareNotificationPayload(
                androidPushTemplate,
                notificationRequest.Text,
                notificationRequest.Action);
    
            var iOSPayload = PrepareNotificationPayload(
                iOSPushTemplate,
                notificationRequest.Text,
                notificationRequest.Action);
    
            try
            {
                if (notificationRequest.Tags.Length == 0)
                {
                    // This will broadcast to all users registered in the notification hub
                    await SendPlatformNotificationsAsync(androidPayload, iOSPayload, token);
                }
                else if (notificationRequest.Tags.Length <= 20)
                {
                    await SendPlatformNotificationsAsync(androidPayload, iOSPayload, notificationRequest.Tags, token);
                }
                else
                {
                    var notificationTasks = notificationRequest.Tags
                        .Select((value, index) => (value, index))
                        .GroupBy(g => g.index / 20, i => i.value)
                        .Select(tags => SendPlatformNotificationsAsync(androidPayload, iOSPayload, tags, token));
    
                    await Task.WhenAll(notificationTasks);
                }
    
                return true;
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Unexpected error sending notification");
                return false;
            }
        }
    
        string PrepareNotificationPayload(string template, string text, string action) => template
            .Replace("$(alertMessage)", text, StringComparison.InvariantCulture)
            .Replace("$(alertAction)", action, StringComparison.InvariantCulture);
    
        Task SendPlatformNotificationsAsync(string androidPayload, string iOSPayload, CancellationToken token)
        {
            var sendTasks = new Task[]
            {
                _hub.SendFcmV1NativeNotificationAsync(androidPayload, token),
                _hub.SendAppleNativeNotificationAsync(iOSPayload, token)
            };
    
            return Task.WhenAll(sendTasks);
        }
    
        Task SendPlatformNotificationsAsync(string androidPayload, string iOSPayload, IEnumerable<string> tags, CancellationToken token)
        {
            var sendTasks = new Task[]
            {
                _hub.SendFcmV1NativeNotificationAsync(androidPayload, tags, token),
                _hub.SendAppleNativeNotificationAsync(iOSPayload, tags, token)
            };
    
            return Task.WhenAll(sendTasks);
        }
    }
    

    Der für die SendTemplateNotificationsAsync-Methode bereitgestellte Tagausdruck ist auf 20 Tags beschränkt, wenn sie nur ODER-Operatoren enthalten. Andernfalls ist er auf 6 Tags beschränkt. Weitere Informationen finden Sie unter Weiterleitung und Tagausdrücke.

  8. Öffnen Sie in Visual Studio die Datei Program.cs, und ändern Sie den Code unter dem Aufruf der builder.Services.AddAuthentication-Methode, um NotificationHubService als Singletonimplementierung von INotificationService hinzuzufügen:

    using PushNotificationsAPI.Authentication;
    using PushNotificationsAPI.Services;
    using PushNotificationsAPI.Models;
    
    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    
    builder.Services.AddControllers();
    
    builder.Services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = ApiKeyAuthOptions.DefaultScheme;
        options.DefaultChallengeScheme = ApiKeyAuthOptions.DefaultScheme;
    }).AddApiKeyAuth(builder.Configuration.GetSection("Authentication").Bind);
    
    builder.Services.AddSingleton<INotificationService, NotificationHubService>();
    builder.Services.AddOptions<NotificationHubOptions>()
        .Configure(builder.Configuration.GetSection("NotificationHub").Bind)
        .ValidateDataAnnotations();
    
    var app = builder.Build();
    

Erstellen der Benachrichtigungen-REST-API

So erstellen Sie die Benachrichtigungen-REST-API

  1. Fügen Sie in Visual Studio dem Ordner Controller einen neuen Controller mit dem Namen NotificationsController hinzu.

    Tipp

    Wählen Sie die Vorlage für API-Controller mit Lese-/Schreibaktionen aus.

  2. Fügen Sie in der Datei NotificationsController.cs die folgenden using-Anweisungen am Anfang der Datei ein:

    using System.ComponentModel.DataAnnotations;
    using System.Net;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using PushNotificationsAPI.Models;
    using PushNotificationsAPI.Services;
    
  3. Fügen Sie in der Datei NotificationsController.cs das Authorize-Attribut der NotificationsController-Klasse hinzu:

    [Authorize]
    [ApiController]
    [Route("api/[controller]")]
    public class NotificationsController : ControllerBase
    
  4. Ändern Sie in der Datei NotificationsController.cs den NotificationsContoller-Konstruktor so, dass er die registrierte Instanz von INotificationService als Argument akzeptiert, und weisen Sie ihn einem schreibgeschützten Member zu:

    readonly INotificationService _notificationService;
    
    public NotificationsController(INotificationService notificationService)
    {
        _notificationService = notificationService;
    }
    
  5. Ersetzen Sie in der Datei NotificationsContoller.cs alle Methoden durch den folgenden Code:

    [HttpPut]
    [Route("installations")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)]
    public async Task<IActionResult> UpdateInstallation(
        [Required] DeviceInstallation deviceInstallation)
    {
        var success = await _notificationService
            .CreateOrUpdateInstallationAsync(deviceInstallation, HttpContext.RequestAborted);
    
        if (!success)
            return new UnprocessableEntityResult();
    
        return new OkResult();
    }
    
    [HttpDelete()]
    [Route("installations/{installationId}")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)]
    public async Task<ActionResult> DeleteInstallation(
        [Required][FromRoute] string installationId)
    {
        // Probably want to ensure deletion even if the connection is broken
        var success = await _notificationService
            .DeleteInstallationByIdAsync(installationId, CancellationToken.None);
    
        if (!success)
            return new UnprocessableEntityResult();
    
        return new OkResult();
    }
    
    [HttpPost]
    [Route("requests")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)]
    public async Task<IActionResult> RequestPush(
        [Required] NotificationRequest notificationRequest)
    {
        if ((notificationRequest.Silent &&
            string.IsNullOrWhiteSpace(notificationRequest?.Action)) ||
            (!notificationRequest.Silent &&
            string.IsNullOrWhiteSpace(notificationRequest?.Text)))
            return new BadRequestResult();
    
        var success = await _notificationService
            .RequestNotificationAsync(notificationRequest, HttpContext.RequestAborted);
    
        if (!success)
            return new UnprocessableEntityResult();
    
        return new OkResult();
    }
    
  6. Ändern Sie in der Datei Properties/launchSettings.json die launchUrl-Eigenschaft für jedes Profil von weatherforecast in api/notifications.

Erstellen einer API-App

Sie erstellen nun eine API-App in Azure App Service, um Ihren Back-End-Dienst zu hosten. Dies kann direkt in Visual Studio oder Visual Studio Code, mithilfe der Azure-Befehlszeilenschnittstelle, mit Azure PowerShell, der Azure Developer CLI und über das Azure-Portal erfolgen. Weitere Informationen finden Sie unter Veröffentlichen Ihrer Web-App.

So erstellen Sie eine API-App im Azure-Portal

  1. Melden Sie sich in einem Webbrowser beim Azure-Portal an.

  2. Wählen Sie im Azure-Portal die Schaltfläche Ressource erstellen aus, und suchen Sie dann nach API-App. Wählen Sie diese Option und danach die Schaltfläche Erstellen aus.

  3. Ändern Sie auf der Seite API-App erstellen die folgenden Felder, bevor Sie die Schaltfläche Erstellen auswählen:

    Feld Aktion
    Abonnement Wählen Sie dasselbe Zielabonnement aus, in dem Sie den Notification Hub erstellt haben.
    Ressourcengruppe Wählen Sie dieselbe Ressourcengruppe aus, in der Sie den Notification Hub erstellt haben.
    Name Geben Sie einen global eindeutigen Namen ein.
    Runtimestapel Vergewissern Sie sich, dass die neueste Version von .NET ausgewählt ist.
  4. Nachdem die API-App bereitgestellt wurde, navigieren Sie zu der Ressource.

  5. Notieren Sie sich auf der Seite Übersicht den Standarddomänenwert. Diese URL ist Ihr Back-End-Endpunkt, der von Ihrer .NET MAUI-App genutzt wird. Die URL verwendet den von Ihnen angegebenen API-App-Namen im Format https://<app_name>.azurewebsites.net.

  6. Navigieren Sie im Azure-Portal zum Blatt Einstellungen > Umgebungsvariablen, und vergewissern Sie sich, dass die Registerkarte App-Einstellungen ausgewählt ist. Verwenden Sie dann die Schaltfläche Hinzufügen, um die folgenden Einstellungen hinzuzufügen:

    Name Wert
    Authentication:ApiKey <api_key_value>
    NotificationHub:Name <hub_name_value>
    NotificationHub:ConnectionString <hub_connection_string_value>

    Wichtig

    Die Anwendungseinstellung Authentication:ApiKey wurde der Einfachheit halber hinzugefügt. Erwägen Sie in Produktionsszenarien die Verwendung eines Diensts wie Azure KeyVault, um die Verbindungszeichenfolge sicher zu speichern.

    Nachdem alle diese Einstellungen eingegeben wurden, wählen Sie die Schaltfläche Übernehmen und dann die Schaltfläche Bestätigen aus.

Veröffentlichen des Back-End-Diensts

So veröffentlichen Sie Ihren Back-End-Dienst in Azure App Service

  1. Klicken Sie in Visual Studio mit der rechten Maustaste auf Ihre Projekt, und wählen Sie Veröffentlichen aus.
  2. Wählen Sie im Veröffentlichungs-Assistenten zuerst Azure und dann die Schaltfläche Weiter aus.
  3. Wählen Sie im Veröffentlichungs-Assistenten zuerst Azure App Service (Windows) und dann die Schaltfläche Weiter aus.
  4. Folgen Sie im Veröffentlichungs-Assistenten dem Authentifizierungsflow, um Visual Studio mit Ihrem Azure-Abonnement zu verbinden und die App zu veröffentlichen.

Visual Studio erstellt, packt und veröffentlicht die App in Azure und startet sie anschließend in Ihrem Standardbrowser. Weitere Informationen finden Sie unter Veröffentlichen von ASP.NET-Web-Apps.

Tipp

Sie können ein Veröffentlichungsprofil für Ihre App über das Blatt Übersicht Ihrer API-App im Azure-Portal herunterladen und dann das Profil in Visual Studio verwenden, um Ihre App zu veröffentlichen.

Überprüfen der veröffentlichten API

Um zu überprüfen, ob die API-App ordnungsgemäß veröffentlicht wurde, sollten Sie REST-Tools Ihrer Wahl verwenden, um eine POST-Anforderung an die folgende Adresse zu senden:

https://<app_name>.azurewebsites.net/api/notifications/requests

Hinweis

Die Basisadresse lautet https://<app_name>.azurewebsites.net.

Stellen Sie sicher, dass Sie die Anforderungsheader so konfigurieren, dass der Schlüssel apikey mit seinem Wert enthalten ist, legen Sie den Textkörper auf unformatiert fest, und verwenden Sie den folgenden JSON-Platzhalterinhalt:

{}

Sie sollten vom Dienst eine 400 Bad Request-Antwort erhalten.

Hinweis

Es ist noch nicht möglich, die API mit gültigen Anforderungsdaten zu testen, da hierfür plattformspezifische Informationen von der .NET MAUI-App erforderlich sind.

Weitere Informationen zum Aufrufen von REST-APIs finden Sie unter Verwenden von HTTP-Dateien in Visual Studio und Testen von Web-APIs mit HTTP REPL. In Visual Studio Code kann der REST-Client zum Testen von REST-APIs verwendet werden.

Erstellen einer .NET MAUI-App

In diesem Abschnitt erstellen Sie eine .NET MAUI-App (.NET Multi-Platform App UI), mit der Sie sich registrieren können, um Pushbenachrichtigungen von einem Notification Hub über den Back-End-Dienst zu empfangen und die Registrierung zu deaktivieren.

So erstellen Sie Ihre .NET MAUI-App

  1. Erstellen Sie in Visual Studio eine neue .NET MAUI-App mit dem Namen PushNotificationsDemo auf Grundlage der Projektvorlage .NET MAUI-App.

  2. Fügen Sie dem .NET MAUI-Projekt in Visual Studio einen neuen Ordner mit dem Namen Models und dann eine neue Klasse mit dem Namen DeviceInstallation im Ordner Models hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    using System.Text.Json.Serialization;
    
    namespace PushNotificationsDemo.Models;
    
    public class DeviceInstallation
    {
        [JsonPropertyName("installationId")]
        public string InstallationId { get; set; }
    
        [JsonPropertyName("platform")]
        public string Platform { get; set; }
    
        [JsonPropertyName("pushChannel")]
        public string PushChannel { get; set; }
    
        [JsonPropertyName("tags")]
        public List<string> Tags { get; set; } = new List<string>();
    }
    
  3. Fügen Sie in Visual Studio im Ordner Models eine Enumeration namens PushDemoAction hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    namespace PushNotificationsDemo.Models;
    
    public enum PushDemoAction
    {
        ActionA,
        ActionB
    }
    
  4. Fügen Sie dem .NET MAUI-Projekt in Visual Studio einen neuen Ordner mit dem Namen Services und dann eine neue Schnittstelle mit dem Namen IDeviceInstallationService im Ordner Services hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    using PushNotificationsDemo.Models;
    
    namespace PushNotificationsDemo.Services;
    
    public interface IDeviceInstallationService
    {
        string Token { get; set; }
        bool NotificationsSupported { get; }
        string GetDeviceId();
        DeviceInstallation GetDeviceInstallation(params string[] tags);
    }
    

    Diese Schnittstelle wird später auf jeder Plattform implementiert, um die vom Back-End-Dienst benötigten DeviceInstallation-Informationen bereitzustellen.

  5. Fügen Sie in Visual Studio im Ordner Services eine Schnittstelle namens INotificationRegistrationService hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    namespace PushNotificationsDemo.Services;
    
    public interface INotificationRegistrationService
    {
        Task DeregisterDeviceAsync();
        Task RegisterDeviceAsync(params string[] tags);
        Task RefreshRegistrationAsync();
    }
    

    Diese Schnittstelle behandelt die Interaktion zwischen dem Client und dem Back-End-Dienst.

  6. Fügen Sie in Visual Studio im Ordner Services eine Schnittstelle namens INotificationActionService hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    namespace PushNotificationsDemo.Services;
    
    public interface INotificationActionService
    {
        void TriggerAction(string action);
    }
    

    Diese Schnittstelle dient dazu, die Behandlung von Benachrichtigungsaktionen zu zentralisieren.

  7. Fügen Sie in Visual Studio im Ordner Services eine Schnittstelle namens IPushDemoNotificationActionService hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    using PushNotificationsDemo.Models;
    
    namespace PushNotificationsDemo.Services;
    
    public interface IPushDemoNotificationActionService : INotificationActionService
    {
        event EventHandler<PushDemoAction> ActionTriggered;
    }
    

    Der Typ IPushDemoNotificationActionService ist spezifisch für diese App und verwendet die PushDemoAction-Enumeration, um die Aktion zu identifizieren, die mit einem streng typisierten Ansatz ausgelöst wird.

  8. Fügen Sie in Visual Studio im Ordner Services eine Klasse namens NotificationRegistrationService hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    using System.Text;
    using System.Text.Json;
    using PushNotificationsDemo.Models;
    
    namespace PushNotificationsDemo.Services;
    
    public class NotificationRegistrationService : INotificationRegistrationService
    {
        const string RequestUrl = "api/notifications/installations";
        const string CachedDeviceTokenKey = "cached_device_token";
        const string CachedTagsKey = "cached_tags";
    
        string _baseApiUrl;
        HttpClient _client;
        IDeviceInstallationService _deviceInstallationService;
    
        IDeviceInstallationService DeviceInstallationService =>
            _deviceInstallationService ?? (_deviceInstallationService = Application.Current.Windows[0].Page.Handler.MauiContext.Services.GetService<IDeviceInstallationService>());
    
        public NotificationRegistrationService(string baseApiUri, string apiKey)
        {
            _client = new HttpClient();
            _client.DefaultRequestHeaders.Add("Accept", "application/json");
            _client.DefaultRequestHeaders.Add("apikey", apiKey);
    
            _baseApiUrl = baseApiUri;
        }
    
        public async Task DeregisterDeviceAsync()
        {
            var cachedToken = await SecureStorage.GetAsync(CachedDeviceTokenKey)
                .ConfigureAwait(false);
    
            if (cachedToken == null)
                return;
    
            var deviceId = DeviceInstallationService?.GetDeviceId();
    
            if (string.IsNullOrWhiteSpace(deviceId))
                throw new Exception("Unable to resolve an ID for the device.");
    
            await SendAsync(HttpMethod.Delete, $"{RequestUrl}/{deviceId}")
                .ConfigureAwait(false);
    
            SecureStorage.Remove(CachedDeviceTokenKey);
            SecureStorage.Remove(CachedTagsKey);
        }
    
        public async Task RegisterDeviceAsync(params string[] tags)
        {
            var deviceInstallation = DeviceInstallationService?.GetDeviceInstallation(tags);
    
            await SendAsync<DeviceInstallation>(HttpMethod.Put, RequestUrl, deviceInstallation)
                .ConfigureAwait(false);
    
            await SecureStorage.SetAsync(CachedDeviceTokenKey, deviceInstallation.PushChannel)
                .ConfigureAwait(false);
    
            await SecureStorage.SetAsync(CachedTagsKey, JsonSerializer.Serialize(tags));
        }
    
        public async Task RefreshRegistrationAsync()
        {
            var cachedToken = await SecureStorage.GetAsync(CachedDeviceTokenKey)
                .ConfigureAwait(false);
    
            var serializedTags = await SecureStorage.GetAsync(CachedTagsKey)
                .ConfigureAwait(false);
    
            if (string.IsNullOrWhiteSpace(cachedToken) ||
                string.IsNullOrWhiteSpace(serializedTags) ||
                string.IsNullOrWhiteSpace(_deviceInstallationService.Token) ||
                cachedToken == DeviceInstallationService.Token)
                return;
    
            var tags = JsonSerializer.Deserialize<string[]>(serializedTags);
    
            await RegisterDeviceAsync(tags);
        }
    
        async Task SendAsync<T>(HttpMethod requestType, string requestUri, T obj)
        {
            string serializedContent = null;
    
            await Task.Run(() => serializedContent = JsonSerializer.Serialize(obj))
                .ConfigureAwait(false);
    
            await SendAsync(requestType, requestUri, serializedContent);
        }
    
        async Task SendAsync(HttpMethod requestType, string requestUri, string jsonRequest = null)
        {
            var request = new HttpRequestMessage(requestType, new Uri($"{_baseApiUrl}{requestUri}"));
    
            if (jsonRequest != null)
                request.Content = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
    
            var response = await _client.SendAsync(request).ConfigureAwait(false);
    
            response.EnsureSuccessStatusCode();
        }
    }
    
  9. Fügen Sie in Visual Studio im Ordner Services eine Klasse namens PushDemoNotificationActionService hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    using PushNotificationsDemo.Models;
    
    namespace PushNotificationsDemo.Services;
    
    public class PushDemoNotificationActionService : IPushDemoNotificationActionService
    {
        readonly Dictionary<string, PushDemoAction> _actionMappings = new Dictionary<string, PushDemoAction>
        {
            { "action_a", PushDemoAction.ActionA },
            { "action_b", PushDemoAction.ActionB }
        };
    
        public event EventHandler<PushDemoAction> ActionTriggered = delegate { };
    
        public void TriggerAction(string action)
        {
            if (!_actionMappings.TryGetValue(action, out var pushDemoAction))
                return;
    
            List<Exception> exceptions = new List<Exception>();
    
            foreach (var handler in ActionTriggered?.GetInvocationList())
            {
                try
                {
                    handler.DynamicInvoke(this, pushDemoAction);
                }
                catch (Exception ex)
                {
                    exceptions.Add(ex);
                }
            }
    
            if (exceptions.Any())
                throw new AggregateException(exceptions);
        }
    }
    
  10. Fügen Sie in Visual Studio im Stammverzeichnis des Projekts eine Klasse namens Config hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    namespace PushNotificationsDemo;
    
    public static partial class Config
    {
        public static string ApiKey = "API_KEY";
        public static string BackendServiceEndpoint = "BACKEND_SERVICE_ENDPOINT";
    }
    

    Die Config-Klasse wird als einfache Methode verwendet, um Ihre Geheimnisse aus der Quellcodeverwaltung herauszuhalten. Sie können diese Werte als Teil eines automatisierten Builds ersetzen oder durch eine lokale Teilklasse überschreiben.

    Wichtig

    Wenn Sie die Basisadresse in der .NET MAUI-App angeben, stellen Sie sicher, dass sie mit einem / endet.

  11. Fügen Sie in Visual Studio im Stammverzeichnis des Projekts eine Klasse namens Config.local_secrets hinzu. Ersetzen Sie dann den Code in der Datei Config.local_secrets.cs durch den folgenden Code:

    namespace PushNotificationsDemo;
    
    public static partial class Config
    {
        static Config()
        {
            ApiKey = "<your_api_key>";
            BackendServiceEndpoint = "<your_api_app_url>";
        }
    }
    

    Ersetzen Sie die Platzhalterwerte durch die Werte, die Sie beim Erstellen des Back-End-Diensts ausgewählt haben. Die BackendServiceEndpoint-URL sollte das Format https://<api_app_name>.azurewebsites.net/ aufweisen.

    Tipp

    Denken Sie daran, *.local_secrets.* Ihrer Datei .gitignore hinzuzufügen, um zu vermeiden, dass diese Datei in die Quellcodeverwaltung aufgenommen wird.

Erstellen der Benutzeroberfläche

So erstellen Sie die App-Benutzeroberfläche

  1. Öffnen Sie in Visual Studio die Datei MainPage.xaml, und ersetzen Sie VerticalStackLayout und die untergeordneten Elemente durch folgenden XAML-Code:

    <VerticalStackLayout Margin="20"
                         Spacing="6">
        <Button x:Name="registerButton"
                Text="Register"
                Clicked="OnRegisterButtonClicked" />
        <Button x:Name="deregisterButton"
                Text="Deregister"
                Clicked="OnDeregisterButtonClicked" />
    </VerticalStackLayout>
    
  2. Öffnen Sie in Visual Studio die Datei MainPage.xaml.cs, und fügen Sie eine using-Anweisung für den PushNotificationsDemo.Services-Namespace hinzu:

    using PushNotificationsDemo.Services;
    
  3. Fügen Sie in der Datei MainPage.xaml.cs ein readonly-Unterstützungsfeld hinzu, um einen Verweis auf die INotificationRegistrationService-Implementierung zu speichern:

    readonly INotificationRegistrationService _notificationRegistrationService;
    
  4. Lösen Sie im MainPage-Konstruktor die INotificationRegistrationService-Implementierung auf, und weisen Sie sie dem _notificationRegistrationService-Unterstützungsfeld zu:

    public MainPage(INotificationRegistrationService service)
    {
        InitializeComponent();
    
        _notificationRegistrationService = service;
    }
    
  5. Implementieren Sie in der MainPage-Klasse die Ereignishandler OnRegisterButtonClicked und OnDeregisterButtonClicked, und rufen Sie die entsprechenden Methoden zum Registrieren und Aufheben der Registrierung für das INotificationRegistrationService-Objekt auf:

    void OnRegisterButtonClicked(object sender, EventArgs e)
    {
        _notificationRegistrationService.RegisterDeviceAsync()
            .ContinueWith((task) =>
            {
                ShowAlert(task.IsFaulted ? task.Exception.Message : $"Device registered");
            });
    }
    
    void OnDeregisterButtonClicked(object sender, EventArgs e)
    {
        _notificationRegistrationService.DeregisterDeviceAsync()
            .ContinueWith((task) =>
            {
                ShowAlert(task.IsFaulted ? task.Exception.Message : $"Device deregistered");
            });
    }
    
    void ShowAlert(string message)
    {
        MainThread.BeginInvokeOnMainThread(() =>
        {
            DisplayAlert("Push notifications demo", message, "OK")
                .ContinueWith((task) =>
                {
                    if (task.IsFaulted)
                        throw task.Exception;
                });
        });
    }
    

    Wichtig

    In der App erfolgt die Registrierung und Aufhebung der Registrierung als Reaktion auf Benutzereingaben, damit diese Funktionalität einfacher untersucht und getestet werden kann. In einer Produktions-App führen Sie die Aktionen zum Registrieren und Aufheben der Registrierung in der Regel zum entsprechenden Zeitpunkt im App-Lebenszyklus aus, ohne dass explizite Benutzereingaben erforderlich sind.

  6. Öffnen Sie in Visual Studio die Datei App.xaml.cs, und fügen Sie die folgenden using-Anweisungen hinzu:

    using PushNotificationsDemo.Models;
    using PushNotificationsDemo.Services;
    
  7. Fügen Sie in der Datei App.xaml.cs ein readonly-Unterstützungsfeld hinzu, um einen Verweis auf die IPushDemoNotificationActionService-Implementierung zu speichern:

    readonly IPushDemoNotificationActionService _actionService;
    
  1. Lösen Sie im App-Konstruktor die IPushDemoNotificationActionService-Implementierung auf, weisen Sie sie dem _actionService-Unterstützungsfeld zu, und abonnieren Sie das IPushDemoNotificationActionService.ActionTriggered-Ereignis:

    public App(IPushDemoNotificationActionService service)
    {
        InitializeComponent();
    
        _actionService = service;
        _actionService.ActionTriggered += NotificationActionTriggered;
    
        MainPage = new AppShell();
    }
    
  1. Lösen Sie im App-Konstruktor die IPushDemoNotificationActionService-Implementierung auf, weisen Sie sie dem _actionService-Unterstützungsfeld zu, und abonnieren Sie das IPushDemoNotificationActionService.ActionTriggered-Ereignis:

    public App(IPushDemoNotificationActionService service)
    {
        InitializeComponent();
    
        _actionService = service;
        _actionService.ActionTriggered += NotificationActionTriggered;
    }
    
  1. Implementieren Sie in der App-Klasse den Ereignishandler für das IPushDemoNotificationActionService.ActionTriggered-Ereignis:

    void NotificationActionTriggered(object sender, PushDemoAction e)
    {
        ShowActionAlert(e);
    }
    
    void ShowActionAlert(PushDemoAction action)
    {
        MainThread.BeginInvokeOnMainThread(() =>
        {
            Windows[0].Page?.DisplayAlert("Push notifications demo", $"{action} action received.", "OK")
                .ContinueWith((task) =>
                {
                    if (task.IsFaulted)
                        throw task.Exception;
                });
        });
    }
    

    Der Ereignishandler für das ActionTriggered-Ereignis veranschaulicht den Empfang und die Verteilung von Pushbenachrichtigungsaktionen. Diese werden in der Regel im Hintergrund behandelt, z. B. wenn Sie zu einer bestimmten Ansicht navigieren oder einige Daten aktualisieren, anstatt eine Warnung anzuzeigen.

Konfigurieren der Android-App

So konfigurieren Sie Ihre .NET MAUI-App unter Android zum Empfangen und Verarbeiten von Pushbenachrichtigungen

  1. Fügen Sie in Visual Studio Ihrem .NET MAUI-App-Projekt das NuGet-Paket Xamarin.Firebase.Messaging hinzu.

  2. Fügen Sie in Visual Studio Ihre Datei google-services.json im Ordner Platforms/Android Ihres .NET MAUI-App-Projekts hinzu. Nachdem die Datei Ihrem Projekt hinzugefügt wurde, sollte sie mit einer Buildaktion GoogleServicesJson hinzugefügt worden sein:

    <ItemGroup Condition="'$(TargetFramework)' == 'net8.0-android'">
      <GoogleServicesJson Include="Platforms\Android\google-services.json" />
    </ItemGroup>
    

    Tipp

    Denken Sie daran, google-services.json Ihrer Datei .gitignore hinzuzufügen, um zu vermeiden, dass diese Datei in die Quellcodeverwaltung aufgenommen wird.

  3. Bearbeiten Sie in Visual Studio die Projektdatei (*.csproj), und legen Sie SupportedOSPlatformVersion für Android auf 26.0 fest:

    <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">26.0</SupportedOSPlatformVersion>
    

    Google hat Änderungen an Android-Benachrichtigungskanälen in API 26 vorgenommen. Weitere Informationen finden Sie unter Benachrichtigungskanäle auf developer.android.com.

  4. Fügen Sie im Ordner Platforms/Android des Projekts eine neue Klasse namens DeviceInstallationService hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    using Android.Gms.Common;
    using PushNotificationsDemo.Models;
    using PushNotificationsDemo.Services;
    using static Android.Provider.Settings;
    
    namespace PushNotificationsDemo.Platforms.Android;
    
    public class DeviceInstallationService : IDeviceInstallationService
    {
        public string Token { get; set; }
    
        public bool NotificationsSupported
            => GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(Platform.AppContext) == ConnectionResult.Success;
    
        public string GetDeviceId()
            => Secure.GetString(Platform.AppContext.ContentResolver, Secure.AndroidId);
    
        public DeviceInstallation GetDeviceInstallation(params string[] tags)
        {
            if (!NotificationsSupported)
                throw new Exception(GetPlayServicesError());
    
            if (string.IsNullOrWhiteSpace(Token))
                throw new Exception("Unable to resolve token for FCMv1.");
    
            var installation = new DeviceInstallation
            {
                InstallationId = GetDeviceId(),
                Platform = "fcmv1",
                PushChannel = Token
            };
    
            installation.Tags.AddRange(tags);
    
            return installation;
        }
    
        string GetPlayServicesError()
        {
            int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(Platform.AppContext);
    
            if (resultCode != ConnectionResult.Success)
                return GoogleApiAvailability.Instance.IsUserResolvableError(resultCode) ?
                           GoogleApiAvailability.Instance.GetErrorString(resultCode) :
                           "This device isn't supported.";
    
            return "An error occurred preventing the use of push notifications.";
        }
    }
    

    Diese Klasse stellt eine eindeutige ID mit dem Wert Secure.AndroidId und den Nutzdaten der Notification Hub-Registrierung bereit.

  5. Fügen Sie im Ordner Platforms/Android des Projekts eine neue Klasse namens PushNotificationFirebaseMessagingService hinzu, und ersetzen Sie den enthaltenen Code durch den folgenden Code:

    using Android.App;
    using Firebase.Messaging;
    using PushNotificationsDemo.Services;
    
    namespace PushNotificationsDemo.Platforms.Android;
    
    [Service(Exported = false)]
    [IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
    public class PushNotificationFirebaseMessagingService : FirebaseMessagingService
    {
        IPushDemoNotificationActionService _notificationActionService;
        INotificationRegistrationService _notificationRegistrationService;
        IDeviceInstallationService _deviceInstallationService;
        int _messageId;
    
        IPushDemoNotificationActionService NotificationActionService =>
            _notificationActionService ?? (_notificationActionService = IPlatformApplication.Current.Services.GetService<IPushDemoNotificationActionService>());
    
        INotificationRegistrationService NotificationRegistrationService =>
            _notificationRegistrationService ?? (_notificationRegistrationService = IPlatformApplication.Current.Services.GetService<INotificationRegistrationService>());
    
        IDeviceInstallationService DeviceInstallationService =>
            _deviceInstallationService ?? (_deviceInstallationService = IPlatformApplication.Current.Services.GetService<IDeviceInstallationService>());
    
        public override void OnNewToken(string token)
        {
            DeviceInstallationService.Token = token;
    
            NotificationRegistrationService.RefreshRegistrationAsync()
                .ContinueWith((task) =>
                {
                    if (task.IsFaulted)
                        throw task.Exception;
                });
        }
    
        public override void OnMessageReceived(RemoteMessage message)
        {
            base.OnMessageReceived(message);
    
            if (message.Data.TryGetValue("action", out var messageAction))
                NotificationActionService.TriggerAction(messageAction);
        }
    }
    

    Diese Klasse verfügt über ein IntentFilter-Attribut, das den Filter com.google.firebase.MESSAGING_EVENT enthält. Mit diesem Filter kann Android eingehende Nachrichten zur Verarbeitung an diese Klasse übergeben.

    Weitere Informationen zum Firebase Cloud Messaging-Nachrichtenformat finden Sie unter Informationen zu FCM-Nachrichten auf developer.android.com.

  6. Öffnen Sie in Visual Studio die Datei MainActivity.cs im Ordner Platforms/Android, und fügen Sie die folgenden using-Anweisungen hinzu:

    using Android.App;
    using Android.Content;
    using Android.Content.PM;
    using Android.OS;
    using PushNotificationsDemo.Services;
    using Firebase.Messaging;
    
  7. Legen Sie in der MainActivity-Klasse LaunchMode auf SingleTop fest, damit MainActivity beim Öffnen nicht erneut erstellt wird:

    [Activity(
        Theme = "@style/Maui.SplashTheme",
        MainLauncher = true,
        LaunchMode = LaunchMode.SingleTop,
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
    
  8. Fügen Sie in der MainActivity-Klasse Unterstützungsfelder hinzu, um Verweise auf die Implementierungen IPushDemoNotificationActionService und IDeviceInstallationService zu speichern:

    IPushDemoNotificationActionService _notificationActionService;
    IDeviceInstallationService _deviceInstallationService;
    
  9. Fügen Sie in der MainActivity-Klasse die privaten Eigenschaften NotificationActionService und DeviceInstallationService hinzu, die ihre konkreten Implementierungen aus dem Abhängigkeitsinjektionscontainer der App abrufen:

    IPushDemoNotificationActionService NotificationActionService =>
        _notificationActionService ?? (_notificationActionService = IPlatformApplication.Current.Services.GetService<IPushDemoNotificationActionService>());
    
    IDeviceInstallationService DeviceInstallationService =>
        _deviceInstallationService ?? (_deviceInstallationService = IPlatformApplication.Current.Services.GetService<IDeviceInstallationService>());
    
  10. Implementieren Sie in der MainActivity-Klasse die Android.Gms.Tasks.IOnSuccessListener-Schnittstelle zum Abrufen und Speichern des Firebase-Tokens:

    public class MainActivity : MauiAppCompatActivity, Android.Gms.Tasks.IOnSuccessListener
    {
        public void OnSuccess(Java.Lang.Object result)
        {
            DeviceInstallationService.Token = result.ToString();
        }
    }
    
  11. Fügen Sie in der MainActivity-Klasse die ProcessNotificationActions- Methode hinzu, die überprüft, ob ein bestimmter Intent-Wert einen zusätzlichen Wert mit dem Namen action hat, und lösen Sie action dann mit der IPushDemoNotificationActionService-Implementierung bedingt aus:

    void ProcessNotificationsAction(Intent intent)
    {
        try
        {
            if (intent?.HasExtra("action") == true)
            {
                var action = intent.GetStringExtra("action");
    
                if (!string.IsNullOrEmpty(action))
                    NotificationActionService.TriggerAction(action);
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message);
        }
    }
    
  12. Überschreiben Sie in der MainActivity-Klasse die OnNewIntent-Methode, um die ProcessNotificationActions-Methode aufzurufen:

    protected override void OnNewIntent(Intent? intent)
    {
        base.OnNewIntent(intent);
        ProcessNotificationsAction(intent);
    }
    

    Da LaunchMode für Activity auf SingleTop festgelegt ist, wird eine Intent über die OnNewIntent-Überschreibung und nicht über die OnCreate-Methode an die vorhandene Activity-Instanz gesendet. Daher müssen Sie eine eingehende Absicht sowohl in OnNewIntent als auch in OnCreate behandeln.

  13. Überschreiben Sie in der MainActivity-Klasse die OnCreate-Methode, um die ProcessNotificationActions-Methode aufzurufen und das Token von Firebase abzurufen. Fügen Sie dabei MainActivity als IOnSuccessListener hinzu:

    protected override void OnCreate(Bundle? savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
    
        if (DeviceInstallationService.NotificationsSupported)
            FirebaseMessaging.Instance.GetToken().AddOnSuccessListener(this);
    
        ProcessNotificationsAction(Intent);
    }
    

    Hinweis

    Die App muss jedes Mal, wenn Sie sie von einer Debugsitzung aus ausführen und beenden, neu registriert werden, um weiterhin Pushbenachrichtigungen zu erhalten.

  14. Fügen Sie in Visual Studio die POST_NOTIFICATIONS-Berechtigung in der Datei AndroidManifest.xml im Ordner Platforms/Android hinzu:

    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    

    Weitere Informationen zu dieser Berechtigung finden Sie unter Benachrichtigungs-Laufzeitberechtigung auf developer.android.com.

  15. Öffnen Sie in Visual Studio die Datei MainPage.xaml.cs, und fügen Sie der MainPage-Klasse den folgenden Code hinzu:

    #if ANDROID
            protected override async void OnAppearing()
            {
                base.OnAppearing();
    
                PermissionStatus status = await Permissions.RequestAsync<Permissions.PostNotifications>();
            }
    #endif
    

    Dieser Code wird unter Android ausgeführt, wenn die MainPage angezeigt wird, und fordert Benutzer auf, die POST_NOTIFICATIONS-Berechtigung zu gewähren. Weitere Informationen zu .NET MAUI-Berechtigungen finden Sie unter Berechtigungen.

Konfigurieren der iOS-App

Der iOS-Simulator unterstützt Remotebenachrichtigungen unter iOS 16 und höher bei der Ausführung auf Mac-Computern mit Apple Silicon- oder T2-Prozessoren unter macOS 13 und höher. Jeder Simulator generiert Registrierungstoken, die eindeutig für die Kombination aus diesem Simulator und der Mac-Hardware sind, auf der er ausgeführt wird.

Wichtig

Der Simulator unterstützt die Sandboxumgebung von Apple Push Notification Service.

In den folgenden Anweisungen wird davon ausgegangen, dass Sie Hardware verwenden, die das Empfangen von Remotebenachrichtigungen in einem iOS-Simulator unterstützt. Wenn dies nicht der Fall ist, müssen Sie die iOS-App auf einem physischen Gerät ausführen. Dazu müssen Sie ein Bereitstellungsprofil für Ihre App erstellen, das die Funktion für Pushbenachrichtigungen umfasst. Anschließend müssen Sie sicherstellen, dass Ihre App mit Ihrem Zertifikat und Ihrem Bereitstellungsprofil erstellt wird. Weitere Informationen zur Vorgehensweise finden Sie unter Einrichten Ihrer iOS-App für die Arbeit mit Azure Notification Hubs. Befolgen Sie anschließend die nachstehenden Anweisungen.

So konfigurieren Sie Ihre .NET MAUI-App unter iOS zum Empfangen und Verarbeiten von Pushbenachrichtigungen

  1. Bearbeiten Sie in Visual Studio die Projektdatei (*.csproj), und legen Sie SupportedOSPlatformVersion für iOS auf 13.0 fest:

    <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">13.0</SupportedOSPlatformVersion>
    

    Apple hat in iOS 13 Änderungen am Pushdienst vorgenommen. Weitere Informationen finden Sie unter Azure Notification Hubs-Updates für iOS 13.

  2. Fügen Sie in Visual Studio dem Ordner Platforms/iOS des Projekts eine Datei Entitlements.plist hinzu, und fügen Sie in der Datei den folgenden XML-Code hinzu:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
      <key>aps-environment</key>
      <string>development</string>
    </dict>
    </plist>
    

    Dadurch wird die APS-Umgebungsberechtigung festgelegt und die Verwendung der Entwicklungsumgebung von Apple Push Notification Service angegeben. In Produktions-Apps sollte dieser Berechtigungswert auf production festgelegt werden. Weitere Informationen zu dieser Berechtigung finden Sie unter APS Environment Entitlement (Berechtigungen in der APS-Umgebung) auf developer.apple.com.

    Weitere Informationen zum Hinzufügen einer Berechtigungsdatei finden Sie unter iOS-Berechtigungen.

  3. Fügen Sie in Visual Studio im Ordner Platforms/iOS des Projekts eine neue Klasse namens DeviceInstallationService hinzu, und fügen Sie in der Datei den folgenden Code hinzu:

    using PushNotificationsDemo.Services;
    using PushNotificationsDemo.Models;
    using UIKit;
    
    namespace PushNotificationsDemo.Platforms.iOS;
    
    public class DeviceInstallationService : IDeviceInstallationService
    {
        const int SupportedVersionMajor = 13;
        const int SupportedVersionMinor = 0;
    
        public string Token { get; set; }
    
        public bool NotificationsSupported =>
            UIDevice.CurrentDevice.CheckSystemVersion(SupportedVersionMajor, SupportedVersionMinor);
    
        public string GetDeviceId() =>
            UIDevice.CurrentDevice.IdentifierForVendor.ToString();
    
        public DeviceInstallation GetDeviceInstallation(params string[] tags)
        {
            if (!NotificationsSupported)
                throw new Exception(GetNotificationsSupportError());
    
            if (string.IsNullOrWhiteSpace(Token))
                throw new Exception("Unable to resolve token for APNS");
    
            var installation = new DeviceInstallation
            {
                InstallationId = GetDeviceId(),
                Platform = "apns",
                PushChannel = Token
            };
    
            installation.Tags.AddRange(tags);
    
            return installation;
        }
    
        string GetNotificationsSupportError()
        {
            if (!NotificationsSupported)
                return $"This app only supports notifications on iOS {SupportedVersionMajor}.{SupportedVersionMinor} and above. You are running {UIDevice.CurrentDevice.SystemVersion}.";
    
            if (Token == null)
                return $"This app can support notifications but you must enable this in your settings.";
    
            return "An error occurred preventing the use of push notifications";
        }
    }
    

    Diese Klasse stellt eine eindeutige ID mit dem Wert UIDevice.IdentifierForVendor und den Nutzdaten der Notification Hub-Registrierung bereit.

  4. Fügen Sie in Visual Studio im Ordner Platforms/iOS des Projekts eine neue Klasse namens NSDataExtensions hinzu, und fügen Sie in der Datei den folgenden Code hinzu:

    using Foundation;
    using System.Text;
    
    namespace PushNotificationsDemo.Platforms.iOS;
    
    internal static class NSDataExtensions
    {
        internal static string ToHexString(this NSData data)
        {
            var bytes = data.ToArray();
    
            if (bytes == null)
                return null;
    
            StringBuilder sb = new StringBuilder(bytes.Length * 2);
    
            foreach (byte b in bytes)
                sb.AppendFormat("{0:x2}", b);
    
            return sb.ToString().ToUpperInvariant();
        }
    }
    

    Die ToHexString-Erweiterungsmethode wird von dem Code verwendet, den Sie hinzufügen, um das abgerufene Gerätetoken zu parsen.

  5. Öffnen Sie in Visual Studio die Datei AppDelegate.cs im Ordner Platforms/iOS, und fügen Sie die folgenden using-Anweisungen hinzu:

    using System.Diagnostics;
    using Foundation;
    using PushNotificationsDemo.Platforms.iOS;
    using PushNotificationsDemo.Services;
    using UIKit;
    using UserNotifications;
    
  6. Fügen Sie in der AppDelegate-Klasse Unterstützungsfelder hinzu, um Verweise auf die Implementierungen IPushDemoNotificationActionService, INotificationRegistrationService und IDeviceInstallationService zu speichern:

    IPushDemoNotificationActionService _notificationActionService;
    INotificationRegistrationService _notificationRegistrationService;
    IDeviceInstallationService _deviceInstallationService;
    
  7. Fügen Sie in der AppDelegate-Klasse die privaten Eigenschaften NotificationActionService, NotificationRegistrationService und DeviceInstallationService hinzu, die ihre konkreten Implementierungen aus dem Abhängigkeitsinjektionscontainer der App abrufen:

    IPushDemoNotificationActionService NotificationActionService =>
        _notificationActionService ?? (_notificationActionService = IPlatformApplication.Current.Services.GetService<IPushDemoNotificationActionService>());
    
    INotificationRegistrationService NotificationRegistrationService =>
        _notificationRegistrationService ?? (_notificationRegistrationService = IPlatformApplication.Current.Services.GetService<INotificationRegistrationService>());
    
    IDeviceInstallationService DeviceInstallationService =>
        _deviceInstallationService ?? (_deviceInstallationService = IPlatformApplication.Current.Services.GetService<IDeviceInstallationService>());
    
  8. Fügen Sie in der AppDelegate-Klasse die CompleteRegistrationAsync-Methode hinzu, um den Wert der IDeviceInstallationService.Token-Eigenschaft festzulegen:

    Task CompleteRegistrationAsync(NSData deviceToken)
    {
        DeviceInstallationService.Token = deviceToken.ToHexString();
        return NotificationRegistrationService.RefreshRegistrationAsync();
    }
    

    Diese Methode aktualisiert auch die Registrierung und speichert das Gerätetoken zwischen, sofern es seit der letzten Speicherung aktualisiert wurde.

  9. Fügen Sie in der AppDelegate-Klasse die ProcessNotificationActions-Methode für die Verarbeitung der NSDictionary-Benachrichtigungsdaten und den bedingten Aufruf von NotificationActionService.TriggerAction hinzu:

    void ProcessNotificationActions(NSDictionary userInfo)
    {
        if (userInfo == null)
            return;
    
        try
        {
            // If your app isn't in the foreground, the notification goes to Notification Center.
            // If your app is in the foreground, the notification goes directly to your app and you
            // need to process the notification payload yourself.
            var actionValue = userInfo.ObjectForKey(new NSString("action")) as NSString;
    
            if (!string.IsNullOrWhiteSpace(actionValue?.Description))
                NotificationActionService.TriggerAction(actionValue.Description);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
    }
    
  10. Fügen Sie in der AppDelegate-Klasse die RegisteredForRemoteNotifications-Methode hinzu, und übergeben Sie das deviceToken-Argument an die CompleteRegistrationAsync-Methode:

    [Export("application:didRegisterForRemoteNotificationsWithDeviceToken:")]
    public void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
    {
        CompleteRegistrationAsync(deviceToken)
            .ContinueWith((task) =>
            {
                if (task.IsFaulted)
                    throw task.Exception;
            });
    }
    

    Diese Methode wird aufgerufen, wenn die App für den Empfang von Remotebenachrichtigungen registriert wird. Sie dient dazu, das eindeutige Gerätetoken anzufordern, das tatsächlich die Adresse Ihrer App auf dem Gerät ist.

  11. Fügen Sie in der AppDelegate-Klasse die ReceivedRemoteNotification-Methode hinzu, und übergeben Sie das userInfo-Argument an die ProcessNotificationActions-Methode:

    [Export("application:didReceiveRemoteNotification:")]
    public void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
    {
        ProcessNotificationActions(userInfo);
    }
    

    Diese Methode wird aufgerufen, wenn die App eine Remotebenachrichtigung empfangen hat, und dient zum Verarbeiten der Benachrichtigung.

  12. Fügen Sie in der AppDelegate-Klasse die FailedToRegisterForRemoteNotifications-Methode hinzu, um mögliche Fehler zu protokollieren:

    [Export("application:didFailToRegisterForRemoteNotificationsWithError:")]
    public void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)
    {
        Debug.WriteLine(error.Description);
    }
    

    Diese Methode wird aufgerufen, wenn die App nicht für den Empfang von Remotebenachrichtigungen registriert werden konnte. Die Registrierung kann fehlschlagen, wenn das Gerät nicht mit dem Netzwerk verbunden ist, wenn der APNS-Server nicht erreichbar ist oder wenn die App falsch konfiguriert wurde.

    Hinweis

    In Produktionsszenarien sollten Sie eine richtige Protokollierung und Fehlerbehandlung in der FailedToRegisterForRemoteNotifications-Methode implementieren.

  13. Fügen Sie in der AppDelegate-Klasse die FinishedLaunching-Methode hinzu, um bedingt die Berechtigung zur Verwendung von Benachrichtigungen und die Registrierung für Remotebenachrichtigungen anzufordern:

    [Export("application:didFinishLaunchingWithOptions:")]
    public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
    {
        if (DeviceInstallationService.NotificationsSupported)
        {
            UNUserNotificationCenter.Current.RequestAuthorization(
                UNAuthorizationOptions.Alert |
                UNAuthorizationOptions.Badge |
                UNAuthorizationOptions.Sound,
                (approvalGranted, error) =>
                {
                    if (approvalGranted && error == null)
                    {
                        MainThread.BeginInvokeOnMainThread(() =>
                        {
                            UIApplication.SharedApplication.RegisterForRemoteNotifications();
                        });
                    }
                });
        }
    
        using (var userInfo = launchOptions?.ObjectForKey(UIApplication.LaunchOptionsRemoteNotificationKey) as NSDictionary)
        {
            ProcessNotificationActions(userInfo);
        }
    
        return base.FinishedLaunching(application, launchOptions);
    }
    

    Weitere Informationen zum Anfordern von Berechtigungen für die Verwendung von Benachrichtigungen finden Sie unter Asking permission to use notifications (Anfordern von Berechtigungen zum Verwenden von Benachrichtigungen) auf developer.apple.com.

Weitere Informationen zu Benachrichtigungen unter iOS finden Sie unter User Notifications (Benutzerbenachrichtigungen) auf developer.apple.com.

Registrieren von Typen beim Abhängigkeitsinjektionscontainer

  1. Öffnen Sie in Visual Studio die Datei MauiProgram.xaml.cs, und fügen Sie eine using-Anweisung für den PushNotificationsDemo.Services-Namespace hinzu:

    using PushNotificationsDemo.Services;
    
  2. Fügen Sie in der MauiProgram-Klasse Code für die RegisterServices-Erweiterungsmethode hinzu, die DeviceInstallationService auf jeder Plattform und die plattformübergreifenden Dienste PushDemoNotificationActionService und NotificationRegistrationService registriert und ein MauiAppBuilder-Objekt zurückgibt:

    public static MauiAppBuilder RegisterServices(this MauiAppBuilder builder)
    {
    #if IOS
        builder.Services.AddSingleton<IDeviceInstallationService, PushNotificationsDemo.Platforms.iOS.DeviceInstallationService>();
    #elif ANDROID
        builder.Services.AddSingleton<IDeviceInstallationService, PushNotificationsDemo.Platforms.Android.DeviceInstallationService>();
    #endif
    
        builder.Services.AddSingleton<IPushDemoNotificationActionService, PushDemoNotificationActionService>();
        builder.Services.AddSingleton<INotificationRegistrationService>(new NotificationRegistrationService(Config.BackendServiceEndpoint, Config.ApiKey));
    
        return builder;
    }
    
  3. Fügen Sie in der MauiProgram-Klasse Code für die RegisterViews-Erweiterungsmethode hinzu, die den Typ MainPage als Singleton registriert und ein MauiAppBuilder-Objekt zurückgibt:

    public static MauiAppBuilder RegisterViews(this MauiAppBuilder builder)
    {
        builder.Services.AddSingleton<MainPage>();
        return builder;
    }
    

    Der Typ MainPage wird registriert, da er eine INotificationRegistrationService-Abhängigkeit erfordert, und alle Typen, die eine Abhängigkeit erfordern, müssen beim Abhängigkeitsinjektionscontainer registriert werden.

  4. Ändern Sie in der MauiProgram-Klasse die CreateMauiApp-Methode so, dass sie die Erweiterungsmethoden RegisterServices und RegisterViews aufruft:

    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");
            })
            .RegisterServices()
            .RegisterViews();
    
    #if DEBUG
          builder.Logging.AddDebug();
    #endif
          return builder.Build();
    }
    

Weitere Informationen zur Abhängigkeitsinjektion in .NET MAUI finden Sie unter Abhängigkeitsinjektion.

Testen der App

Sie können Ihre App testen, indem Sie Pushbenachrichtigungen über den Back-End-Dienst oder über das Azure-Portal an die App senden.

Der iOS-Simulator unterstützt Remotebenachrichtigungen unter iOS 16 und höher bei der Ausführung auf Mac-Computern mit Apple Silicon- oder T2-Prozessoren unter macOS 13 und höher. Wenn diese Hardwareanforderungen nicht erfüllt sind, müssen Sie Ihre iOS-App auf einem physischen Gerät testen. Unter Android können Sie Ihre App auf einem für die Entwicklung entsperrten physischen Gerät oder in einem Emulator testen.

Unter Android und iOS werden Pushbenachrichtigungen im Namen der App an, wenn sie im Hintergrund ausgeführt wird. Wenn die App beim Empfang der Benachrichtigung im Vordergrund ausgeführt wird, bestimmt der App-Code das Verhalten. Sie können beispielsweise die Benutzeroberfläche Ihrer App so aktualisieren, dass die neuen Informationen aus der Benachrichtigung angezeigt werden.

Testen mithilfe des Back-End-Diensts

So senden Sie eine Testpushbenachrichtigung über den Back-End-Dienst, die in Azure App Service veröffentlicht wird

  1. Führen Sie in Visual Studio die PushNotificationsDemo-App unter Android oder iOS aus, und wählen Sie die Schaltfläche zum Registrieren aus.

    Hinweis

    Wenn Sie unter Android testen, stellen Sie sicher, dass die Ausführung nicht mit der Debugkonfiguration erfolgt. Wenn die App zuvor bereitgestellt wurde, stellen Sie außerdem sicher, dass sie geschlossen wurde, und starten Sie sie dann erneut über den Launcher.

  2. Senden Sie im REST-Tool Ihrer Wahl eine POST-Anforderung an die folgende Adresse:

    https://<app_name>.azurewebsites.net/api/notifications/requests
    

    Stellen Sie sicher, dass Sie die Anforderungsheader so konfigurieren, dass der Schlüssel apikey mit seinem Wert enthalten ist, legen Sie den Textkörper auf unformatiert fest, und verwenden Sie den folgenden JSON-Inhalt:

    {
        "text": "Message from REST tooling!",
        "action": "action_a"
    }
    

    Die Anforderung sollte dem folgenden Beispiel ähneln:

    POST /api/notifications/requests HTTP/1.1
    Host: https://<app_name>.azurewebsites.net
    apikey: <your_api_key>
    Content-Type: application/json
    
    {
        "text": "Message from REST tooling!",
        "action": "action_a"
    }
    
  3. Überprüfen Sie im REST-Tool Ihrer Wahl, dass Sie eine Antwort vom Typ 200 OK erhalten.

  4. In der App sollte unter Android oder iOS eine Warnung vom Typ ActionA-Aktion empfangen angezeigt werden.

Weitere Informationen zum Aufrufen von REST-APIs finden Sie unter Verwenden von HTTP-Dateien in Visual Studio und Testen von Web-APIs mit HTTP REPL. In Visual Studio Code kann der REST-Client zum Testen von REST-APIs verwendet werden.

Testen über das Azure-Portal

Mit Azure Notification Hubs können Sie überprüfen, ob Ihre App Pushbenachrichtigungen empfangen kann.

So senden Sie eine Testpushbenachrichtigung über das Azure-Portal an Ihre App

  1. Führen Sie in Visual Studio die PushNotificationsDemo-App unter Android oder iOS aus, und wählen Sie die Schaltfläche zum Registrieren aus.

    Hinweis

    Wenn Sie unter Android testen, stellen Sie sicher, dass die Ausführung nicht mit der Debugkonfiguration erfolgt. Wenn die App zuvor bereitgestellt wurde, stellen Sie außerdem sicher, dass sie geschlossen wurde, und starten Sie sie dann erneut über den Launcher.

  2. Navigieren Sie im Azure-Portal zu Ihrem Notification Hub, und wählen Sie auf dem Blatt Übersicht die Schaltfläche Senden testen aus.

  3. Wählen Sie auf dem Blatt Senden testen Ihre Plattform aus, und ändern Sie die Nutzdaten.

    Verwenden Sie für Apple folgende Nutzdaten:

    {
      "aps": {
        "alert": "Message from Notification Hub!"
      },
      "action": "action_a"
    }
    

    Verwenden Sie für Android folgende Nutzdaten:

    {
      "message": {
        "notification": {
          "title": "PushDemo",
          "body": "Message from Notification Hub!"
        },
        "data": {
          "action": "action_a"
        }
      }
    }
    

    Im Azure-Portal sollte angegeben werden, dass die Benachrichtigung erfolgreich gesendet wurde.

    Weitere Informationen zum Firebase Cloud Messaging-Nachrichtenformat finden Sie unter Informationen zu FCM-Nachrichten auf developer.android.com.

  4. In der App sollte unter Android oder iOS eine Warnung vom Typ ActionA-Aktion empfangen angezeigt werden.

Problembehandlung

In den folgenden Abschnitten werden häufig auftretende Probleme beim Verwenden von Pushbenachrichtigungen in einer Client-App erläutert.

Keine Antwort vom Back-End-Dienst

Vergewissern Sie sich beim lokalen Testen, dass der Back-End-Dienst ausgeführt wird und den richtigen Port verwendet.

Wenn Sie den Test mit der Azure-API-App ausführen, überprüfen Sie, ob der Dienst ausgeführt wird und ohne Fehler bereitgestellt und gestartet wurde.

Vergewissern Sie sich, dass Sie die Basisadresse in Ihrem REST-Tool oder in der Konfiguration Ihrer .NET MAUI-App richtig angegeben haben. Die Basisadresse sollte bei lokalen Tests https://<api_name>.azurewebsites.net oder https://localhost:7020 lauten.

Empfangen eines 401-Statuscodes vom Back-End-Dienst

Vergewissern Sie sich, dass Sie den apikey-Anforderungsheader richtig festgelegt haben und dass dieser Wert mit dem übereinstimmt, den Sie für den Back-End-Dienst konfiguriert haben.

Wenn dieser Fehler bei lokalen Tests auftritt, stellen Sie sicher, dass der Schlüsselwert, den Sie in Ihrer .NET MAUI-App definiert haben, mit dem Authentication:ApiKey-Wert für das Benutzergeheimnis übereinstimmt, der vom Back-End-Dienst verwendet wird.

Stellen Sie bei Tests mit einer Azure-API-App sicher, dass der in Ihrer .NET MAUI-App definierte Schlüsselwert mit dem im Azure-Portal in den App-Einstellungen definierten Authentication:ApiKey-Wert übereinstimmt. Wenn Sie diese App-Einstellung erstellt oder geändert haben, nachdem Sie den Back-End-Dienst bereitgestellt haben, müssen Sie den Dienst neu starten, damit der Wert wirksam wird.

Empfangen eines 404-Statuscodes vom Back-End-Dienst

Überprüfen Sie, ob der Endpunkt und die HTTP-Anforderungsmethode korrekt sind:

  • PUT: https://<api_name>.azurewebsites.net/api/notifications/installations
  • DELETE: https://<api_name>.azurewebsites.net/api/notifications/installations/<installation_id>
  • POST: https://<api_name>.azurewebsites.net/api/notifications/requests

Oder beim lokalen Testen:

  • PUT: https://localhost:7020/api/notifications/installations
  • DELETE: https://localhost:7020/api/notifications/installations/<installation_id>
  • POST: https://localhost:7020/api/notifications/requests

Wichtig

Wenn Sie die Basisadresse in der .NET MAUI-App angeben, stellen Sie sicher, dass sie mit einem / endet. Die Basisadresse sollte bei lokalen Tests https://<api_name>.azurewebsites.net oder https://localhost:7020/ lauten.

Kein Empfang von Benachrichtigungen unter Android nach dem Starten oder Beenden einer Debugsitzung

Achten Sie darauf, bei jedem Start einer Debugsitzung eine Registrierung durchzuführen. Der Debugger löst das Generieren eines neuen Firebase-Tokens aus, daher muss die Installation des Notification Hubs aktualisiert werden.

Registrierung kann nicht ausgeführt werden, und eine Benachrichtigungshub-Fehlermeldung wird angezeigt

Stellen Sie sicher, dass das Testgerät über Netzwerkkonnektivität verfügt. Bestimmen Sie dann den HTTP-Statuscode der Antwort, indem Sie einen Haltepunkt festlegen, um die StatusCode-Eigenschaft in der HttpResponse zu untersuchen.

Prüfen Sie gegebenenfalls die früheren Vorschläge zur Problembehandlung basierend auf dem Statuscode.

Legen Sie einen Haltpunkt für die Zeilen fest, die spezifische Statuscodes für die jeweilige API zurückgeben. Versuchen Sie dann, beim lokalen Debuggen den Back-End-Dienst aufzurufen.

Überprüfen Sie mit Ihrem bevorzugten REST-Tool, ob der Back-End-Dienst wie erwartet funktioniert, und verwenden Sie die von der .NET MAUI-App für Ihre ausgewählte Plattform erstellten Nutzdaten.

Überprüfen Sie die plattformspezifischen Konfigurationsabschnitte, um sicherzustellen, dass keine Schritte ausgelassen wurden. Vergewissern Sie sich, dass für die Variablen InstallationId und Token geeignete Werte für die entsprechende Plattform aufgelöst werden.

Fehlermeldung „Eine ID für das Gerät kann nicht aufgelöst werden“

Überprüfen Sie die plattformspezifischen Konfigurationsabschnitte, um sicherzustellen, dass keine Schritte ausgelassen wurden.