Tutorial: Senden von Pushbenachrichtigungen an Flutter-Apps mithilfe von Azure Notification Hubs über einen Back-End-Dienst

Beispiel herunterladen Herunterladen des Beispiels

In diesem Tutorial verwenden Sie Azure Notification Hubs zum Pushen von Benachrichtigungen an eine Flutter-Anwendung für Android und iOS.

Ein ASP.NET Core Web-API-Back-End wird verwendet, um die Geräteregistrierung für den Client mithilfe des neuesten und besten Installationsansatzes zu verarbeiten. Der Dienst sendet auch plattformübergreifend Pushbenachrichtigungen.

Diese Vorgänge werden mit dem Notification Hubs SDK für Back-End-Vorgänge verarbeitet. Weitere Details zum Gesamtansatz finden Sie in der Dokumentation Registrieren über Das App-Back-End .

In diesem Tutorial werden die folgenden Schritte erklärt:

Voraussetzungen

Für die Weiterverfolgung benötigen Sie Folgendes:

Für Android benötigen Sie Folgendes:

  • Ein entwicklerentsperrtes physisches Gerät oder ein Emulator (mit API 26 und höher mit installierten Google Play Services)

Für iOS benötigen Sie Folgendes:

Hinweis

Der iOS-Simulator unterstützt keine Remotebenachrichtigungen, sodass ein physisches Gerät erforderlich ist, wenn Sie dieses Beispiel unter iOS untersuchen. Sie müssen die App jedoch nicht sowohl unter Android als auch unter iOS ausführen, um dieses Tutorial abzuschließen.

Sie können die Schritte in diesem ersten Beispiel für Prinzipien ohne vorherige Erfahrung ausführen. Sie profitieren jedoch davon, dass Sie mit den folgenden Aspekten vertraut sind.

Die angegebenen Schritte sind spezifisch für macOS. Es ist möglich, auf Windows zu folgen, indem Sie die iOS-Aspekte überspringen.

Einrichten von Push Notification Services und Azure Notification Hub

In diesem Abschnitt richten Sie Firebase Cloud Messaging (FCM) und Apple Push Notification Services (APNS) ein. Anschließend erstellen und konfigurieren Sie einen Notification Hub für die Verwendung dieser Dienste.

Erstellen eines Firebase-Projekts und Aktivieren von Firebase Cloud Messaging für Android

  1. Melden Sie sich bei der Firebase-Konsole an. Erstellen Sie ein neues Firebase-Projekt, indem Sie PushDemo als Projektnamen eingeben.

    Hinweis

    Ein eindeutiger Name wird für Sie generiert. Standardmäßig besteht dies aus einer Kleinbuchstabenvariante des angegebenen Namens sowie einer generierten Zahl, die durch einen Bindestrich getrennt ist. Sie können dies ändern, wenn Sie dies möchten, sofern sie weiterhin global eindeutig ist.

  2. Nachdem Sie Ihr Projekt erstellt haben, wählen Sie Firebase zu Ihrer Android-App hinzufügen aus.

    Hinzufügen von Firebase zu Ihrer Android-App

  3. Führen Sie auf der Seite Firebase zu Ihrer Android-App hinzufügen die folgenden Schritte aus.

    1. Geben Sie unter Android-Paketname einen Namen für Ihr Paket ein. Beispiel: com.<organization_identifier>.<package_name>.

      Angeben des Paketnamens

    2. Wählen Sie App registrieren aus.

    3. Wählen Sie google-services.json herunterladen aus. Speichern Sie die Datei dann zur späteren Verwendung in einem lokalen Ordner, und wählen Sie Weiter aus.

      google-services.json herunterladen

    4. Klicken Sie auf Weiter.

    5. Wählen Sie Weiter zur Konsole aus.

      Hinweis

      Wenn die Schaltfläche Mit Konsole fortfahren aufgrund der Überprüfung der Installation nicht aktiviert ist, wählen Sie Diesen Schritt überspringen aus.

  4. Wählen Sie in der Firebase-Konsole das Zahnrad für Ihr Projekt aus. Wählen Sie dann Projekteinstellungen aus.

    Auswählen von Projekteinstellungen

    Hinweis

    Wenn Sie die google-services.json-Datei nicht heruntergeladen haben, können Sie sie auf dieser Seite herunterladen.

  5. Wechseln Sie oben zur Registerkarte Cloud Messaging . Kopieren Und speichern Sie den Serverschlüssel zur späteren Verwendung. Sie verwenden diesen Wert, um Ihren Notification Hub zu konfigurieren.

    Kopieren des Serverschlüssels

Registrieren Ihrer iOS-App für Pushbenachrichtigungen

Um Pushbenachrichtigungen an eine iOS-App zu senden, registrieren Sie Ihre Anwendung bei Apple, und registrieren Sie sich auch für Pushbenachrichtigungen.

  1. Wenn Sie Ihre App noch nicht registriert haben, navigieren Sie zum iOS-Bereitstellungsportal im Apple Developer Center. Melden Sie sich mit Ihrer Apple-ID beim Portal an, navigieren Sie zu Zertifikate, Bezeichner & Profile, und wählen Sie dann Bezeichner aus. Klicken Sie hier + , um eine neue App zu registrieren.

    iOS-Seite

  2. Wählen Sie auf dem Bildschirm Neuen Bezeichner registrieren das Optionsfeld App-IDs aus. Klicken Sie anschließend auf Weiter.

    Seite

  3. Aktualisieren Sie die folgenden drei Werte für Ihre neue App, und wählen Sie dann Weiter aus:

    • Beschreibung: Geben Sie einen beschreibenden Namen für Ihre App ein.

    • Bundle-ID: Geben Sie eine Bundle-ID im Format com.organization_identifier<> ein.<>product_name, wie im App-Verteilungshandbuch erwähnt. Im folgenden Screenshot wird der mobcat Wert als organization-Bezeichner und der PushDemo-Wert als Produktname verwendet.

      Seite

    • Pushbenachrichtigungen: Aktivieren Sie die Option Pushbenachrichtigungen im Abschnitt Funktionen .

      Formular zum Registrieren einer neuen App-ID

      Diese Aktion generiert Ihre App-ID und fordert sie auf, die Informationen zu bestätigen. Wählen Sie Weiter und dann Registrieren aus, um die neue App-ID zu bestätigen.

      Bestätigen der neuen App-ID

      Nachdem Sie Registrieren ausgewählt haben, wird die neue App-ID als Zeilenelement auf der Seite Zertifikate, Bezeichner & Profile angezeigt .

  4. Suchen Sie auf der Seite Zertifikate, Bezeichner & Profile unter Bezeichner das von Ihnen erstellte App-ID-Zeilenelement. Wählen Sie dann die zugehörige Zeile aus, um den Bildschirm App-ID-Konfiguration bearbeiten anzuzeigen.

Erstellen eines Zertifikats für Notification Hubs

Ein Zertifikat ist erforderlich, damit der Notification Hub mit Apple Push Notification Services (APNS) arbeiten kann und kann auf zwei Arten bereitgestellt werden:

  1. Erstellen eines p12-Pushzertifikats, das direkt in Notification Hub hochgeladen werden kann (der ursprüngliche Ansatz)

  2. Erstellen eines p8-Zertifikats, das für die tokenbasierte Authentifizierung verwendet werden kann (neuer und empfohlener Ansatz)

Der neuere Ansatz bietet eine Reihe von Vorteilen, die in der tokenbasierten Authentifizierung (HTTP/2) für APNS dokumentiert sind. Es sind weniger Schritte erforderlich, aber auch für bestimmte Szenarien vorgeschrieben. Für beide Ansätze wurden jedoch Schritte bereitgestellt, da beide für die Zwecke dieses Tutorials funktionieren.

OPTION 1: Erstellen eines p12-Pushzertifikats, das direkt in den Notification Hub hochgeladen werden kann
  1. Führen Sie auf Ihrem Mac das Keychain Access-Tool aus. Sie kann im Ordner Hilfsprogramme oder im Ordner Andere auf dem Launchpad geöffnet werden.

  2. Wählen Sie Schlüsselbundzugriff aus, erweitern Sie Zertifikat-Assistent, und wählen Sie dann Zertifikat von einer Zertifizierungsstelle anfordern aus.

    Verwenden des Schlüsselbundzugriffs zum Anfordern eines neuen Zertifikats

    Hinweis

    Standardmäßig wählt keychain Access das erste Element in der Liste aus. Dies kann ein Problem sein, wenn Sie sich in der Kategorie Zertifikate befinden und die Apple Worldwide Developer Relations Certification Authority nicht das erste Element in der Liste ist. Stellen Sie sicher, dass Sie über ein nicht schlüsselfähiges Element verfügen oder dass der Apple Worldwide Developer Relations Certification Authority-Schlüssel ausgewählt ist, bevor Sie die CSR (Certificate Signing Request) generieren.

  3. Wählen Sie Ihre Benutzer-Email-Adresse aus, geben Sie Ihren Common Name-Wert ein, stellen Sie sicher, dass Sie Auf Datenträger gespeichert angeben, und wählen Sie dann Weiter aus. Lassen Sie Email Adresse der Zertifizierungsstelle leer, da sie nicht erforderlich ist.

    Erwartete Zertifikatinformationen

  4. Geben Sie unter Speichern unter einen Namen für die CSR-Datei (Certificate Signing Request) ein, wählen Sie den Speicherort in Where aus, und wählen Sie dann Speichern aus.

    Auswählen eines Dateinamens für das Zertifikat

    Mit dieser Aktion wird die CSR-Datei am ausgewählten Speicherort gespeichert. Der Standardspeicherort ist Desktop. Merken Sie sich den für die Datei ausgewählten Speicherort.

  5. Zurück auf der Seite Zertifikate, Bezeichner & Profile im iOS-Bereitstellungsportal, scrollen Sie nach unten zur aktivierten Option Pushbenachrichtigungen , und wählen Sie dann Konfigurieren aus, um das Zertifikat zu erstellen.

    Seite

  6. Das Fenster TLS/SSL-Zertifikate des Apple-Pushbenachrichtigungsdiensts wird angezeigt. Wählen Sie im Abschnitt Entwicklung TLS/SSL-Zertifikat die Schaltfläche Zertifikat erstellen aus.

    Schaltfläche

    Der Bildschirm Neues Zertifikat erstellen wird angezeigt.

    Hinweis

    In diesem Tutorial wird ein Entwicklungszertifikat verwendet. Der gleiche Prozess wird beim Registrieren eines Produktionszertifikats verwendet. Stellen Sie einfach sicher, dass Sie beim Senden von Benachrichtigungen denselben Zertifikattyp verwenden.

  7. Wählen Sie Datei auswählen aus, navigieren Sie zu dem Speicherort, an dem Sie die CSR-Datei gespeichert haben, und doppelklicken Sie dann auf den Zertifikatnamen, um sie zu laden. Klicken Sie anschließend auf Weiter.

  8. Nachdem das Portal das Zertifikat erstellt hat, wählen Sie die Schaltfläche Herunterladen aus. Speichern Sie das Zertifikat, und merken Sie sich den Speicherort, an dem es gespeichert wird.

    Seite zum Herunterladen eines generierten Zertifikats

    Das Zertifikat wird heruntergeladen und auf Ihrem Computer im Ordner Downloads gespeichert.

    Suchen der Zertifikatdatei im Ordner Downloads

    Hinweis

    Standardmäßig heißt das heruntergeladene Entwicklungszertifikat aps_development.cer.

  9. Doppelklicken Sie auf das heruntergeladene Pushzertifikat aps_development.cer. Mit dieser Aktion wird das neue Zertifikat im Schlüsselbund installiert, wie in der folgenden Abbildung gezeigt:

    Liste der Schlüsselbundzugriffszertifikate mit neuem Zertifikat

    Hinweis

    Obwohl sich der Name in Ihrem Zertifikat möglicherweise unterscheidet, wird dem Namen das Präfix Apple Development iOS Push Services vorangestellt und der entsprechende Bundle-Bezeichner zugeordnet.

  10. Klicken Sie in Keychain Access, Control + Klicken Sie auf das neue Pushzertifikat, das Sie in der Kategorie Zertifikate erstellt haben. Wählen Sie Exportieren, benennen Sie die Datei, wählen Sie das p12-Format und dann Speichern aus.

    Exportieren des Zertifikats als P12-Format

    Sie können das Zertifikat mit einem Kennwort schützen, ein Kennwort ist jedoch optional. Klicken Sie auf OK , wenn Sie die Kennworterstellung umgehen möchten. Notieren Sie sich den Dateinamen und den Speicherort des exportierten p12-Zertifikats. Sie werden verwendet, um die Authentifizierung mit APNs zu aktivieren.

    Hinweis

    Ihr p12-Dateiname und -Speicherort unterscheiden sich möglicherweise von den Abbildungen in diesem Tutorial.

OPTION 2: Erstellen eines p8-Zertifikats, das für die tokenbasierte Authentifizierung verwendet werden kann
  1. Notieren Sie sich die folgenden Details:

    • App-ID-Präfix (Team-ID)
    • Bundle-ID
  2. Klicken Sie zurück unter Zertifikate, Bezeichner & Profile auf Schlüssel.

    Hinweis

    Wenn Sie bereits einen Schlüssel für APNS konfiguriert haben, können Sie das p8-Zertifikat, das Sie direkt nach der Erstellung heruntergeladen haben, erneut verwenden. Wenn ja, können Sie die Schritte 3 bis 5 ignorieren.

  3. Klicken Sie auf die + Schaltfläche (oder die Schaltfläche Schlüssel erstellen ), um einen neuen Schlüssel zu erstellen.

  4. Geben Sie einen geeigneten Schlüsselnamenwert an, aktivieren Sie dann die Option Apple Push Notifications Service (APNS), und klicken Sie dann auf Weiter, gefolgt von Registrieren auf dem nächsten Bildschirm.

  5. Klicken Sie auf Herunterladen , verschieben Sie dann die p8-Datei (mit dem Präfix AuthKey_) in ein sicheres lokales Verzeichnis, und klicken Sie dann auf Fertig.

    Hinweis

    Bewahren Sie Ihre p8-Datei an einem sicheren Ort auf (und speichern Sie eine Sicherung). Nachdem Sie Ihren Schlüssel heruntergeladen haben, kann er nicht erneut heruntergeladen werden, da die Serverkopie entfernt wird.

  6. Klicken Sie unter Schlüssel auf den schlüssel, den Sie erstellt haben (oder auf einen vorhandenen Schlüssel, wenn Sie diesen stattdessen verwenden möchten).

  7. Notieren Sie sich den Schlüssel-ID-Wert .

  8. Öffnen Sie Ihr p8-Zertifikat in einer geeigneten Anwendung Ihrer Wahl, z. B . Visual Studio Code. Notieren Sie sich den Schlüsselwert (zwischen -----BEGIN PRIVATE KEY----- und -----END PRIVATE KEY-----).

    -----BEGIN PRIVATE KEY-----
    <key_value>
    -----END PRIVATE KEY-----

    Hinweis

    Dies ist der Tokenwert , der später zum Konfigurieren des Notification Hubs verwendet wird.

Am Ende dieser Schritte sollten Sie die folgenden Informationen zur späteren Verwendung unter Konfigurieren Ihres Notification Hubs mit APNS-Informationen haben:

  • Team-ID (siehe Schritt 1)
  • Bundle-ID (siehe Schritt 1)
  • Schlüssel-ID (siehe Schritt 7)
  • Tokenwert (p8-Schlüsselwert, der in Schritt 8 abgerufen wurde)

Erstellen eines Bereitstellungsprofils für die App

  1. Kehren Sie zum iOS-Bereitstellungsportal zurück, wählen Sie Zertifikate, Bezeichner & Profile aus, wählen Sie profile im linken Menü aus, und wählen Sie + dann ein neues Profil aus. Der Bildschirm Neues Bereitstellungsprofil registrieren wird angezeigt.

  2. Wählen Sie unter Entwicklung als Bereitstellungsprofiltyp die Option iOS-App-Entwicklung aus, und wählen Sie dann Weiter aus.

    Liste des Bereitstellungsprofils

  3. Wählen Sie als Nächstes die app-ID aus, die Sie in der Dropdownliste App-ID erstellt haben, und wählen Sie Weiter aus.

    Auswählen der App-ID

  4. Wählen Sie im Fenster Zertifikate auswählen das Entwicklungszertifikat aus, das Sie für die Codesignierung verwenden, und dann Weiter.

    Hinweis

    Dieses Zertifikat ist nicht das Pushzertifikat, das Sie im vorherigen Schritt erstellt haben. Dies ist Ihr Entwicklungszertifikat. Wenn sie nicht vorhanden ist, müssen Sie es erstellen, da dies eine Voraussetzung für dieses Tutorial ist. Entwicklerzertifikate können im Apple Developer Portal, über Xcode oder in Visual Studio erstellt werden.

  5. Kehren Sie zur Seite Zertifikate, Bezeichner & Profile zurück, wählen Sie im linken Menü Profile aus, und wählen Sie + dann ein neues Profil aus. Der Bildschirm Neues Bereitstellungsprofil registrieren wird angezeigt.

  6. Wählen Sie im Fenster Zertifikate auswählen das von Ihnen erstellte Entwicklungszertifikat aus. Klicken Sie anschließend auf Weiter.

  7. Wählen Sie als Nächstes die Geräte aus, die zum Testen verwendet werden sollen, und wählen Sie Weiter aus.

  8. Wählen Sie schließlich unter Name des Bereitstellungsprofils einen Namen für das Profil aus, und wählen Sie Generieren aus.

    Auswählen eines Bereitstellungsprofilnamens

  9. Wenn das neue Bereitstellungsprofil erstellt wird, wählen Sie Herunterladen aus. Merken Sie sich den Speicherort, an dem sie gespeichert wird.

  10. Navigieren Sie zum Speicherort des Bereitstellungsprofils, und doppelklicken Sie darauf, um es auf Ihrem Entwicklungscomputer zu installieren.

Erstellen eines Notification Hubs

In diesem Abschnitt erstellen Sie einen Notification Hub und konfigurieren die Authentifizierung mit APNS. Sie können ein p12-Pushzertifikat oder eine tokenbasierte Authentifizierung verwenden. Wenn Sie einen bereits erstellten Notification Hub verwenden möchten, können Sie mit Schritt 5 fortfahren.

  1. Melden Sie sich bei Azure an.

  2. Klicken Sie auf Ressource erstellen, suchen Sie nach Notification Hub, und wählen Sie diese Option aus, und klicken Sie dann auf Erstellen.

  3. Aktualisieren Sie die folgenden Felder, und klicken Sie dann auf Erstellen:

    GRUNDLEGENDE DETAILS

    Abonnement: Auswählen des Zielabonnements aus der Dropdownliste
    Ressourcengruppe: Erstellen einer neuen Ressourcengruppe (oder Auswählen einer vorhandenen Ressourcengruppe)

    NAMESPACEDETAILS

    Notification Hub-Namespace: Geben Sie einen global eindeutigen Namen für den Notification Hub-Namespace ein.

    Hinweis

    Stellen Sie sicher, dass die Option Neu erstellen für dieses Feld ausgewählt ist.

    NOTIFICATION HUB-DETAILS

    Notification Hub: Geben Sie einen Namen für den Notification Hub ein.
    Lage: Auswählen eines geeigneten Standorts aus der Dropdownliste
    Tarif: Behalten Sie die Standardoption Free bei.

    Hinweis

    Es sei denn, Sie haben die maximale Anzahl von Hubs im Free-Tarif erreicht.

  4. Nachdem der Notification Hub bereitgestellt wurde, navigieren Sie zu dieser Ressource.

  5. Navigieren Sie zu Ihrem neuen Notification Hub.

  6. Wählen Sie in der Liste Zugriffsrichtlinien aus (unter VERWALTEN).

  7. Notieren Sie sich die Werte des Richtliniennamens zusammen mit den entsprechenden Verbindungszeichenfolgenwerten .

Konfigurieren Ihres Notification Hubs mit APNS-Informationen

Wählen Sie unter Notification Servicesdie Option Apple aus, und führen Sie dann die entsprechenden Schritte basierend auf dem Ansatz aus, den Sie zuvor im Abschnitt Erstellen eines Zertifikats für Notification Hubs ausgewählt haben.

Hinweis

Verwenden Sie den Produktionsmodus nur, 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 Certificateaus.

  2. Wählen Sie das Dateisymbol aus.

  3. Wählen Sie die P12-Datei aus, die Sie zuvor exportiert haben, und wählen Sie dann Öffnen aus.

  4. Geben Sie bei Bedarf das richtige Kennwort an.

  5. Wählen Sie den Modus Sandbox aus.

  6. Wählen Sie Speichern aus.

OPTION 2: Verwenden der tokenbasierten Authentifizierung

  1. Wählen Sie Token aus.

  2. Geben Sie die folgenden Werte ein, die Sie zuvor erworben haben:

    • Schlüssel-ID
    • Bundle-ID
    • Team-ID
    • Token
  3. Wählen Sie Sandbox aus.

  4. Wählen Sie Speichern aus.

Konfigurieren Ihres Notification Hubs mit FCM-Informationen

  1. Wählen Sie im linken Menü im Abschnitt Einstellungen die Option Google (GCM/FCM) aus.
  2. Geben Sie den Serverschlüssel ein, den Sie sich in der Google Firebase-Konsole notiert haben.
  3. Wählen Sie auf der Symbolleiste Speichern aus.

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

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

Erstellen eines Webprojekts

  1. Wählen Sie in Visual StudioDatei>Neue Projektmappe aus.

  2. Wählen Sie .NETCore-App>>ASP.NET Core>API>Weiter aus.

  3. Wählen Sie im Dialogfeld Neue ASP.NET Core Web-API konfigurierendie Option Zielframework von .NET Core 3.1 aus.

  4. Geben Sie pushDemoApi als Projektname ein, und wählen Sie dann Erstellen aus.

  5. Starten Sie das Debuggen (Eingabetaste), + um die app mit Vorlagen zu testen.

    Hinweis

    Die app mit Vorlagen ist so konfiguriert, dass der WeatherForecastController als launchUrl verwendet wird. Dies wird unter Eigenschaften>launchSettings.json festgelegt.

    Wenn Sie zur Meldung Ungültiges Entwicklungszertifikat gefunden aufgefordert werden:

    1. Klicken Sie auf Ja , um der Ausführung des Tools "dotnet dev-certs https" zuzustimmen, um dies zu beheben. Das Tool "dotnet dev-certs https" fordert Sie dann auf, ein Kennwort für das Zertifikat und das Kennwort für Ihren Keychain einzugeben.

    2. Klicken Sie auf Ja , wenn Sie aufgefordert werden, das neue Zertifikat zu installieren und dem neuen Zertifikat zu vertrauen, und geben Sie dann das Kennwort für Ihren Schlüsselbund ein.

  6. Erweitern Sie den Ordner Controller , und löschen Sie dann WeatherForecastController.cs.

  7. Löschen Sie WeatherForecast.cs.

  8. Richten Sie lokale Konfigurationswerte mit dem Geheimnis-Manager-Tool ein. Durch das Entkoppeln der Geheimnisse von der Lösung wird sichergestellt, dass sie nicht in der Quellcodeverwaltung landen. Öffnen Sie Terminal , wechseln Sie dann zum Verzeichnis der Projektdatei, und führen Sie die folgenden 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 Ihren eigenen Notification Hub-Namen und Verbindungszeichenfolge Werte. Sie haben sich diese im Abschnitt Erstellen eines Notification Hubs notieren. Andernfalls können Sie sie in Azure nachschlagen.

    NotificationHub:Name:
    Weitere Informationen finden Sie unter Name in der Zusammenfassung der Grundlagen oben in der Übersicht.

    NotificationHub:ConnectionString:
    Weitere Informationen finden Sie unter DefaultFullSharedAccessSignature unter Zugriffsrichtlinien.

    Hinweis

    Für Produktionsszenarien können Sie Optionen wie Azure KeyVault anzeigen, um die Verbindungszeichenfolge sicher zu speichern. Der Einfachheit halber werden die Geheimnisse den Azure App Service Anwendungseinstellungen hinzugefügt.

Authentifizieren von Clients mithilfe eines API-Schlüssels (optional)

API-Schlüssel sind nicht so sicher wie Token, reichen aber für die Zwecke dieses Tutorials aus. Ein API-Schlüssel kann einfach über die ASP.NET Middleware konfiguriert werden.

  1. Fügen Sie den lokalen Konfigurationswerten den API-Schlüssel hinzu.

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

    Hinweis

    Ersetzen Sie den Platzhalterwert durch Ihren eigenen Wert, und notieren Sie sich ihn.

  2. Steuerung + Klicken Sie auf das Projekt PushDemoApi, wählen Sie im Menü Hinzufügen die Option Neuer Ordner aus, und klicken Sie dann auf Mithilfe der Authentifizierung als Ordnernamehinzufügen.

  3. Steuerung + Klicken Sie auf den Ordner Authentifizierung, und wählen Sie dann im Menü Hinzufügen die Option Neue Datei... aus.

  4. Wählen Sie Allgemein>Leere Klasse aus, geben Sie ApiKeyAuthOptions.cs als Name ein, und klicken Sie dann auf Neu , um die folgende Implementierung hinzuzufügen.

    using Microsoft.AspNetCore.Authentication;
    
    namespace PushDemoApi.Authentication
    {
        public class ApiKeyAuthOptions : AuthenticationSchemeOptions
        {
            public const string DefaultScheme = "ApiKey";
            public string Scheme => DefaultScheme;
            public string ApiKey { get; set; }
        }
    }
    
  5. Fügen Sie dem Authentifizierungsordnermit dem Namen ApiKeyAuthHandler.cs eine weitere leere Klasse hinzu, und fügen Sie dann die folgende Implementierung hinzu.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Claims;
    using System.Text.Encodings.Web;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    
    namespace PushDemoApi.Authentication
    {
        public class ApiKeyAuthHandler : AuthenticationHandler<ApiKeyAuthOptions>
        {
            const string ApiKeyIdentifier = "apikey";
    
            public ApiKeyAuthHandler(
                IOptionsMonitor<ApiKeyAuthOptions> options,
                ILoggerFactory logger,
                UrlEncoder encoder,
                ISystemClock clock)
                : base(options, logger, encoder, clock) {}
    
            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));
            }
        }
    }
    

    Hinweis

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

  6. Fügen Sie dem Authentifizierungsordner mit dem Namen ApiKeyAuthenticationBuilderExtensions.cs eine weitere leere Klasse hinzu, und fügen Sie dann die folgende Implementierung hinzu.

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

    Hinweis

    Diese Erweiterungsmethode vereinfacht den Middlewarekonfigurationscode in Startup.cs macht ihn lesbarer und im Allgemeinen einfacher zu befolgen.

  7. Aktualisieren Sie in Startup.cs die ConfigureServices-Methode , um die API-Schlüsselauthentifizierung unterhalb des Aufrufs der Dienste zu konfigurieren . AddControllers-Methode .

    using PushDemoApi.Authentication;
    using PushDemoApi.Models;
    using PushDemoApi.Services;
    
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
    
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = ApiKeyAuthOptions.DefaultScheme;
            options.DefaultChallengeScheme = ApiKeyAuthOptions.DefaultScheme;
        }).AddApiKeyAuth(Configuration.GetSection("Authentication").Bind);
    }
    
  8. Aktualisieren Sie noch in Startup.cs die Configure-Methode , um die Erweiterungsmethoden UseAuthentication und UseAuthorization für den IApplicationBuilder der App aufzurufen. Stellen Sie sicher, dass diese Methoden nach UseRouting und vor der App aufgerufen werden. UseEndpoints.

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
    
        app.UseHttpsRedirection();
    
        app.UseRouting();
    
        app.UseAuthentication();
    
        app.UseAuthorization();
    
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
    

    Hinweis

    Beim Aufrufen von UseAuthentication wird die Middleware registriert, die die zuvor registrierten Authentifizierungsschemas (von ConfigureServices) verwendet. Dies muss vor jeder Middleware aufgerufen werden, die von der Authentifizierung der Benutzer abhängt.

Hinzufügen von Abhängigkeiten und Konfigurieren von Diensten

ASP.NET Core unterstützt das Di-Softwareentwurfsmuster (Dependency Injection), ein Verfahren zum Erreichen der Inversion der Steuerung (Inversion of Control, IoC) zwischen Klassen und ihren Abhängigkeiten.

Die Verwendung des Notification Hubs und des Notification Hubs SDK für Back-End-Vorgänge wird in einem Dienst gekapselt. Der Dienst wird registriert und durch eine geeignete Abstraktion zur Verfügung gestellt.

  1. Steuerung + Klicken Sie auf den Ordner Abhängigkeiten , und wählen Sie NuGet-Pakete verwalten... aus.

  2. Suchen Sie nach Microsoft.Azure.NotificationHubs , und stellen Sie sicher, dass es aktiviert ist.

  3. Klicken Sie auf Pakete hinzufügen und dann auf Akzeptieren , wenn Sie aufgefordert werden, die Lizenzbedingungen zu akzeptieren.

  4. Steuerung + Klicken Sie auf das Projekt PushDemoApi, wählen Sie im Menü Hinzufügen die Option Neuer Ordner aus, und klicken Sie dann auf Mithilfe von Modellen als Ordnernamehinzufügen.

  5. Steuerung + Klicken Sie auf den Ordner Modelle, und wählen Sie dann im Menü Hinzufügendie Option Neue Datei... aus.

  6. Wählen Sie Allgemein>Leere Klasse aus, geben Sie als NamePushTemplates.cs ein, und klicken Sie dann auf Neu, um die folgende Implementierung hinzuzufügen.

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

    Hinweis

    Diese Klasse enthält die tokenisierten Benachrichtigungsnutzlasten für die generischen und unbeaufsichtigten Benachrichtigungen, die für dieses Szenario erforderlich sind. Die Nutzlasten werden außerhalb der Installation definiert, um Experimente zu ermöglichen, ohne vorhandene Installationen über den Dienst aktualisieren zu müssen. Die Verarbeitung von Änderungen an Installationen auf diese Weise ist für dieses Tutorial nicht vorgesehen. Für die Produktion sollten Sie benutzerdefinierte Vorlagen berücksichtigen.

  7. Fügen Sie dem Ordner Models mit dem Namen DeviceInstallation.cs eine weitere leere Klasse hinzu, und fügen Sie dann die folgende Implementierung hinzu.

    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    
    namespace PushDemoApi.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>();
        }
    }
    
  8. Fügen Sie dem Ordner Models mit dem Namen NotificationRequest.cs eine weitere leere Klasse hinzu, und fügen Sie dann die folgende Implementierung hinzu.

    using System;
    
    namespace PushDemoApi.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; }
        }
    }
    
  9. Fügen Sie dem Ordner Models mit dem Namen NotificationHubOptions.cs eine weitere leere Klasse hinzu, und fügen Sie dann die folgende Implementierung hinzu.

    using System.ComponentModel.DataAnnotations;
    
    namespace PushDemoApi.Models
    {
        public class NotificationHubOptions
        {
            [Required]
            public string Name { get; set; }
    
            [Required]
            public string ConnectionString { get; set; }
        }
    }
    
  10. Fügen Sie dem PushDemoApi-Projekt einen neuen Ordner mit dem Namen Services hinzu.

  11. Fügen Sie dem Ordner Dienste eine leere Schnittstelle mit dem Namen INotificationService.cs hinzu, und fügen Sie dann die folgende Implementierung hinzu.

    using System.Threading;
    using System.Threading.Tasks;
    using PushDemoApi.Models;
    
    namespace PushDemoApi.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);
        }
    }
    
  12. Fügen Sie dem Ordner Services eine leere Klasse mit dem Namen NotificationHubsService.cs hinzu, und fügen Sie dann den folgenden Code hinzu, um die INotificationService-Schnittstelle zu implementieren:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Azure.NotificationHubs;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    using PushDemoApi.Models;
    
    namespace PushDemoApi.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.Fcm).ToLower(), NotificationPlatform.Fcm }
                };
            }
    
            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.SendFcmNativeNotificationAsync(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.SendFcmNativeNotificationAsync(androidPayload, tags, token),
                    _hub.SendAppleNativeNotificationAsync(iOSPayload, tags, token)
                };
    
                return Task.WhenAll(sendTasks);
            }
        }
    }
    

    Hinweis

    Der für SendTemplateNotificationAsync bereitgestellte Tagausdruck ist auf 20 Tags beschränkt. Er ist für die meisten Operatoren auf 6 beschränkt, aber der Ausdruck enthält in diesem Fall nur ORs (||). Wenn die Anforderung mehr als 20 Tags enthält, müssen sie in mehrere Anforderungen unterteilt werden. Weitere Informationen finden Sie in der Dokumentation zu Routing- und Tagausdrücken .

  13. Aktualisieren Sie in Startup.cs die ConfigureServices-Methode , um NotificationHubsService als Singletonimplementierung von INotificationService hinzuzufügen.

    
    using PushDemoApi.Models;
    using PushDemoApi.Services;
    
    public void ConfigureServices(IServiceCollection services)
    {
        ...
    
        services.AddSingleton<INotificationService, NotificationHubService>();
    
        services.AddOptions<NotificationHubOptions>()
            .Configure(Configuration.GetSection("NotificationHub").Bind)
            .ValidateDataAnnotations();
    }
    

Erstellen der Benachrichtigungs-API

  1. Steuerung + Klicken Sie auf den Ordner Controller, und wählen Sie dann Im Menü Hinzufügen die Option Neue Datei... aus.

  2. Wählen Sie ASP.NET Core>Web-API-Controller-Klasse aus, geben Sie NotificationsController als Namen ein, und klicken Sie dann auf Neu.

    Hinweis

    Wenn Sie visual Studio 2019 verwenden, wählen Sie die Api Controller-Vorlage mit Lese-/Schreibaktionen aus.

  3. Fügen Sie die folgenden Namespaces am Anfang der Datei hinzu.

    using System.ComponentModel.DataAnnotations;
    using System.Net;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using PushDemoApi.Models;
    using PushDemoApi.Services;
    
  4. Aktualisieren Sie den vorlagenbasierten Controller so, dass er von ControllerBase abgeleitet wird und mit dem ApiController-Attribut versehen ist.

    [ApiController]
    [Route("api/[controller]")]
    public class NotificationsController : ControllerBase
    {
        // Templated methods here
    }
    

    Hinweis

    Die Controller-Basisklasse bietet Unterstützung für Ansichten, dies ist in diesem Fall jedoch nicht erforderlich, sodass stattdessen ControllerBase verwendet werden kann. Wenn Sie visual Studio 2019 verwenden, können Sie diesen Schritt überspringen.

  5. Wenn Sie den Abschnitt Authentifizieren von Clients mithilfe eines API-Schlüssels abgeschlossen haben, sollten Sie auch den NotificationsController mit dem Attribut Authorize versehen.

    [Authorize]
    
  6. Aktualisieren Sie den Konstruktor, um die registrierte instance von INotificationService als Argument zu akzeptieren, und weisen Sie es einem schreibgeschützten Member zu.

    readonly INotificationService _notificationService;
    
    public NotificationsController(INotificationService notificationService)
    {
        _notificationService = notificationService;
    }
    
  7. Ändern Sie in launchSettings.json (im Ordner Eigenschaften ) die launchUrl von in weatherforecastapi/notifications , um der URL zu entsprechen, die im Attribut "RegistrationsControllerRoute " angegeben ist.

  8. Starten Sie das Debuggen (Befehlseingabe + ), um zu überprüfen, ob die App mit dem neuen NotificationsController funktioniert, und gibt einen nicht autorisierten status 401 zurück.

    Hinweis

    Visual Studio startet die App möglicherweise nicht automatisch im Browser. Ab diesem Zeitpunkt verwenden Sie Postman , um die API zu testen.

  9. Legen Sie auf einer neuen Postman-Registerkarte die Anforderung auf GET fest. Geben Sie die folgende Adresse ein, und ersetzen Sie den Platzhalter <applicationUrl> durch den https applicationUrl in Properties>launchSettings.json.

    <applicationUrl>/api/notifications
    

    Hinweis

    ApplicationUrl sollte für das Standardprofil "https://localhost:5001" sein. Wenn Sie IIS verwenden (Standard in Visual Studio 2019 unter Windows), sollten Sie stattdessen die im element iisSettings angegebene applicationUrl verwenden. Sie erhalten eine Antwort 404, wenn die Adresse falsch ist.

  10. Wenn Sie den Abschnitt Authentifizieren von Clients mithilfe eines API-Schlüssels abgeschlossen haben, müssen Sie die Anforderungsheader so konfigurieren, dass sie Ihren apikey-Wert enthalten.

    Schlüssel Wert
    apikey <your_api_key>
  11. Klicken Sie auf die Schaltfläche Senden .

    Hinweis

    Sie sollten eine 200 OK-status mit JSON-Inhalten erhalten.

    Wenn Sie eine SSL-Zertifikatüberprüfungswarnung erhalten, können Sie die Postman-Einstellung SSL-Zertifikatüberprüfung der Anforderung in den Einstellungen deaktivieren.

  12. Ersetzen Sie die vorlagenbasierten Klassenmethoden in NotificationsController.cs 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)
    {
        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();
    }
    

Erstellen der API-App

Sie erstellen jetzt eine API-App in Azure App Service zum Hosten des Back-End-Diensts.

  1. Melden Sie sich beim Azure-Portal an.

  2. Klicken Sie auf Ressource erstellen, suchen Sie nach API-App, und wählen Sie sie aus, und klicken Sie dann auf Erstellen.

  3. Aktualisieren Sie die folgenden Felder, und klicken Sie dann auf Erstellen.

    App-Name:
    Geben Sie einen global eindeutigen Namen für die API-App ein.

    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.

    App Service Plan/Standort:
    Erstellen eines neuen App Service Plans

    Hinweis

    Ändern Sie von der Standardoption zu einem Plan, der SSL-Unterstützung enthält. Andernfalls müssen Sie beim Arbeiten mit der mobilen App die entsprechenden Schritte unternehmen, um zu verhindern , dass HTTP-Anforderungen blockiert werden.

    Application Insights:
    Behalten Sie die vorgeschlagene Option bei (eine neue Ressource wird mit diesem Namen erstellt), oder wählen Sie eine vorhandene Ressource aus.

  4. Navigieren Sie nach der Bereitstellung der API-App zu dieser Ressource.

  5. Notieren Sie sich die URL-Eigenschaft in der Zusammenfassung der Grundlagen oben in der Übersicht. Diese URL ist Ihr Back-End-Endpunkt , der später in diesem Tutorial verwendet wird.

    Hinweis

    Die URL verwendet den zuvor angegebenen API-App-Namen im Format https://<app_name>.azurewebsites.net.

  6. Wählen Sie in der Liste (unter Einstellungen) die Option Konfiguration aus.

  7. Klicken Sie für jede der folgenden Einstellungen auf Neue Anwendungseinstellung , um den Namen und einen Wert einzugeben, und klicken Sie dann auf OK.

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

    Hinweis

    Dies sind dieselben Einstellungen, die Sie zuvor in den Benutzereinstellungen definiert haben. Sie sollten in der Lage sein, diese zu kopieren. Die Einstellung Authentication:ApiKey ist nur erforderlich, wenn Sie den Abschnitt Authentifizieren von Clients mithilfe eines API-Schlüssels abgeschlossen haben. Für Produktionsszenarien können Sie Optionen wie Azure KeyVault anzeigen. Diese wurden der Einfachheit halber in diesem Fall als Anwendungseinstellungen hinzugefügt.

  8. Nachdem alle Anwendungseinstellungen hinzugefügt wurden, klicken Sie auf Speichern und dann auf Weiter.

Veröffentlichen des Back-End-Diensts

Als Nächstes stellen Sie die App in der API-App bereit, damit sie von allen Geräten aus zugänglich ist.

Hinweis

Die folgenden Schritte sind spezifisch für Visual Studio für Mac. Wenn Sie Visual Studio 2019 unter Windows verwenden, unterscheidet sich der Veröffentlichungsablauf. Weitere Informationen finden Sie unter Veröffentlichen in Azure App Service unter Windows.

  1. Ändern Sie Ihre Konfiguration von Debuggen in Release , wenn Sie dies noch nicht getan haben.

  2. Steuerung + Klicken Sie auf das Projekt PushDemoApi, und wählen Sie dann im Menü Veröffentlichen die Option In Azure veröffentlichen... aus.

  3. Befolgen Sie den Authentifizierungsflow, wenn Sie dazu aufgefordert werden. Verwenden Sie das Konto, das Sie im vorherigen Erstellen des Abschnitts API-App verwendet haben.

  4. Wählen Sie die Azure App Service API-App, die Sie zuvor erstellt haben, aus der Liste als Veröffentlichungsziel aus, und klicken Sie dann auf Veröffentlichen.

Nachdem Sie den Assistenten abgeschlossen haben, veröffentlicht er die App in Azure und öffnet dann die App. Notieren Sie sich die URL , falls Sie dies noch nicht getan haben. Diese URL ist Ihr Back-End-Endpunkt , der später in diesem Tutorial verwendet wird.

Überprüfen der veröffentlichten API

  1. Öffnen Sie in Postman eine neue Registerkarte, legen Sie die Anforderung auf PUT fest, und geben Sie die folgende Adresse ein. Ersetzen Sie den Platzhalter durch die Basisadresse, die Sie im vorherigen Abschnitt zum Veröffentlichen des Back-End-Diensts notieren haben.

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

    Hinweis

    Die Basisadresse sollte das Format aufweisen. https://<app_name>.azurewebsites.net/

  2. Wenn Sie den Abschnitt Authentifizieren von Clients mithilfe eines API-Schlüssels abgeschlossen haben, müssen Sie die Anforderungsheader so konfigurieren, dass sie Ihren apikey-Wert enthalten.

    Schlüssel Wert
    apikey <your_api_key>
  3. Wählen Sie die Raw-Option für den Text aus, wählen Sie dann JSON aus der Liste der Formatoptionen aus, und fügen Sie dann einige Platzhalter-JSON-Inhalte ein:

    {}
    
  4. Klicken Sie auf Send.

    Hinweis

    Sie sollten eine 422 UnprocessableEntity-status vom Dienst erhalten.

  5. Führen Sie die Schritte 1 bis 4 erneut aus, aber geben Sie diesmal den Anforderungsendpunkt an, um zu überprüfen, dass Sie eine Antwort mit 400 fehlerhaften Anforderungen erhalten.

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

Hinweis

Es ist noch nicht möglich, die API mit gültigen Anforderungsdaten zu testen, da dies plattformspezifische Informationen aus der mobilen Client-App erfordert.

Erstellen einer plattformübergreifenden Flutter-Anwendung

In diesem Abschnitt erstellen Sie eine mobile Flutter-Anwendung , die Pushbenachrichtigungen plattformübergreifend implementiert.

Sie können sich über den von Ihnen erstellten Back-End-Dienst bei einem Notification Hub registrieren und die Registrierung aufheben.

Eine Warnung wird angezeigt, wenn eine Aktion angegeben wird und sich die App im Vordergrund befindet. Andernfalls werden Benachrichtigungen im Notification Center angezeigt.

Hinweis

In der Regel führen Sie die Registrierungsaktionen (und die Registrierung aufheben) während des entsprechenden Punkts im Anwendungslebenszyklus (oder vielleicht als Teil Ihrer Ersten Ausführung) ohne explizite Benutzerregistrierungs-/Deregistrierungseingaben aus. Dieses Beispiel erfordert jedoch eine explizite Benutzereingabe, damit diese Funktionalität leichter untersucht und getestet werden kann.

Erstellen der Flutter-Lösung

  1. Öffnen Sie eine neue instance von Visual Studio Code.

  2. Öffnen Sie die Befehlspalette (Umschaltbefehl + + P).

  3. Wählen Sie den Befehl Flutter: Neues Projekt aus, und drücken Sie dann die EINGABETASTE.

  4. Geben Sie als Projektnamepush_demo ein, und wählen Sie dann einen Projektspeicherort aus.

  5. Wenn Sie dazu aufgefordert werden, wählen Sie Pakete abrufen aus.

  6. Steuerung + Klicken Sie auf den Ordner kotlin (unter app>src>Standard), und wählen Sie dann Im Finder anzeigen aus. Benennen Sie dann die untergeordneten Ordner (unter dem Ordner kotlin) in , <your_organization>bzwpushdemo. umcom.

    Hinweis

    Wenn Sie die Visual Studio Code-Vorlage verwenden, wird für diese Ordner standardmäßig com verwendet, z. B<. project_name>. Wenn mobcat für die organization verwendet wird, sollte die Ordnerstruktur indikativ wie folgt aussehen:

    • kotlin
      • Com
        • mobcat
          • pushdemo
  7. Aktualisieren Sie in Visual Studio Code den Wert applicationId in der Android-App>>build.gradle auf com.<your_organization>.pushdemo.

    Hinweis

    Sie sollten Ihren eigenen organization Namen für den <your_organization> Platzhalter verwenden. Die Verwendung von mobcat als organization führt beispielsweise zu einem Paketnamenswertvon com.mobcat.pushdemo.

  8. Aktualisieren Sie das Paketattribute in den AndroidManifest.xml-Dateien unter src>debug, src>Standard bzw. src-Profil>. Stellen Sie sicher, dass die Werte mit der applicationId übereinstimmen, die Sie im vorherigen Schritt verwendet haben.

    <manifest
        xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.<your_organization>.pushdemo>">
        ...
    </manifest>
    
  9. Aktualisieren Sie das android:label Attribut in der AndroidManifest.xml-Datei unter src>Standard in PushDemo. Fügen Sie dann das android:allowBackup Attribut direkt unter android:labelhinzu, und legen Sie seinen Wert auf false fest.

    <application
        android:name="io.flutter.app.FlutterApplication"
        android:label="PushDemo"
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher">
        ...
    </application>
    
  10. Öffnen Sie die Datei build.gradle auf App-Ebene (Android-App>>build.gradle), und aktualisieren Sie dann compileSdkVersion (aus dem Android-Abschnitt), um API 29 zu verwenden. Aktualisieren Sie dann die Werte minSdkVersion und targetSdkVersion (aus dem Abschnitt defaultConfig ) auf 26 bzw. 29 .

    Hinweis

    Nur Geräte mit API-Ebene 26 und höher werden für die Zwecke dieses Tutorials unterstützt. Sie können es jedoch erweitern, um Geräte zu unterstützen, auf denen ältere Versionen ausgeführt werden.

  11. Steuerung + Klicken Sie auf den Ordner ios , und wählen Sie dann In Xcode öffnen aus.

  12. Klicken Sie in Xcode auf Runner (das xcodeproj oben, nicht auf den Ordner). Wählen Sie dann das Ziel Runner aus, und wählen Sie die Registerkarte Allgemein aus. Aktualisieren Sie den Bundle-Bezeichnercom.<your_organization>.PushDemoauf, wenn die Konfiguration "Alle Build" ausgewählt ist.

    Hinweis

    Sie sollten Ihren eigenen organization Namen für den <your_organization> Platzhalter verwenden. Die Verwendung von mobcat als organization führt beispielsweise zu einem Bundle Identifier-Wert von com.mobcat.PushDemo.

  13. Klicken Sie auf Info.plist, und aktualisieren Sie den Wert des Bundlenamens auf PushDemo.

  14. Schließen Sie Xcode , und kehren Sie zu Visual Studio Code zurück.

  15. Öffnen Sie wieder in Visual Studio Codepubspec.yaml, fügen Sie die pakete http und flutter_secure_storageDart als Abhängigkeiten hinzu. Speichern Sie dann die Datei, und klicken Sie auf Pakete abrufen , wenn Sie dazu aufgefordert werden.

    dependencies:
      flutter:
        sdk: flutter
    
      http: ^0.12.1
      flutter_secure_storage: ^3.3.3
    
  16. Ändern Sie im Terminal das Verzeichnis in den Ordner ios (für Ihr Flutter-Projekt). Führen Sie dann den Befehl Podinstallation aus, um neue Pods zu installieren (erforderlich für das flutter_secure_storage-Paket ).

  17. Steuerung + Klicken Sie auf den Ordner lib , und wählen Sie dann Neue Datei aus dem Menü mit main_page.dart als Dateinamen aus. Fügen Sie dann den folgenden Code hinzu.

    import 'package:flutter/material.dart';
    
    class MainPage extends StatefulWidget {
      @override
      _MainPageState createState() => _MainPageState();
    }
    
    class _MainPageState extends State<MainPage> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: SafeArea(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[],
            )
          )
        );
      }
    }
    
  18. Ersetzen Sie in Standard.dart den vorlagenbasierten Code durch Folgendes.

    import 'package:flutter/material.dart';
    import 'package:push_demo/main_page.dart';
    
    final navigatorKey = GlobalKey<NavigatorState>();
    
    void main() => runApp(MaterialApp(home: MainPage(), navigatorKey: navigatorKey));
    
  19. Erstellen und führen Sie die App im Terminal auf jeder Zielplattform aus, um die Ausführung der app-Vorlagen auf Ihrem(n) Gerät(n) zu testen. Stellen Sie sicher, dass unterstützte Geräte verbunden sind.

    flutter run
    

Implementieren der plattformübergreifenden Komponenten

  1. Steuerung + Klicken Sie auf den Ordner lib, und wählen Sie dann Im Menü mit Modellen als Ordnername die Option Neuer Ordner aus.

  2. Steuerung + Klicken Sie auf den Ordner models , und wählen Sie dann Neue Datei im Menü aus, indem Sie device_installation.dart als Dateinamen verwenden. Fügen Sie dann den folgenden Code hinzu.

    class DeviceInstallation {
        final String deviceId;
        final String platform;
        final String token;
        final List<String> tags;
    
        DeviceInstallation(this.deviceId, this.platform, this.token, this.tags);
    
        DeviceInstallation.fromJson(Map<String, dynamic> json)
          : deviceId = json['installationId'],
            platform = json['platform'],
            token = json['pushChannel'],
            tags = json['tags'];
    
        Map<String, dynamic> toJson() =>
        {
          'installationId': deviceId,
          'platform': platform,
          'pushChannel': token,
          'tags': tags,
        };
    }
    
  3. Fügen Sie dem Ordner models eine neue Datei mit dem Namen push_demo_action.dart hinzu, um die Enumeration der in diesem Beispiel unterstützten Aktionen zu definieren.

    enum PushDemoAction {
      actionA,
      actionB,
    }
    
  4. Fügen Sie dem Projekt einen neuen Ordner namens Services hinzu, und fügen Sie dann mit der folgenden Implementierung eine neue Datei mit dem Namen device_installation_service.dart zu diesem Ordner hinzu.

    import 'package:flutter/services.dart';
    
    class DeviceInstallationService {
      static const deviceInstallation = const MethodChannel('com.<your_organization>.pushdemo/deviceinstallation');
      static const String getDeviceIdChannelMethod = "getDeviceId";
      static const String getDeviceTokenChannelMethod = "getDeviceToken";
      static const String getDevicePlatformChannelMethod = "getDevicePlatform";
    
      Future<String> getDeviceId() {
        return deviceInstallation.invokeMethod(getDeviceIdChannelMethod);
      }
    
      Future<String> getDeviceToken() {
        return deviceInstallation.invokeMethod(getDeviceTokenChannelMethod);
      }
    
      Future<String> getDevicePlatform() {
        return deviceInstallation.invokeMethod(getDevicePlatformChannelMethod);
      }
    }
    

    Hinweis

    Sie sollten Ihren eigenen organization Namen für den <your_organization> Platzhalter verwenden. Die Verwendung von mobcat als organization führt beispielsweise zu einem MethodChannel-Namenvon com.mobcat.pushdemo/deviceinstallation.

    Diese Klasse kapselt die Arbeit mit der zugrunde liegenden nativen Plattform, um die erforderlichen Geräteinstallationsdetails zu erhalten. Ein MethodChannel erleichtert die bidirektionale asynchrone Kommunikation mit den zugrunde liegenden nativen Plattformen. Das plattformspezifische Pendant für diesen Kanal wird in den späteren Schritten erstellt.

  5. Fügen Sie diesem Ordner mit der folgenden Implementierung eine weitere Datei namens notification_action_service.dart hinzu.

    import 'package:flutter/services.dart';
    import 'dart:async';
    import 'package:push_demo/models/push_demo_action.dart';
    
    class NotificationActionService {
      static const notificationAction =
          const MethodChannel('com.<your_organization>.pushdemo/notificationaction');
      static const String triggerActionChannelMethod = "triggerAction";
      static const String getLaunchActionChannelMethod = "getLaunchAction";
    
      final actionMappings = {
        'action_a' : PushDemoAction.actionA,
        'action_b' : PushDemoAction.actionB
      };
    
      final actionTriggeredController = StreamController.broadcast();
    
      NotificationActionService() {
        notificationAction
            .setMethodCallHandler(handleNotificationActionCall);
      }
    
      Stream get actionTriggered => actionTriggeredController.stream;
    
      Future<void> triggerAction({action: String}) async {
    
        if (!actionMappings.containsKey(action)) {
          return;
        }
    
        actionTriggeredController.add(actionMappings[action]);
      }
    
      Future<void> checkLaunchAction() async {
        final launchAction = await notificationAction.invokeMethod(getLaunchActionChannelMethod) as String;
    
        if (launchAction != null) {
          triggerAction(action: launchAction);
        }
      }
    
      Future<void> handleNotificationActionCall(MethodCall call) async {
        switch (call.method) {
          case triggerActionChannelMethod:
            return triggerAction(action: call.arguments as String);
          default:
            throw MissingPluginException();
            break;
        }
      }
    }
    

    Hinweis

    Dies wird als einfacher Mechanismus verwendet, um die Verarbeitung von Benachrichtigungsaktionen zu zentralisieren, sodass diese plattformübergreifend mithilfe einer stark typisierten Enumeration verarbeitet werden können. Der Dienst ermöglicht es der zugrunde liegenden nativen Plattform, eine Aktion auszulösen, wenn eine in der Benachrichtigungsnutzlast angegeben ist. Außerdem kann der allgemeine Code rückwirkend überprüfen, ob eine Aktion während des Anwendungsstarts angegeben wurde, sobald Flutter bereit ist, sie zu verarbeiten. Beispielsweise, wenn die App gestartet wird, indem Sie im Notification Center auf eine Benachrichtigung tippen.

  6. Fügen Sie dem Dienstordnernotification_registration_service.dart mit der folgenden Implementierung eine neue Datei hinzu.

    import 'dart:convert';
    import 'package:flutter/services.dart';
    import 'package:http/http.dart' as http;
    import 'package:push_demo/services/device_installation_service.dart';
    import 'package:push_demo/models/device_installation.dart';
    import 'package:flutter_secure_storage/flutter_secure_storage.dart';
    
    class NotificationRegistrationService {
      static const notificationRegistration =
          const MethodChannel('com.<your_organization>.pushdemo/notificationregistration');
    
      static const String refreshRegistrationChannelMethod = "refreshRegistration";
      static const String installationsEndpoint = "api/notifications/installations";
      static const String cachedDeviceTokenKey = "cached_device_token";
      static const String cachedTagsKey = "cached_tags";
    
      final deviceInstallationService = DeviceInstallationService();
      final secureStorage = FlutterSecureStorage();
    
      String baseApiUrl;
      String apikey;
    
      NotificationRegistrationService(this.baseApiUrl, this.apikey) {
        notificationRegistration
            .setMethodCallHandler(handleNotificationRegistrationCall);
      }
    
      String get installationsUrl => "$baseApiUrl$installationsEndpoint";
    
      Future<void> deregisterDevice() async {
        final cachedToken = await secureStorage.read(key: cachedDeviceTokenKey);
        final serializedTags = await secureStorage.read(key: cachedTagsKey);
    
        if (cachedToken == null || serializedTags == null) {
          return;
        }
    
        var deviceId = await deviceInstallationService.getDeviceId();
    
        if (deviceId.isEmpty) {
          throw "Unable to resolve an ID for the device.";
        }
    
        var response = await http
            .delete("$installationsUrl/$deviceId", headers: {"apikey": apikey});
    
        if (response.statusCode != 200) {
          throw "Deregister request failed: ${response.reasonPhrase}";
        }
    
        await secureStorage.delete(key: cachedDeviceTokenKey);
        await secureStorage.delete(key: cachedTagsKey);
      }
    
      Future<void> registerDevice(List<String> tags) async {
        try {
          final deviceId = await deviceInstallationService.getDeviceId();
          final platform = await deviceInstallationService.getDevicePlatform();
          final token = await deviceInstallationService.getDeviceToken();
    
          final deviceInstallation =
              DeviceInstallation(deviceId, platform, token, tags);
    
          final response = await http.put(installationsUrl,
              body: jsonEncode(deviceInstallation),
              headers: {"apikey": apikey, "Content-Type": "application/json"});
    
          if (response.statusCode != 200) {
            throw "Register request failed: ${response.reasonPhrase}";
          }
    
          final serializedTags = jsonEncode(tags);
    
          await secureStorage.write(key: cachedDeviceTokenKey, value: token);
          await secureStorage.write(key: cachedTagsKey, value: serializedTags);
        } on PlatformException catch (e) {
          throw e.message;
        } catch (e) {
          throw "Unable to register device: $e";
        }
      }
    
      Future<void> refreshRegistration() async {
        final currentToken = await deviceInstallationService.getDeviceToken();
        final cachedToken = await secureStorage.read(key: cachedDeviceTokenKey);
        final serializedTags = await secureStorage.read(key: cachedTagsKey);
    
        if (currentToken == null ||
            cachedToken == null ||
            serializedTags == null ||
            currentToken == cachedToken) {
          return;
        }
    
        final tags = jsonDecode(serializedTags);
    
        return registerDevice(tags);
      }
    
      Future<void> handleNotificationRegistrationCall(MethodCall call) async {
        switch (call.method) {
          case refreshRegistrationChannelMethod:
            return refreshRegistration();
          default:
            throw MissingPluginException();
            break;
        }
      }
    }
    

    Hinweis

    Diese Klasse kapselt die Verwendung von DeviceInstallationService und die Anforderungen an den Back-End-Dienst zum Ausführen der erforderlichen Registrierungs-, Deregistrierungs- und Aktualisierungsaktionen. Das apiKey-Argument ist nur erforderlich, wenn Sie den Abschnitt Authentifizieren von Clients mithilfe eines API-Schlüssels abgeschlossen haben.

  7. Fügen Sie dem lib-Ordnerconfig.dart mit der folgenden Implementierung eine neue Datei hinzu.

    class Config {
      static String apiKey = "API_KEY";
      static String backendServiceEndpoint = "BACKEND_SERVICE_ENDPOINT";
    }
    

    Hinweis

    Dies wird als einfache Möglichkeit zum Definieren von App-Geheimnissen verwendet. Ersetzen Sie die Platzhalterwerte durch Ihre eigenen Werte. Sie sollten sich diese beim Erstellen des Back-End-Diensts notieren. Die API-App-URL sollte sein https://<api_app_name>.azurewebsites.net/. Das apiKey-Element ist nur erforderlich, wenn Sie den Abschnitt Authentifizieren von Clients mithilfe eines API-Schlüssels abgeschlossen haben.

    Fügen Sie dies ihrer gitignore-Datei hinzu, um zu vermeiden, dass diese Geheimnisse an die Quellcodeverwaltung übergeben werden.

Implementieren der plattformübergreifenden Benutzeroberfläche

  1. Ersetzen Sie in main_page.dart die Buildfunktion durch Folgendes.

    @override
    Widget build(BuildContext context) {
    return Scaffold(
        body: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 40.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.end,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              FlatButton(
                child: Text("Register"),
                onPressed: registerButtonClicked,
              ),
              FlatButton(
                child: Text("Deregister"),
                onPressed: deregisterButtonClicked,
              ),
            ],
          ),
        ),
      );
    }
    
  2. Fügen Sie die erforderlichen Importe oben in der Datei main_page.dart hinzu.

    import 'package:push_demo/services/notification_registration_service.dart';
    import 'config.dart';
    
  3. Fügen Sie der _MainPageState-Klasse ein Feld hinzu, um einen Verweis auf den NotificationRegistrationService zu speichern.

    final notificationRegistrationService = NotificationRegistrationService(Config.backendServiceEndpoint, Config.apiKey);
    
  4. Implementieren Sie in der _MainPageState-Klasse die Ereignishandler für die Schaltflächen Registrieren und Registrieren aufhebenfür Komprimierte Ereignisse. Rufen Sie die entsprechendenRegister-Deregistrierungsmethoden/ auf, und zeigen Sie dann eine Warnung an, um das Ergebnis anzugeben.

    void registerButtonClicked() async {
        try {
          await notificationRegistrationService.registerDevice(List<String>());
          await showAlert(message: "Device registered");
        }
        catch (e) {
          await showAlert(message: e);
        }
      }
    
      void deregisterButtonClicked() async {
        try {
          await notificationRegistrationService.deregisterDevice();
          await showAlert(message: "Device deregistered");
        }
        catch (e) {
          await showAlert(message: e);
        }
      }
    
      Future<void> showAlert({ message: String }) async {
        return showDialog<void>(
          context: context,
          barrierDismissible: false,
          builder: (BuildContext context) {
            return AlertDialog(
              title: Text('PushDemo'),
              content: SingleChildScrollView(
                child: ListBody(
                  children: <Widget>[
                    Text(message),
                  ],
                ),
              ),
              actions: <Widget>[
                FlatButton(
                  child: Text('OK'),
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                ),
              ],
            );
          },
        );
      }
    
  5. Stellen Sie nun in Standard.dart sicher, dass die folgenden Importe oben in der Datei vorhanden sind.

    import 'package:flutter/material.dart';
    import 'package:push_demo/models/push_demo_action.dart';
    import 'package:push_demo/services/notification_action_service.dart';
    import 'package:push_demo/main_page.dart';
    
  6. Deklarieren Sie eine Variable, um den Verweis auf eine instance von NotificationActionService zu speichern, und initialisieren Sie sie.

    final notificationActionService = NotificationActionService();
    
  7. Fügen Sie Funktionen hinzu, um die Anzeige einer Warnung zu behandeln, wenn eine Aktion ausgelöst wird.

    void notificationActionTriggered(PushDemoAction action) {
      showActionAlert(message: "${action.toString().split(".")[1]} action received");
    }
    
    Future<void> showActionAlert({ message: String }) async {
      return showDialog<void>(
        context: navigatorKey.currentState.overlay.context,
        barrierDismissible: false,
        builder: (BuildContext context) {
          return AlertDialog(
            title: Text('PushDemo'),
            content: SingleChildScrollView(
              child: ListBody(
                children: <Widget>[
                  Text(message),
                ],
              ),
            ),
            actions: <Widget>[
              FlatButton(
                child: Text('OK'),
                onPressed: () {
                  Navigator.of(context).pop();
                },
              ),
            ],
          );
        },
      );
    }
    
  8. Aktualisieren Sie die Standard-Funktion, um die NotificationActionService-AktionTriggered-Stream zu beobachten, und überprüfen Sie, ob alle Aktionen während des App-Starts erfasst werden.

    void main() async {
      runApp(MaterialApp(home: MainPage(), navigatorKey: navigatorKey,));
      notificationActionService.actionTriggered.listen((event) { notificationActionTriggered(event as PushDemoAction); });
      await notificationActionService.checkLaunchAction();
    }
    

    Hinweis

    Dies ist einfach, um den Empfang und die Weitergabe von Pushbenachrichtigungsaktionen zu veranschaulichen. In der Regel werden diese im Hintergrund behandelt, z. B. beim Navigieren zu einer bestimmten Ansicht oder beim Aktualisieren einiger Daten, anstatt in diesem Fall eine Warnung anzuzeigen.

Konfigurieren des nativen Android-Projekts für Pushbenachrichtigungen

Hinzufügen der JSON-Datei von Google Services

  1. Steuerung + Klicken Sie auf den Android-Ordner , und wählen Sie dann In Android Studio öffnen aus. Wechseln Sie dann zur Projektansicht (sofern noch nicht vorhanden).

  2. Suchen Sie die google-services.json-Datei , die Sie zuvor heruntergeladen haben, als Sie das PushDemo-Projekt in der Firebase-Konsole eingerichtet haben. Ziehen Sie es dann in das Stammverzeichnis des App-Moduls (Android-Android-App>).>

Konfigurieren von Buildeinstellungen und -berechtigungen

  1. Wechseln Sie die Projektansicht auf Android.

  2. Öffnen Sie AndroidManifest.xml, fügen Sie dann das INTERNET hinzu und READ_PHONE_STATE Berechtigungen nach dem Anwendungselement vor dem schließenden Tag.

    <manifest>
        <application>...</application>
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    </manifest>
    

Hinzufügen der Firebase-SDKs

  1. Öffnen Sie in Android Studio die Datei build.gradle auf Projektebene (Gradle Scripts>build.gradle (Project: android)). und stellen Sie sicher, dass Sie über den Klassenpfad "com.google.gms:google-services" im buildscript>Knoten "Abhängigkeiten " verfügen.

    buildscript {
    
      repositories {
        // Check that you have the following line (if not, add it):
        google()  // Google's Maven repository
      }
    
      dependencies {
        // ...
    
        // Add the following line:
        classpath 'com.google.gms:google-services:4.3.3'  // Google Services plugin
      }
    }
    
    allprojects {
      // ...
    
      repositories {
        // Check that you have the following line (if not, add it):
        google()  // Google's Maven repository
        // ...
      }
    }
    

    Hinweis

    Stellen Sie sicher, dass Sie gemäß den Anweisungen in der Firebase-Konsole beim Erstellen des Android-Projekts auf die neueste Version verweisen.

  2. Wenden Sie in der Datei build.gradle auf App-Ebene (Gradle Scripts>build.gradle (Modul: app)) das Google Services Gradle-Plug-In an. Wenden Sie das Plug-In direkt über dem Android-Knoten an.

    // ...
    
    // Add the following line:
    apply plugin: 'com.google.gms.google-services'  // Google Services plugin
    
    android {
      // ...
    }
    
  3. Fügen Sie in derselben Datei im Knoten "Abhängigkeiten" die Abhängigkeit für die Cloud Messaging-Android-Bibliothek hinzu.

    dependencies {
        // ...
        implementation 'com.google.firebase:firebase-messaging:20.2.0'
    }
    

    Hinweis

    Stellen Sie sicher, dass Sie auf die neueste Version gemäß der Cloud Messaging Android-Clientdokumentation verweisen.

  4. Speichern Sie die Änderungen, und klicken Sie dann auf die Schaltfläche Jetzt synchronisieren (in der Symbolleistenaufforderung) oder Auf Projekt mit Gradle-Dateien synchronisieren.

Behandeln von Pushbenachrichtigungen für Android

  1. Klicken Sie in Android Studiomit Steuerelement + Klicken Sie auf den Paketordner com.your_organization.pushdemo<> (app>src>Standard>kotlin), und wählen Sie im Menü Neu die Option Paket aus. Geben Sie Dienste als Namen ein, und drücken Sie dann die EINGABETASTE.

  2. Steuerung + Klicken Sie auf den Ordner dienste , und wählen Sie kotlin File/Class aus dem Menü Neu aus. Geben Sie DeviceInstallationService als Namen ein, und drücken Sie dann die EINGABETASTE.

  3. Implementieren Sie DeviceInstallationService mithilfe des folgenden Codes.

    package com.<your_organization>.pushdemo.services
    
    import android.annotation.SuppressLint
    import android.content.Context
    import android.provider.Settings.Secure
    import com.google.android.gms.common.ConnectionResult
    import com.google.android.gms.common.GoogleApiAvailability
    import io.flutter.embedding.engine.FlutterEngine
    import io.flutter.plugin.common.MethodCall
    import io.flutter.plugin.common.MethodChannel
    
    @SuppressLint("HardwareIds")
    class DeviceInstallationService {
    
        companion object {
            const val DEVICE_INSTALLATION_CHANNEL = "com.<your_organization>.pushdemo/deviceinstallation"
            const val GET_DEVICE_ID = "getDeviceId"
            const val GET_DEVICE_TOKEN = "getDeviceToken"
            const val GET_DEVICE_PLATFORM = "getDevicePlatform"
        }
    
        private var context: Context
        private var deviceInstallationChannel : MethodChannel
    
        val playServicesAvailable
            get() = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS
    
        constructor(context: Context, flutterEngine: FlutterEngine) {
            this.context = context
            deviceInstallationChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, DEVICE_INSTALLATION_CHANNEL)
            deviceInstallationChannel.setMethodCallHandler { call, result -> handleDeviceInstallationCall(call, result) }
        }
    
        fun getDeviceId() : String
            = Secure.getString(context.applicationContext.contentResolver, Secure.ANDROID_ID)
    
        fun getDeviceToken() : String {
            if(!playServicesAvailable) {
                throw Exception(getPlayServicesError())
            }
    
            // TODO: Revisit once we have created the PushNotificationsFirebaseMessagingService
            val token = "Placeholder_Get_Value_From_FirebaseMessagingService_Implementation"
    
            if (token.isNullOrBlank()) {
                throw Exception("Unable to resolve token for FCM.")
            }
    
            return token
        }
    
        fun getDevicePlatform() : String = "fcm"
    
        private fun handleDeviceInstallationCall(call: MethodCall, result: MethodChannel.Result) {
            when (call.method) {
                GET_DEVICE_ID -> {
                    result.success(getDeviceId())
                }
                GET_DEVICE_TOKEN -> {
                    getDeviceToken(result)
                }
                GET_DEVICE_PLATFORM -> {
                    result.success(getDevicePlatform())
                }
                else -> {
                    result.notImplemented()
                }
            }
        }
    
        private fun getDeviceToken(result: MethodChannel.Result) {
            try {
                val token = getDeviceToken()
                result.success(token)
            }
            catch (e: Exception) {
                result.error("ERROR", e.message, e)
            }
        }
    
        private fun getPlayServicesError(): String {
            val resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context)
    
            if (resultCode != ConnectionResult.SUCCESS) {
                return if (GoogleApiAvailability.getInstance().isUserResolvableError(resultCode)){
                    GoogleApiAvailability.getInstance().getErrorString(resultCode)
                } else {
                    "This device is not supported"
                }
            }
    
            return "An error occurred preventing the use of push notifications"
        }
    }
    

    Hinweis

    Diese Klasse implementiert das plattformspezifische Pendant für den com.<your_organization>.pushdemo/deviceinstallation Kanal. Dies wurde im Bereich "Flutter" der App in DeviceInstallationService.dart definiert. In diesem Fall werden die Aufrufe vom allgemeinen Code an den nativen Host ausgeführt. Ersetzen Sie <unbedingt your_organization> durch Ihre eigenen organization, wo immer dies verwendet wird.

    Diese Klasse stellt eine eindeutige ID (mit Secure.AndroidId) als Teil der Notification Hub-Registrierungsnutzlast bereit.

  4. Fügen Sie dem DienstordnerNotificationRegistrationService eine weitere Kotlin-Datei/Klasse hinzu, und fügen Sie dann den folgenden Code hinzu.

    package com.<your_organization>.pushdemo.services
    
    import io.flutter.embedding.engine.FlutterEngine
    import io.flutter.plugin.common.MethodChannel
    
    class NotificationRegistrationService {
    
        companion object {
            const val NOTIFICATION_REGISTRATION_CHANNEL = "com.<your_organization>.pushdemo/notificationregistration"
            const val REFRESH_REGISTRATION = "refreshRegistration"
        }
    
        private var notificationRegistrationChannel : MethodChannel
    
        constructor(flutterEngine: FlutterEngine) {
            notificationRegistrationChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, NotificationRegistrationService.NOTIFICATION_REGISTRATION_CHANNEL)
        }
    
        fun refreshRegistration() {
            notificationRegistrationChannel.invokeMethod(REFRESH_REGISTRATION, null)
        }
    }
    

    Hinweis

    Diese Klasse implementiert das plattformspezifische Pendant für den com.<your_organization>.pushdemo/notificationregistration Kanal. Dies wurde im Bereich "Flutter" der App in NotificationRegistrationService.dart definiert. In diesem Fall werden die Aufrufe vom nativen Host an den allgemeinen Code ausgeführt. Achten Sie auch hier darauf, your_organization> durch Ihre eigenen organization zu ersetzen<, wo immer dies verwendet wird.

  5. Fügen Sie dem DienstordnerNotificationActionService eine weitere Kotlin-Datei/Klasse hinzu, und fügen Sie dann den folgenden Code hinzu.

    package com.<your_organization>.pushdemo.services
    
    import io.flutter.embedding.engine.FlutterEngine
    import io.flutter.plugin.common.MethodCall
    import io.flutter.plugin.common.MethodChannel
    
    class NotificationActionService {
        companion object {
            const val NOTIFICATION_ACTION_CHANNEL = "com.<your_organization>.pushdemo/notificationaction"
            const val TRIGGER_ACTION = "triggerAction"
            const val GET_LAUNCH_ACTION = "getLaunchAction"
        }
    
        private var notificationActionChannel : MethodChannel
        var launchAction : String? = null
    
        constructor(flutterEngine: FlutterEngine) {
            notificationActionChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, NotificationActionService.NOTIFICATION_ACTION_CHANNEL)
            notificationActionChannel.setMethodCallHandler { call, result -> handleNotificationActionCall(call, result) }
        }
    
        fun triggerAction(action: String) {
            notificationActionChannel.invokeMethod(NotificationActionService.TRIGGER_ACTION, action)
        }
    
        private fun handleNotificationActionCall(call: MethodCall, result: MethodChannel.Result) {
            when (call.method) {
                NotificationActionService.GET_LAUNCH_ACTION -> {
                    result.success(launchAction)
                }
                else -> {
                    result.notImplemented()
                }
            }
        }
    }
    

    Hinweis

    Diese Klasse implementiert das plattformspezifische Pendant für den com.<your_organization>.pushdemo/notificationaction Kanal. Dies wurde im Flutter-Teil der App in NotificationActionService.dart definiert. Anrufe können in diesem Fall in beide Richtungen erfolgen. Ersetzen Sie <unbedingt your_organization> durch Ihre eigenen organization, wo immer dies verwendet wird.

  6. Fügen Sie dem com.your_organization.pushdemo-Paket<> eine neue Kotlin-Datei/Klasse namens PushNotificationsFirebaseMessagingService hinzu, und implementieren Sie dann den folgenden Code.

    package com.<your_organization>.pushdemo
    
    import android.os.Handler
    import android.os.Looper
    import com.google.firebase.messaging.FirebaseMessagingService
    import com.google.firebase.messaging.RemoteMessage
    import com.<your_organization>.pushdemo.services.NotificationActionService
    import com.<your_organization>.pushdemo.services.NotificationRegistrationService
    
    class PushNotificationsFirebaseMessagingService : FirebaseMessagingService() {
    
        companion object {
            var token : String? = null
            var notificationRegistrationService : NotificationRegistrationService? = null
            var notificationActionService : NotificationActionService? = null
        }
    
        override fun onNewToken(token: String) {
            PushNotificationsFirebaseMessagingService.token = token
            notificationRegistrationService?.refreshRegistration()
        }
    
        override fun onMessageReceived(message: RemoteMessage) {
            message.data.let {
                Handler(Looper.getMainLooper()).post {
                    notificationActionService?.triggerAction(it.getOrDefault("action", null))
                }
            }
        }
    }
    

    Hinweis

    Diese Klasse ist für die Verarbeitung von Benachrichtigungen zuständig, wenn die App im Vordergrund ausgeführt wird. Es ruft die triggerAction für den NotificationActionService bedingt auf, wenn eine Aktion in der Benachrichtigungsnutzlast enthalten ist, die in onMessageReceived empfangen wird. Dadurch wird auch refreshRegistration für den NotificationRegistrationService aufgerufen, wenn das Firebase-Token durch Überschreiben der onNewToken-Funktion neu generiert wird.

    Achten Sie erneut darauf, your_organization> durch Ihre eigene organization zu ersetzen<, wo immer sie verwendet wird.

  7. Fügen Sie inAndroidManifest.xml (app>src>Standard) den PushNotificationsFirebaseMessagingService am unteren Rand des Anwendungselements mit dem com.google.firebase.MESSAGING_EVENT Absichtsfilter hinzu.

    <manifest>
        <application>
            <!-- EXISTING MANIFEST CONTENT -->
             <service
                android:name="com.<your_organization>.pushdemo.PushNotificationsFirebaseMessagingService"
                android:exported="false">
                <intent-filter>
                    <action android:name="com.google.firebase.MESSAGING_EVENT" />
                </intent-filter>
            </service>
        </application>
    </manifest>
    
  8. Zurück in DeviceInstallationService stellen Sie sicher, dass die folgenden Importe oben in der Datei vorhanden sind.

    package com.<your_organization>.pushdemo
    import com.<your_organization>.pushdemo.services.PushNotificationsFirebaseMessagingService
    

    Hinweis

    Ersetzen Sie <your_organization> durch Ihren eigenen organization Wert.

  9. Aktualisieren Sie den Platzhaltertext Placeholder_Get_Value_From_FirebaseMessagingService_Implementation , um den Tokenwert von PushNotificationFirebaseMessagingService abzurufen.

    fun getDeviceToken() : String {
        if(!playServicesAvailable) {
            throw Exception(getPlayServicesError())
        }
    
        // Get token from the PushNotificationsFirebaseMessagingService.token field.
        val token = PushNotificationsFirebaseMessagingService.token
    
        if (token.isNullOrBlank()) {
            throw Exception("Unable to resolve token for FCM.")
        }
    
        return token
    }
    
  10. Stellen Sie in MainActivity sicher, dass die folgenden Importe oben in der Datei vorhanden sind.

    package com.<your_organization>.pushdemo
    
    import android.content.Intent
    import android.os.Bundle
    import com.google.android.gms.tasks.OnCompleteListener
    import com.google.firebase.iid.FirebaseInstanceId
    import com.<your_organization>.pushdemo.services.DeviceInstallationService
    import com.<your_organization>.pushdemo.services.NotificationActionService
    import com.<your_organization>.pushdemo.services.NotificationRegistrationService
    import io.flutter.embedding.android.FlutterActivity
    

    Hinweis

    Ersetzen Sie <your_organization> durch Ihren eigenen organization Wert.

  11. Fügen Sie eine Variable hinzu, um einen Verweis auf DeviceInstallationService zu speichern.

    private lateinit var deviceInstallationService: DeviceInstallationService
    
  12. Fügen Sie eine Funktion namens processNotificationActions hinzu, um zu überprüfen, ob eine Absicht über einen zusätzlichen Wert namens action verfügt. Lösen Sie diese Aktion bedingt aus, oder speichern Sie sie zur späteren Verwendung, wenn die Aktion während des App-Starts verarbeitet wird.

     private fun processNotificationActions(intent: Intent, launchAction: Boolean = false) {
        if (intent.hasExtra("action")) {
            var action = intent.getStringExtra("action");
    
            if (action.isNotEmpty()) {
                if (launchAction) {
                    PushNotificationsFirebaseMessagingService.notificationActionService?.launchAction = action
                }
                else {
                    PushNotificationsFirebaseMessagingService.notificationActionService?.triggerAction(action)
                }
            }
        }
    }
    
  13. Überschreiben Sie die onNewIntent-Funktion , um processNotificationActions aufzurufen.

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        processNotificationActions(intent)
    }
    

    Hinweis

    Da LaunchMode für MainActivity auf SingleTop festgelegt ist, wird eine Absicht über die onNewIntent-Funktion und nicht über die onCreate-Funktion an die vorhandene Aktivität instance gesendet. Daher müssen Sie eine eingehende Absicht sowohl in den Funktionen onCreate als auch onNewIntent behandeln.

  14. Überschreiben Sie die onCreate-Funktion, und legen Sie deviceInstallationService auf eine neue instance von DeviceInstallationService fest.

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        flutterEngine?.let {
            deviceInstallationService = DeviceInstallationService(context, it)
        }
    }
    
  15. Legen Sie die Eigenschaften notificationActionService und notificationRegistrationService für PushNotificationFirebaseMessagingServices fest.

    flutterEngine?.let {
      deviceInstallationService = DeviceInstallationService(context, it)
      PushNotificationsFirebaseMessagingService.notificationActionService = NotificationActionService(it)
      PushNotificationsFirebaseMessagingService.notificationRegistrationService = NotificationRegistrationService(it)
    }
    
  16. Rufen Sie in derselben Funktion bedingt FirebaseInstanceId.getInstance().instanceId auf. Implementieren Sie OnCompleteListener , um den resultierenden Tokenwert auf PushNotificationFirebaseMessagingService festzulegen, bevor sie refreshRegistration aufrufen.

    if(deviceInstallationService?.playServicesAvailable) {
        FirebaseInstanceId.getInstance().instanceId
            .addOnCompleteListener(OnCompleteListener { task ->
                if (!task.isSuccessful)
                    return@OnCompleteListener
    
                PushNotificationsFirebaseMessagingService.token = task.result?.token
                PushNotificationsFirebaseMessagingService.notificationRegistrationService?.refreshRegistration()
            })
    }
    
  17. Rufen Sie noch onCreate auf, rufen Sie processNotificationActions am Ende der Funktion auf. Verwenden Sie true für das argument launchAction , um anzugeben, dass diese Aktion während des App-Starts verarbeitet wird.

    processNotificationActions(this.intent, true)
    

Hinweis

Sie müssen die App jedes Mal neu registrieren, wenn Sie sie ausführen, und sie in einer Debugsitzung beenden, um weiterhin Pushbenachrichtigungen zu erhalten.

Konfigurieren des nativen iOS-Projekts für Pushbenachrichtigungen

Konfigurieren des Runnerziels und info.plist

  1. Klicken Sie in Visual Studio Codesteuerelement + Klicken Sie auf den Ordner ios , und wählen Sie dann In Xcode öffnen aus.

  2. Klicken Sie in Xcode auf Runner (das xcodeproj oben, nicht auf den Ordner), wählen Sie dann das Runner-Ziel und dann Signieren & Funktionen aus. Wählen Sie bei ausgewählter Alle Buildkonfiguration Ihr Entwicklerkonto für das Team aus. Stellen Sie sicher, dass die Option "Signatur automatisch verwalten" aktiviert ist und Ihr Signaturzertifikat und Ihr Bereitstellungsprofil automatisch ausgewählt sind.

    Hinweis

    Wenn der neue Wert für das Bereitstellungsprofil nicht angezeigt wird, versuchen Sie, die Profile für die Signaturidentität zu aktualisieren, indem SieXcode-Einstellungskonto>> auswählen und dann die Schaltfläche Manuelle Profile herunterladen auswählen, um die Profile herunterzuladen.

  3. Klicken Sie auf + Funktion, und suchen Sie dann nach Pushbenachrichtigungen. Doppelklicken Sie auf Pushbenachrichtigungen , um diese Funktion hinzuzufügen.

  4. Öffnen Sie Info.plist , und legen Sie Mindestsystemversion auf 13.0 fest.

    Hinweis

    Nur Geräte mit iOS 13.0 und höher werden für die Zwecke dieses Tutorials unterstützt. Sie können es jedoch erweitern, um Geräte mit älteren Versionen zu unterstützen.

  5. Öffnen Sie Runner.entitlements , und stellen Sie sicher, dass die Einstellung APS-Umgebung auf Entwicklung festgelegt ist.

Behandeln von Pushbenachrichtigungen für iOS

  1. Steuerung + Klicken Sie auf den Ordner Runner (innerhalb des Runner-Projekts), und wählen Sie dann Neue Gruppe mit Diensten als Namen aus.

  2. Steuerung + Klicken Sie auf den Ordner Dienste , und wählen Sie dann Neue Datei... aus. Wählen Sie dann Swift File (Swift File) aus, und klicken Sie auf Weiter. Geben Sie DeviceInstallationService als Namen an, und klicken Sie dann auf Erstellen.

  3. Implementieren Sie DeviceInstallationService.swift mit dem folgenden Code.

    import Foundation
    
    class DeviceInstallationService {
    
        enum DeviceRegistrationError: Error {
            case notificationSupport(message: String)
        }
    
        var token : Data? = nil
    
        let DEVICE_INSTALLATION_CHANNEL = "com.<your_organization>.pushdemo/deviceinstallation"
        let GET_DEVICE_ID = "getDeviceId"
        let GET_DEVICE_TOKEN = "getDeviceToken"
        let GET_DEVICE_PLATFORM = "getDevicePlatform"
    
        private let deviceInstallationChannel : FlutterMethodChannel
    
        var notificationsSupported : Bool {
            get {
                if #available(iOS 13.0, *) {
                    return true
                }
                else {
                    return false
                }
            }
        }
    
        init(withBinaryMessenger binaryMessenger : FlutterBinaryMessenger) {
            deviceInstallationChannel = FlutterMethodChannel(name: DEVICE_INSTALLATION_CHANNEL, binaryMessenger: binaryMessenger)
            deviceInstallationChannel.setMethodCallHandler(handleDeviceInstallationCall)
        }
    
        func getDeviceId() -> String {
            return UIDevice.current.identifierForVendor!.description
        }
    
        func getDeviceToken() throws -> String {
            if(!notificationsSupported) {
                let notificationSupportError = getNotificationsSupportError()
                throw DeviceRegistrationError.notificationSupport(message: notificationSupportError)
            }
    
            if (token == nil) {
                throw DeviceRegistrationError.notificationSupport(message: "Unable to resolve token for APNS.")
            }
    
            return token!.reduce("", {$0 + String(format: "%02X", $1)})
        }
    
        func getDevicePlatform() -> String {
            return "apns"
        }
    
        private func handleDeviceInstallationCall(call: FlutterMethodCall, result: @escaping FlutterResult) {
            switch call.method {
            case GET_DEVICE_ID:
                result(getDeviceId())
            case GET_DEVICE_TOKEN:
                getDeviceToken(result: result)
            case GET_DEVICE_PLATFORM:
                result(getDevicePlatform())
            default:
                result(FlutterMethodNotImplemented)
            }
        }
    
        private func getDeviceToken(result: @escaping FlutterResult) {
            do {
                let token = try getDeviceToken()
                result(token)
            }
            catch let error {
                result(FlutterError(code: "UNAVAILABLE", message: error.localizedDescription, details: nil))
            }
        }
    
        private func getNotificationsSupportError() -> String {
    
            if (!notificationsSupported) {
                return "This app only supports notifications on iOS 13.0 and above. You are running \(UIDevice.current.systemVersion)"
            }
    
            return "An error occurred preventing the use of push notifications."
        }
    }
    

    Hinweis

    Diese Klasse implementiert das plattformspezifische Pendant für den com.<your_organization>.pushdemo/deviceinstallation Kanal. Dies wurde im Bereich "Flutter" der App in DeviceInstallationService.dart definiert. In diesem Fall werden die Aufrufe vom allgemeinen Code an den nativen Host ausgeführt. Ersetzen Sie <unbedingt your_organization> durch Ihre eigenen organization, wo immer dies verwendet wird.

    Diese Klasse stellt eine eindeutige ID (unter Verwendung des UIDevice.identifierForVendor-Werts ) als Teil der Notification Hub-Registrierungsnutzlast bereit.

  4. Fügen Sie dem Ordner Services eine weitere Swift-Datei namens NotificationRegistrationService hinzu, und fügen Sie dann den folgenden Code hinzu.

    import Foundation
    
    class NotificationRegistrationService {
    
        let NOTIFICATION_REGISTRATION_CHANNEL = "com.<your_organization>.pushdemo/notificationregistration"
        let REFRESH_REGISTRATION = "refreshRegistration"
    
        private let notificationRegistrationChannel : FlutterMethodChannel
    
        init(withBinaryMessenger binaryMessenger : FlutterBinaryMessenger) {
           notificationRegistrationChannel = FlutterMethodChannel(name: NOTIFICATION_REGISTRATION_CHANNEL, binaryMessenger: binaryMessenger)
        }
    
        func refreshRegistration() {
            notificationRegistrationChannel.invokeMethod(REFRESH_REGISTRATION, arguments: nil)
        }
    }
    

    Hinweis

    Diese Klasse implementiert das plattformspezifische Pendant für den com.<your_organization>.pushdemo/notificationregistration Kanal. Dies wurde im Bereich "Flutter" der App in NotificationRegistrationService.dart definiert. In diesem Fall werden die Aufrufe vom nativen Host an den allgemeinen Code ausgeführt. Achten Sie auch hier darauf, your_organization> durch Ihre eigenen organization zu ersetzen<, wo immer dies verwendet wird.

  5. Fügen Sie dem Ordner Services eine weitere Swift-Datei namens NotificationActionService hinzu, und fügen Sie dann den folgenden Code hinzu.

    import Foundation
    
    class NotificationActionService {
    
        let NOTIFICATION_ACTION_CHANNEL = "com.<your_organization>.pushdemo/notificationaction"
        let TRIGGER_ACTION = "triggerAction"
        let GET_LAUNCH_ACTION = "getLaunchAction"
    
        private let notificationActionChannel: FlutterMethodChannel
    
        var launchAction: String? = nil
    
        init(withBinaryMessenger binaryMessenger: FlutterBinaryMessenger) {
            notificationActionChannel = FlutterMethodChannel(name: NOTIFICATION_ACTION_CHANNEL, binaryMessenger: binaryMessenger)
            notificationActionChannel.setMethodCallHandler(handleNotificationActionCall)
        }
    
        func triggerAction(action: String) {
           notificationActionChannel.invokeMethod(TRIGGER_ACTION, arguments: action)
        }
    
        private func handleNotificationActionCall(call: FlutterMethodCall, result: @escaping FlutterResult) {
            switch call.method {
            case GET_LAUNCH_ACTION:
                result(launchAction)
            default:
                result(FlutterMethodNotImplemented)
            }
        }
    }
    

    Hinweis

    Diese Klasse implementiert das plattformspezifische Pendant für den com.<your_organization>.pushdemo/notificationaction Kanal. Dies wurde im Flutter-Teil der App in NotificationActionService.dart definiert. Anrufe können in diesem Fall in beide Richtungen erfolgen. Ersetzen Sie <unbedingt your_organization> durch Ihre eigenen organization, wo immer dies verwendet wird.

  6. Fügen Sie in AppDelegate.swift Variablen hinzu, um einen Verweis auf die zuvor erstellten Dienste zu speichern.

    var deviceInstallationService : DeviceInstallationService?
    var notificationRegistrationService : NotificationRegistrationService?
    var notificationActionService : NotificationActionService?
    
  7. Fügen Sie eine Funktion namens processNotificationActions zum Verarbeiten der Benachrichtigungsdaten hinzu. Lösen Sie diese Aktion bedingt aus, oder speichern Sie sie zur späteren Verwendung, wenn die Aktion während des App-Starts verarbeitet wird.

    func processNotificationActions(userInfo: [AnyHashable : Any], launchAction: Bool = false) {
        if let action = userInfo["action"] as? String {
            if (launchAction) {
                notificationActionService?.launchAction = action
            }
            else {
                notificationActionService?.triggerAction(action: action)
            }
        }
    }
    
  8. Überschreiben Sie die funktion didRegisterForRemoteNotificationsWithDeviceToken , die den Tokenwert für deviceInstallationService festlegt. Rufen Sie anschließend refreshRegistration auf notificationRegistrationService auf.

    override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
      deviceInstallationService?.token = deviceToken
      notificationRegistrationService?.refreshRegistration()
    }
    
  9. Überschreiben Sie die didReceiveRemoteNotification-Funktion , die das userInfo-Argument an die processNotificationActions-Funktion übergibt.

    override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
        processNotificationActions(userInfo: userInfo)
    }
    
  10. Überschreiben Sie die funktion didFailToRegisterForRemoteNotificationsWithError , um den Fehler zu protokollieren.

    override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print(error);
    }
    

    Hinweis

    Dies ist sehr viel ein Platzhalter. Sie sollten eine ordnungsgemäße Protokollierung und Fehlerbehandlung für Produktionsszenarien implementieren.

  11. Instanziieren Sie in didFinishLaunchingWithOptions die Variablen deviceInstallationService, notificationRegistrationService und notificationActionService .

    let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
    
    deviceInstallationService = DeviceInstallationService(withBinaryMessenger: controller.binaryMessenger)
    notificationRegistrationService = NotificationRegistrationService(withBinaryMessenger: controller.binaryMessenger)
    notificationActionService = NotificationActionService(withBinaryMessenger: controller.binaryMessenger)
    
  12. Fordern Sie in derselben Funktion bedingt die Autorisierung an, und registrieren Sie sich für Remotebenachrichtigungen.

    if #available(iOS 13.0, *) {
      UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
          (granted, error) in
    
          if (granted)
          {
              DispatchQueue.main.async {
                  let pushSettings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: nil)
                  application.registerUserNotificationSettings(pushSettings)
                  application.registerForRemoteNotifications()
              }
          }
      }
    }
    
  13. Wenn launchOptions den remoteNotification-Schlüssel enthält, rufen Sie processNotificationActions am Ende der funktion didFinishLaunchingWithOptions auf. Übergeben Sie das resultierende userInfo-Objekt , und verwenden Sie true für das launchAction-Argument . Ein true-Wert gibt an, dass die Aktion während des App-Starts verarbeitet wird.

    if let userInfo = launchOptions?[.remoteNotification] as? [AnyHashable : Any] {
        processNotificationActions(userInfo: userInfo, launchAction: true)
    }
    

Testen der Lösung

Sie können jetzt das Senden von Benachrichtigungen über den Back-End-Dienst testen.

Senden einer Testbenachrichtigung

  1. Öffnen Sie in Postman eine neue Registerkarte.

  2. Legen Sie die Anforderung auf POST fest, und geben Sie die folgende Adresse ein:

    https://<app_name>.azurewebsites.net/api/notifications/requests
    
  3. Wenn Sie den Abschnitt Authentifizieren von Clients mithilfe eines API-Schlüssels abgeschlossen haben, müssen Sie die Anforderungsheader so konfigurieren, dass sie Ihren apikey-Wert enthalten.

    Schlüssel Wert
    apikey <your_api_key>
  4. Wählen Sie die Raw-Option für den Text aus, wählen Sie dann JSON aus der Liste der Formatoptionen aus, und fügen Sie dann einige Platzhalter-JSON-Inhalte ein:

    {
        "text": "Message from Postman!",
        "action": "action_a"
    }
    
  5. Wählen Sie die Schaltfläche Code aus, die sich unter der Schaltfläche Speichern oben rechts im Fenster befindet. Die Anforderung sollte ähnlich wie das folgende Beispiel aussehen, wenn sie für HTML angezeigt wird (je nachdem, ob Sie einen apikey-Header enthalten haben):

    POST /api/notifications/requests HTTP/1.1
    Host: https://<app_name>.azurewebsites.net
    apikey: <your_api_key>
    Content-Type: application/json
    
    {
        "text": "Message from backend service",
        "action": "action_a"
    }
    
  6. Führen Sie die PushDemo-Anwendung auf einer oder beiden Zielplattformen (Android und iOS) aus.

    Hinweis

    Wenn Sie unter Android testen, stellen Sie sicher, dass Sie nicht in Debuggen ausgeführt werden, oder wenn die App bereitgestellt wurde, indem Sie die Anwendung ausführen, dann erzwingen Sie das Schließen der App, und starten Sie sie über das Startprogramm erneut.

  7. Tippen Sie in der PushDemo-App auf die Schaltfläche Registrieren .

  8. Zurück zu Postman, schließen Sie das Fenster Codeausschnitte generieren (falls sie dies noch nicht getan haben), und klicken Sie dann auf die Schaltfläche Senden .

  9. Überprüfen Sie, ob Sie eine 200 OK-Antwort in Postman erhalten und die Warnung in der App angezeigt wird, die AktionA-Aktion empfangen.

  10. Schließen Sie die PushDemo-App, und klicken Sie dann in Postman erneut auf die Schaltfläche Senden.

  11. Überprüfen Sie, ob Sie in Postman erneut eine Antwort mit 200 OK erhalten. Überprüfen Sie, ob eine Benachrichtigung im Infobereich für die PushDemo-App mit der richtigen Nachricht angezeigt wird.

  12. Tippen Sie auf die Benachrichtigung, um zu bestätigen, dass die App geöffnet und die AktionA-Warnung empfangen wurde .

  13. Ändern Sie zurück in Postman den vorherigen Anforderungstext, um eine unbeaufsichtigte Benachrichtigung zu senden, die action_b anstelle von action_a für den Aktionswert angibt.

    {
        "action": "action_b",
        "silent": true
    }
    
  14. Wenn die App weiterhin geöffnet ist, klicken Sie in Postman auf die Schaltfläche Senden.

  15. Überprüfen Sie, ob Sie eine 200 OK-Antwort in Postman erhalten und dass die Warnung in der App angezeigt wird, die Die Aktion B-Aktion empfangen anstelle der empfangenen AktionA-Aktion anzeigt.

  16. Schließen Sie die PushDemo-App, und klicken Sie dann in Postman erneut auf die Schaltfläche Senden.

  17. Überprüfen Sie, ob Sie eine Antwort mit 200 OK in Postman erhalten und dass die unbeaufsichtigte Benachrichtigung nicht im Benachrichtigungsbereich angezeigt wird.

Problembehandlung

Keine Antwort vom Back-End-Dienst

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

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

Vergewissern Sie sich, dass Sie die Basisadresse beim Testen über den Client in Postman oder in der Konfiguration der mobilen App korrekt angegeben haben. Die Basisadresse sollte indikativ oder beim lokalen Testen sein https://<api_name>.azurewebsites.net/https://localhost:5001/ .

Keine Benachrichtigungen unter Android nach dem Starten oder Beenden einer Debugsitzung

Stellen Sie sicher, dass Sie sich nach dem Starten oder Beenden einer Debugsitzung erneut registrieren. Der Debugger bewirkt, dass ein neues Firebase-Token generiert wird. Auch die Notification Hub-Installation muss aktualisiert werden.

Empfangen eines 401-status-Codes vom Back-End-Dienst

Überprüfen Sie, ob Sie den apikey-Anforderungsheader festlegen und dieser Wert mit dem Wert übereinstimmt, den Sie für den Back-End-Dienst konfiguriert haben.

Wenn Sie diesen Fehler beim lokalen Testen erhalten, stellen Sie sicher, dass der Schlüsselwert, den Sie in der Clientkonfiguration definiert haben, dem von der API verwendeten Wert für die Benutzereinstellung Authentication:ApiKey entspricht.

Wenn Sie mit einer API-App testen, stellen Sie sicher, dass der Schlüsselwert in der Clientkonfigurationsdatei der Anwendungseinstellung Authentication:ApiKey entspricht, die Sie in der API-App verwenden.

Hinweis

Wenn Sie diese Einstellung erstellt oder geändert haben, nachdem Sie den Back-End-Dienst bereitgestellt haben, müssen Sie den Dienst neu starten, damit er wirksam wird.

Wenn Sie den Abschnitt Clients mithilfe eines API-Schlüssels authentifizieren nicht abschließen möchten, stellen Sie sicher, dass Sie das Authorize-Attribut nicht auf die NotificationsController-Klasse angewendet haben.

Empfangen eines 404-status-Codes vom Back-End-Dienst

Überprüfen Sie, ob der Endpunkt und die HTTP-Anforderungsmethode korrekt sind. Die Endpunkte sollten z. B. indikativ sein:

  • [PUT]https://<api_name>.azurewebsites.net/api/notifications/installations
  • [LÖSCHEN]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:5001/api/notifications/installations
  • [LÖSCHEN]https://localhost:5001/api/notifications/installations/<installation_id>
  • [POST]https://localhost:5001/api/notifications/requests

Wenn Sie die Basisadresse in der Client-App angeben, stellen Sie sicher, dass sie mit einem /endet. Die Basisadresse sollte indikativ oder beim lokalen Testen sein https://<api_name>.azurewebsites.net/https://localhost:5001/ .

Registrierung nicht möglich, und eine Notification Hub-Fehlermeldung wird angezeigt

Vergewissern Sie sich, dass das Testgerät über Netzwerkkonnektivität verfügt. Bestimmen Sie dann die HTTP-Antwort status Code, indem Sie einen Haltepunkt festlegen, um den StatusCode-Eigenschaftswert in der HttpResponse zu überprüfen.

Überprüfen Sie ggf. die vorherigen Problembehandlungsvorschläge basierend auf dem status Code.

Legen Sie einen Haltepunkt für die Zeilen fest, die diese spezifischen status Codes für die jeweilige API zurückgeben. Versuchen Sie dann, den Back-End-Dienst beim lokalen Debuggen aufzurufen.

Überprüfen Sie, ob der Back-End-Dienst über Postman mit der entsprechenden Nutzlast wie erwartet funktioniert. Verwenden Sie die tatsächliche Nutzlast, die vom Clientcode für die betreffende Plattform erstellt wurde.

Überprüfen Sie die abschnitte zur plattformspezifischen Konfiguration, um sicherzustellen, dass keine Schritte verpasst wurden. Überprüfen Sie, ob geeignete Werte für installation id und token Variablen für die entsprechende Plattform aufgelöst werden.

Eine ID für die Angezeigte Gerätefehlermeldung kann nicht aufgelöst werden.

Überprüfen Sie die abschnitte zur plattformspezifischen Konfiguration, um sicherzustellen, dass keine Schritte verpasst wurden.

Nächste Schritte

Sie sollten jetzt über eine einfache Flutter-App verfügen, die über einen Back-End-Dienst mit einem Notification Hub verbunden ist und Benachrichtigungen senden und empfangen kann.

Wahrscheinlich müssen Sie das in diesem Tutorial verwendete Beispiel an Ihr eigenes Szenario anpassen. Es wird auch empfohlen, eine robustere Fehlerbehandlung, Wiederholungslogik und Protokollierung zu implementieren.

Visual Studio App Center kann schnell in mobile Apps integriert werden, die Analysen und Diagnose bereitstellen, um die Problembehandlung zu unterstützen.