Tutorial: Senden von Pushbenachrichtigungen an bestimmte Android-Apps mit Azure Notification Hubs

Hinweis

Informationen zur Einstellung und Migrationsschritte für Firebase Cloud Messaging finden Sie unter Google Firebase Cloud Messaging-Migration.

Ein ASP.NET WebAPI-Back-End wird verwendet, um Clients zu authentifizieren. Zum Authentifizieren von Clients und Generieren von Benachrichtigungen wird ein ASP.NET WebAPI-Back-End verwendet, wie im Artikel Registrierungsverwaltung über ein Back-End gezeigt. Dieses Tutorial baut auf dem Benachrichtigungs-Hub auf, den Sie unter Tutorial: Senden von Pushbenachrichtigungen an Android-Geräte mit Azure Notification Hubs und Firebase Cloud Messaging erstellt haben.

In diesem Tutorial führen Sie die folgenden Schritte aus:

  • Erstellen des Back-End-Web-API-Projekts, das Benutzer authentifiziert.
  • Aktualisieren der Android-Anwendung.
  • Testen der App

Voraussetzungen

Absolvieren Sie Tutorial: Senden von Pushbenachrichtigungen an Android-Geräte mit Azure Notification Hubs und Firebase Cloud Messaging, bevor Sie mit diesem Tutorial beginnen.

Erstellen des WebAPI-Projekts

In den folgenden Abschnitten wird die Erstellung eines neuen ASP.NET-WebAPI-Back-Ends erläutert. Dieser Prozess hat drei Hauptfunktionen:

  • Authentifizieren von Clients: Sie fügen einen Meldungshandler hinzu, um Clientanforderungen zu authentifizieren und den Benutzer der Anforderung zuzuordnen.
  • Registrieren für Benachrichtigungen unter Verwendung des WebAPI-Back-Ends: Sie fügen einen Controller hinzu, um neue Registrierungen für ein Clientgerät zum Empfangen von Benachrichtigungen zu verarbeiten. Der authentifizierte Benutzername wird der Registrierung automatisch als Tag hinzugefügt.
  • Senden von Benachrichtigungen an Clients: Sie fügen einen Controller hinzu, um Benutzern die Möglichkeit zu geben, einen sicheren Pushvorgang an Geräte und Clients auszulösen, die dem Tag zugeordnet sind.

Gehen Sie zum Erstellen des neuen ASP.NET Core 6.0-Web-API-Back-Ends wie folgt vor:

Um dies zu überprüfen, starten Sie Visual Studio. Wählen Sie im Menü Extras die Option Erweiterungen und Updates aus. Suchen Sie in Ihrer Version von Visual Studio nach NuGet-Paket-Manager, und vergewissern Sie sich, dass Sie über die neueste Version verfügen. Deinstallieren Sie andernfalls Ihre Version, und installieren Sie den NuGet-Paket-Manager erneut.

Screenshot of the Extensions and Updates dialog box with the NuGet Package manage for Visual Studios package highlighted.

Hinweis

Stellen Sie sicher, dass Sie das Visual Studio Azure SDK für die Websitebereitstellung installiert haben.

  1. Starten Sie Visual Studio oder Visual Studio Express.

  2. Wählen Sie Server-Explorer aus, und melden Sie sich bei Ihrem Azure-Konto an. Zur Erstellung der Websiteressourcen für Ihr Konto müssen Sie angemeldet sein.

  3. Wählen Sie in Visual Studio im Menü Datei die Optionen Neu>Projekt aus.

  4. Geben Sie Web-API in das Suchfeld ein.

  5. Wählen Sie die Projektvorlage ASP.NET Core-Web-API und dann Weiter aus.

  6. Geben Sie im Dialogfeld Neues Projekt konfigurieren dem Projekt den Namen AppBackend, und wählen Sie dann Weiter aus.

  7. Im Dialogfeld Zusätzliche Informationen:

    • Vergewissern Sie sich, dass das Framework auf .NET 6.0 (Langfristiger Support) festgelegt ist.
    • Vergewissern Sie sich, dass das Kontrollkästchen Controller verwenden (zur Verwendung minimaler APIs deaktivieren) aktiviert ist.
    • Deaktivieren Sie OpenAPI-Unterstützung aktivieren.
    • Klicken Sie auf Erstellen.

Entfernen der WeatherForecast-Vorlagendateien

  1. Entfernen Sie die Beispieldateien WeatherForecast.cs und "Controllers/WeatherForecastController.cs aus dem neuen AppBackend-Projekt.
  2. Öffnen Sie Properties\launchSettings.json.
  3. Ändern Sie launchUrl-Eigenschaften von wetterforcast in appbackend.

Wählen Sie im Fenster Microsoft Azure-Web-App konfigurieren ein Abonnement aus, und führen Sie anschließend in der Liste App Service-Plan eine der folgenden Aktionen aus:

  • Wählen Sie einen bereits erstellten Azure App Service-Plan aus.
  • Wählen Sie Einen neuen App Services-Plan erstellen aus, und erstellen Sie einen neuen Plan.

Sie benötigen für dieses Lernprogramm keine Datenbank. Wählen Sie nach der Wahl Ihres App Service-Plans OK aus, um das Projekt zu erstellen.

The Configure Microsoft Azure Web App window

Wird diese Seite zum Konfigurieren des App Service-Plans nicht angezeigt, fahren Sie mit dem Tutorial fort. Sie können ihn später beim Veröffentlichen der App konfigurieren.

Authentifizieren von Clients beim WebAPI-Back-End

In diesem Abschnitt erstellen Sie für das neue Back-End eine neue Meldungshandlerklasse namens AuthenticationTestHandler. Diese Klasse wird von DelegatingHandler abgeleitet und als Meldungshandler hinzugefügt, damit alle beim Back-End eingehenden Anforderungen verarbeitet werden können.

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt AppBackend, und wählen Sie Hinzufügen und anschließend Klasse aus.

  2. Geben Sie der neuen Klasse den Namen AuthenticationTestHandler.cs, und wählen Sie Hinzufügen aus, um die Klasse zu generieren. Mit dieser Klasse werden Benutzer der Einfachheit halber unter Verwendung der Standardauthentifizierung authentifiziert. Ihre App kann ein beliebiges Authentifizierungsschema verwenden.

  3. Fügen Sie in der Datei "AuthenticationTestHandler.cs" die folgenden using -Anweisungen hinzu:

    using System.Net.Http;
    using System.Threading;
    using System.Security.Principal;
    using System.Net;
    using System.Text;
    using System.Threading.Tasks;
    
  4. Ersetzen Sie in der Datei „AuthenticationTestHandler.cs“ die Definition der Klasse AuthenticationTestHandler durch den folgenden Code:

    Der Handler autorisiert die Anforderung, wenn die folgenden drei Bedingungen erfüllt sind:

    • Die Anforderung enthält einen Autorisierungsheader.
    • Für die Anforderung wird die Standardauthentifizierung verwendet.
    • Bei der Benutzernamen-Zeichenfolge und der Kennwortzeichenfolge handelt es sich um die gleiche Zeichenfolge.

    Andernfalls wird die Anforderung abgelehnt. Diese Authentifizierung ist keine echte Vorgehensweise zur Authentifizierung und Autorisierung. Hierbei handelt es sich lediglich um ein einfaches Beispiel für dieses Tutorial.

    Wenn die Anforderungsnachricht von AuthenticationTestHandler authentifiziert und autorisiert wurde, wird der Benutzer der Standardauthentifizierung an die aktuelle Anforderung in HttpContext angefügt. Die Benutzerinformationen in „HttpContext“ werden später von einem anderen Controller (RegisterController) verwendet, um der Registrierungsanforderung für die Benachrichtigung ein Tag hinzuzufügen.

    public class AuthenticationTestHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var authorizationHeader = request.Headers.GetValues("Authorization").First();
    
            if (authorizationHeader != null && authorizationHeader
                .StartsWith("Basic ", StringComparison.InvariantCultureIgnoreCase))
            {
                string authorizationUserAndPwdBase64 =
                    authorizationHeader.Substring("Basic ".Length);
                string authorizationUserAndPwd = Encoding.Default
                    .GetString(Convert.FromBase64String(authorizationUserAndPwdBase64));
                string user = authorizationUserAndPwd.Split(':')[0];
                string password = authorizationUserAndPwd.Split(':')[1];
    
                if (VerifyUserAndPwd(user, password))
                {
                    // Attach the new principal object to the current HttpContext object
                    HttpContext.Current.User =
                        new GenericPrincipal(new GenericIdentity(user), new string[0]);
                    System.Threading.Thread.CurrentPrincipal =
                        System.Web.HttpContext.Current.User;
                }
                else return Unauthorized();
            }
            else return Unauthorized();
    
            return base.SendAsync(request, cancellationToken);
        }
    
        private bool VerifyUserAndPwd(string user, string password)
        {
            // This is not a real authentication scheme.
            return user == password;
        }
    
        private Task<HttpResponseMessage> Unauthorized()
        {
            var response = new HttpResponseMessage(HttpStatusCode.Forbidden);
            var tsc = new TaskCompletionSource<HttpResponseMessage>();
            tsc.SetResult(response);
            return tsc.Task;
        }
    }
    

    Hinweis

    Sicherheitshinweis: Die Klasse AuthenticationTestHandler ermöglicht keine wirkliche Authentifizierung. Sie wird nur verwendet, um eine Standardauthentifizierung zu imitieren, und ist nicht sicher. Sie müssen einen sicheren Authentifizierungsmechanismus in Ihren Produktionsanwendungen und -diensten implementieren.

  5. Fügen Sie am Ende der Register-Methode in der Datei Program.cs den folgenden Code hinzu, um den Meldungshandler zu registrieren:

    config.MessageHandlers.Add(new AuthenticationTestHandler());
    
  6. Speichern Sie die Änderungen.

Registrieren für Benachrichtigungen unter Verwendung des WebAPI-Back-Ends

In diesem Abschnitt wird dem WebAPI-Back-End ein neuer Controller hinzugefügt, um Anforderungen zum Registrieren eines Benutzers und eines Geräts für Benachrichtigungen unter Verwendung der Clientbibliothek für Notification Hubs zu verarbeiten. Der Controller fügt ein Benutzertag für den Benutzer hinzu, der durch AuthenticationTestHandler authentifiziert und an „HttpContext“ angefügt wurde. Die Markierung hat das Zeichenfolgenformat "username:<actual username>".

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt AppBackend, und wählen Sie dann NuGet-Pakete verwalten aus.

  2. Wählen Sie im linken Bereich Online aus, und geben Sie dann im Feld Suche die Zeichenfolge Microsoft.Azure.NotificationHubs ein.

  3. Wählen Sie in der Ergebnisliste die Option Microsoft Azure Notification Hubs und anschließend Installieren aus. Schließen Sie die Installation ab, und schließen Sie dann das Fenster des NuGet-Paket-Managers.

    Dadurch wird mithilfe des Microsoft.Azure.NotificationHubs-NuGet-Pakets ein Verweis auf das Azure Notification Hubs-SDK hinzugefügt.

  4. Erstellen Sie eine neue Klassendatei, die die Verbindung mit dem Notification Hub darstellt, der zum Senden von Benachrichtigungen verwendet wird. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner Modelle, und wählen Sie dann Hinzufügen und anschließend Klasse aus. Nennen Sie die neue Klasse Notifications.cs, und wählen Sie dann Hinzufügen aus, um die Klasse zu generieren.

    The Add New Item window

  5. Fügen Sie die folgende using -Anweisung am Anfang der Datei "Notifications.cs" hinzu:

    using Microsoft.Azure.NotificationHubs;
    
  6. Ersetzen Sie die Definition der Klasse Notifications durch den folgenden Code und die beiden Platzhalter durch die Verbindungszeichenfolge (mit Vollzugriff) für Ihren Notification Hub bzw. durch den Namen des Hubs (verfügbar im Azure-Portal):

    public class Notifications
    {
        public static Notifications Instance = new Notifications();
    
        public NotificationHubClient Hub { get; set; }
    
        private Notifications() {
            Hub = NotificationHubClient.CreateClientFromConnectionString("<your hub's DefaultFullSharedAccessSignature>",
                                                                            "<hub name>");
        }
    }
    

    Wichtig

    Geben Sie für den Hub den Namen und einen Wert für DefaultFullSharedAccessSignature ein, bevor Sie fortfahren.

  7. Erstellen Sie als Nächstes einen neuen Controller namens RegisterController. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner Controller, und wählen Sie dann Hinzufügen und Controller aus.

  8. Wählen Sie API-Controller – Leer und anschließend Hinzufügen aus.

  9. Geben Sie im Feld Controllername die Zeichenfolge RegisterController ein, um die neue Klasse zu benennen, und wählen Sie anschließend Hinzufügen aus.

    The Add Controller window.

  10. Fügen Sie in der Datei "RegisterController.cs" die folgenden using -Anweisungen hinzu:

    using Microsoft.Azure.NotificationHubs;
    using Microsoft.Azure.NotificationHubs.Messaging;
    using AppBackend.Models;
    using System.Threading.Tasks;
    using System.Web;
    
  11. Fügen Sie innerhalb der RegisterController -Klassendefinition den folgenden Code hinzu. Mit diesem Code fügen Sie ein Benutzertag für den Benutzer hinzu, der HttpContext angefügt ist. Der Benutzer wurde mit dem von Ihnen hinzugefügten Nachrichtenfilter AuthenticationTestHandler authentifiziert und HttpContext angefügt. Sie können auch optionale Überprüfungen hinzufügen, um zu überprüfen, dass der Benutzer die richtigen Berechtigungen besitzt, um sich für die angeforderten Tags zu registrieren.

    private NotificationHubClient hub;
    
    public RegisterController()
    {
        hub = Notifications.Instance.Hub;
    }
    
    public class DeviceRegistration
    {
        public string Platform { get; set; }
        public string Handle { get; set; }
        public string[] Tags { get; set; }
    }
    
    // POST api/register
    // This creates a registration id
    public async Task<string> Post(string handle = null)
    {
        string newRegistrationId = null;
    
        // make sure there are no existing registrations for this push handle (used for iOS and Android)
        if (handle != null)
        {
            var registrations = await hub.GetRegistrationsByChannelAsync(handle, 100);
    
            foreach (RegistrationDescription registration in registrations)
            {
                if (newRegistrationId == null)
                {
                    newRegistrationId = registration.RegistrationId;
                }
                else
                {
                    await hub.DeleteRegistrationAsync(registration);
                }
            }
        }
    
        if (newRegistrationId == null) 
            newRegistrationId = await hub.CreateRegistrationIdAsync();
    
        return newRegistrationId;
    }
    
    // PUT api/register/5
    // This creates or updates a registration (with provided channelURI) at the specified id
    public async Task<HttpResponseMessage> Put(string id, DeviceRegistration deviceUpdate)
    {
        RegistrationDescription registration = null;
        switch (deviceUpdate.Platform)
        {
            case "mpns":
                registration = new MpnsRegistrationDescription(deviceUpdate.Handle);
                break;
            case "wns":
                registration = new WindowsRegistrationDescription(deviceUpdate.Handle);
                break;
            case "apns":
                registration = new AppleRegistrationDescription(deviceUpdate.Handle);
                break;
            case "fcm":
                registration = new FcmRegistrationDescription(deviceUpdate.Handle);
                break;
            default:
                throw new HttpResponseException(HttpStatusCode.BadRequest);
        }
    
        registration.RegistrationId = id;
        var username = HttpContext.Current.User.Identity.Name;
    
        // add check if user is allowed to add these tags
        registration.Tags = new HashSet<string>(deviceUpdate.Tags);
        registration.Tags.Add("username:" + username);
    
        try
        {
            await hub.CreateOrUpdateRegistrationAsync(registration);
        }
        catch (MessagingException e)
        {
            ReturnGoneIfHubResponseIsGone(e);
        }
    
        return Request.CreateResponse(HttpStatusCode.OK);
    }
    
    // DELETE api/register/5
    public async Task<HttpResponseMessage> Delete(string id)
    {
        await hub.DeleteRegistrationAsync(id);
        return Request.CreateResponse(HttpStatusCode.OK);
    }
    
    private static void ReturnGoneIfHubResponseIsGone(MessagingException e)
    {
        var webex = e.InnerException as WebException;
        if (webex.Status == WebExceptionStatus.ProtocolError)
        {
            var response = (HttpWebResponse)webex.Response;
            if (response.StatusCode == HttpStatusCode.Gone)
                throw new HttpRequestException(HttpStatusCode.Gone.ToString());
        }
    }
    
  12. Speichern Sie die Änderungen.

Senden von Benachrichtigungen über das WebAPI-Back-End

In diesem Abschnitt wird ein neuer Controller hinzugefügt, der Clientgeräten das Senden einer Benachrichtigung ermöglicht. Die Benachrichtigung basiert auf dem Benutzernamentag, das die Azure Notification Hubs .NET-Bibliothek des ASP.NET WebAPI-Back-Ends verwendet.

  1. Erstellen Sie einen weiteren neuen Domänencontroller namens NotificationsController. Verwenden Sie dazu die gleiche Vorgehensweise wie bei der Erstellung von RegisterController im vorherigen Abschnitt.

  2. Fügen Sie in der Datei "NotificationsController.cs" die folgenden using -Anweisungen hinzu:

    using AppBackend.Models;
    using System.Threading.Tasks;
    using System.Web;
    
  3. Fügen Sie der Klasse NotificationsController die folgende Methode hinzu:

    Mit diesem Code wird ein Benachrichtigungstyp gesendet, der auf dem Parameter pns des Plattformbenachrichtigungssystems (Plattform Notification System, PNS) basiert. Der Wert von to_tag dient zum Festlegen des username -Tags in der Nachricht. Dieses Tag muss mit einem Benutzernamentag einer aktiven Notification Hub-Registrierung übereinstimmen. Die Benachrichtigung wird aus dem Text der POST-Anforderung abgerufen und für den Ziel-PNS formatiert.

    Abhängig von dem PNS, mit dem Ihre unterstützten Geräte Benachrichtigungen empfangen, werden Benachrichtigungen mit unterschiedlichen Formaten unterstützt. Ein Beispiel: Angenommen, Sie verwenden auf Windows-Geräten eine Popupbenachrichtigung mit WNS, die nicht direkt durch ein anderes PNS unterstützt wird. In diesem Fall muss Ihr Back-End die Benachrichtigung so formatieren, dass sie mit dem PNS der zu unterstützenden Geräte kompatibel ist. Verwenden Sie anschließend die entsprechende Sende-API für die NotificationHubClient-Klasse.

    public async Task<HttpResponseMessage> Post(string pns, [FromBody]string message, string to_tag)
    {
        var user = HttpContext.Current.User.Identity.Name;
        string[] userTag = new string[2];
        userTag[0] = "username:" + to_tag;
        userTag[1] = "from:" + user;
    
        Microsoft.Azure.NotificationHubs.NotificationOutcome outcome = null;
        HttpStatusCode ret = HttpStatusCode.InternalServerError;
    
        switch (pns.ToLower())
        {
            case "wns":
                // Windows 8.1 / Windows Phone 8.1
                var toast = @"<toast><visual><binding template=""ToastText01""><text id=""1"">" + 
                            "From " + user + ": " + message + "</text></binding></visual></toast>";
                outcome = await Notifications.Instance.Hub.SendWindowsNativeNotificationAsync(toast, userTag);
                break;
            case "apns":
                // iOS
                var alert = "{\"aps\":{\"alert\":\"" + "From " + user + ": " + message + "\"}}";
                outcome = await Notifications.Instance.Hub.SendAppleNativeNotificationAsync(alert, userTag);
                break;
            case "fcm":
                // Android
                var notif = "{ \"data\" : {\"message\":\"" + "From " + user + ": " + message + "\"}}";
                outcome = await Notifications.Instance.Hub.SendFcmNativeNotificationAsync(notif, userTag);
                break;
        }
    
        if (outcome != null)
        {
            if (!((outcome.State == Microsoft.Azure.NotificationHubs.NotificationOutcomeState.Abandoned) ||
                (outcome.State == Microsoft.Azure.NotificationHubs.NotificationOutcomeState.Unknown)))
            {
                ret = HttpStatusCode.OK;
            }
        }
    
        return Request.CreateResponse(ret);
    }
    
  4. Drücken Sie F5, um die Anwendung auszuführen und sich zu vergewissern, dass soweit alles funktioniert. Die App öffnet einen Webbrowser und wird auf der Homepage von ASP.NET angezeigt.

Veröffentlichen des neuen WebAPI-Back-Ends

Als Nächstes wird die App auf einer Azure-Website bereitgestellt, damit sie für alle Geräte zur Verfügung steht.

  1. Klicken Sie mit der rechten Maustaste auf das Projekt AppBackend, und wählen Sie Veröffentlichen aus.

  2. Wählen Sie Microsoft Azure App Service als Veröffentlichungsziel und anschließend **Veröffentlichen aus. Das Fenster „App Service erstellen“ wird geöffnet. Hier können Sie alle Azure-Ressourcen erstellen, die zum Ausführen der ASP.NET-Web-App in Azure benötigt werden.

    The Microsoft Azure App Service tile

  3. Wählen Sie im Fenster App Service erstellen Ihr Azure-Konto aus. Wählen Sie Typ ändern>Web App aus. Behalten Sie den Standardwert für Web-App-Name bei, und wählen Sie Abonnement, Ressourcengruppe und App Service-Plan aus.

  4. Klicken Sie auf Erstellen.

  5. Notieren Sie sich die Website-URL aus der Zusammenfassung. Diese URL ist später im Tutorial Ihr Back-End-Endpunkt.

  6. Wählen Sie Veröffentlichen.

Nach Abschluss des Assistenten wird die ASP.NET Web-App in Azure veröffentlicht und anschließend im Standardbrowser geöffnet. Ihre Anwendung kann in Azure App Services angezeigt werden.

In der URL wird der von Ihnen angegebene Web-App-Name im Format http://<app_name>.azurewebsites.net verwendet.

Erstellen des Android-Projekts

Aktualisieren Sie als Nächstes die Android-Anwendung, die Sie in Tutorial: Senden von Pushbenachrichtigungen an Android-Geräte mit Azure Notification Hubs und Firebase Cloud Messaging erstellt haben.

  1. Öffnen Sie die Datei res/layout/activity_main.xml, und ersetzen Sie die folgenden Inhaltsdefinitionen:

    So werden neue EditText-Steuerelemente für die Anmeldung als Benutzer hinzugefügt. Zudem wird ein Feld für eine Benutzernamenmarkierung hinzugefügt, die in den von Ihnen gesendeten Benachrichtigungen enthalten ist.

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    
    <EditText
        android:id="@+id/usernameText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="@string/usernameHint"
        android:layout_above="@+id/passwordText"
        android:layout_alignParentEnd="true" />
    <EditText
        android:id="@+id/passwordText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="@string/passwordHint"
        android:inputType="textPassword"
        android:layout_above="@+id/buttonLogin"
        android:layout_alignParentEnd="true" />
    <Button
        android:id="@+id/buttonLogin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/loginButton"
        android:onClick="login"
        android:layout_above="@+id/toggleButtonFCM"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="24dp" />
    <ToggleButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textOn="WNS on"
        android:textOff="WNS off"
        android:id="@+id/toggleButtonWNS"
        android:layout_toLeftOf="@id/toggleButtonFCM"
        android:layout_centerVertical="true" />
    <ToggleButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textOn="FCM on"
        android:textOff="FCM off"
        android:id="@+id/toggleButtonFCM"
        android:checked="true"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" />
    <ToggleButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textOn="APNS on"
        android:textOff="APNS off"
        android:id="@+id/toggleButtonAPNS"
        android:layout_toRightOf="@id/toggleButtonFCM"
        android:layout_centerVertical="true" />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/editTextNotificationMessageTag"
        android:layout_below="@id/toggleButtonFCM"
        android:layout_centerHorizontal="true"
        android:hint="@string/notification_message_tag_hint" />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/editTextNotificationMessage"
        android:layout_below="@+id/editTextNotificationMessageTag"
        android:layout_centerHorizontal="true"
        android:hint="@string/notification_message_hint" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/send_button"
        android:id="@+id/sendbutton"
        android:onClick="sendNotificationButtonOnClick"
        android:layout_below="@+id/editTextNotificationMessage"
        android:layout_centerHorizontal="true" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:id="@+id/text_hello"
        />
    </RelativeLayout>
    
  2. Öffnen Sie die Datei res/values/strings.xml, und ersetzen Sie die Definition send_button durch die folgenden Zeilen, um die Zeichenfolge für send_button neu zu definieren und Zeichenfolgen für die anderen Steuerelemente hinzuzufügen:

    <string name="usernameHint">Username</string>
    <string name="passwordHint">Password</string>
    <string name="loginButton">1. Sign in</string>
    <string name="send_button">2. Send Notification</string>
    <string name="notification_message_hint">Notification message</string>
    <string name="notification_message_tag_hint">Recipient username</string>
    

    Das grafische Layout von main_activity.xml sollte nun wie folgt aussehen:

    Screenshot of an emulator displaying what the main activity X M L graphical layout will look like.

  3. Erstellen Sie in dem Paket, in dem sich auch die Klasse MainActivity befindet, eine neue Klasse mit dem Namen RegisterClient. Verwenden Sie den folgenden Code für die neue Klassendatei.

    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.Set;
    
    import org.apache.http.HttpResponse;
    import org.apache.http.HttpStatus;
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.client.methods.HttpPut;
    import org.apache.http.client.methods.HttpUriRequest;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.apache.http.util.EntityUtils;
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    
    import android.content.Context;
    import android.content.SharedPreferences;
    import android.util.Log;
    
    public class RegisterClient {
        private static final String PREFS_NAME = "ANHSettings";
        private static final String REGID_SETTING_NAME = "ANHRegistrationId";
        private String Backend_Endpoint;
        SharedPreferences settings;
        protected HttpClient httpClient;
        private String authorizationHeader;
    
        public RegisterClient(Context context, String backendEndpoint) {
            super();
            this.settings = context.getSharedPreferences(PREFS_NAME, 0);
            httpClient =  new DefaultHttpClient();
            Backend_Endpoint = backendEndpoint + "/api/register";
        }
    
        public String getAuthorizationHeader() {
            return authorizationHeader;
        }
    
        public void setAuthorizationHeader(String authorizationHeader) {
            this.authorizationHeader = authorizationHeader;
        }
    
        public void register(String handle, Set<String> tags) throws ClientProtocolException, IOException, JSONException {
            String registrationId = retrieveRegistrationIdOrRequestNewOne(handle);
    
            JSONObject deviceInfo = new JSONObject();
            deviceInfo.put("Platform", "fcm");
            deviceInfo.put("Handle", handle);
            deviceInfo.put("Tags", new JSONArray(tags));
    
            int statusCode = upsertRegistration(registrationId, deviceInfo);
    
            if (statusCode == HttpStatus.SC_OK) {
                return;
            } else if (statusCode == HttpStatus.SC_GONE){
                settings.edit().remove(REGID_SETTING_NAME).commit();
                registrationId = retrieveRegistrationIdOrRequestNewOne(handle);
                statusCode = upsertRegistration(registrationId, deviceInfo);
                if (statusCode != HttpStatus.SC_OK) {
                    Log.e("RegisterClient", "Error upserting registration: " + statusCode);
                    throw new RuntimeException("Error upserting registration");
                }
            } else {
                Log.e("RegisterClient", "Error upserting registration: " + statusCode);
                throw new RuntimeException("Error upserting registration");
            }
        }
    
        private int upsertRegistration(String registrationId, JSONObject deviceInfo)
                throws UnsupportedEncodingException, IOException,
                ClientProtocolException {
            HttpPut request = new HttpPut(Backend_Endpoint+"/"+registrationId);
            request.setEntity(new StringEntity(deviceInfo.toString()));
            request.addHeader("Authorization", "Basic "+authorizationHeader);
            request.addHeader("Content-Type", "application/json");
            HttpResponse response = httpClient.execute(request);
            int statusCode = response.getStatusLine().getStatusCode();
            return statusCode;
        }
    
        private String retrieveRegistrationIdOrRequestNewOne(String handle) throws ClientProtocolException, IOException {
            if (settings.contains(REGID_SETTING_NAME))
                return settings.getString(REGID_SETTING_NAME, null);
    
            HttpUriRequest request = new HttpPost(Backend_Endpoint+"?handle="+handle);
            request.addHeader("Authorization", "Basic "+authorizationHeader);
            HttpResponse response = httpClient.execute(request);
            if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                Log.e("RegisterClient", "Error creating registrationId: " + response.getStatusLine().getStatusCode());
                throw new RuntimeException("Error creating Notification Hubs registrationId");
            }
            String registrationId = EntityUtils.toString(response.getEntity());
            registrationId = registrationId.substring(1, registrationId.length()-1);
    
            settings.edit().putString(REGID_SETTING_NAME, registrationId).commit();
    
            return registrationId;
        }
    }
    

    Diese Komponente implementiert die REST-Aufrufe, die für das Kontaktieren des App-Back-Ends erforderlich sind, um sich für Pushbenachrichtigungen zu registrieren. Außerdem werden die vom Notification Hub erstellten registrationIds lokal gespeichert, wie unter Registrierung vom App-Back-End ausbeschrieben. Wenn Sie die Schaltfläche Anmelden verwenden, wird ein Authentifizierungstoken aus dem lokalen Speicher verwendet.

  4. Fügen Sie in Ihrer MainActivity-Klasse ein Feld für die RegisterClient-Klasse und eine Zeichenfolge für den Endpunkt Ihres ASP.NET-Back-Ends hinzu. Ersetzen Sie <Enter Your Backend Endpoint> unbedingt durch den tatsächlichen Back-End-Endpunkt, den Sie zuvor abgerufen haben. Beispiel: http://mybackend.azurewebsites.net.

    private RegisterClient registerClient;
    private static final String BACKEND_ENDPOINT = "<Enter Your Backend Endpoint>";
    FirebaseInstanceId fcm;
    String FCM_token = null;
    
  5. Entfernen Sie in der MainActivity-Klasse in der onCreate-Methode die Initialisierung des hub-Felds, oder kommentieren Sie sie aus, und rufen Sie die registerWithNotificationHubs-Methode auf. Fügen Sie dann Code zum Initialisieren einer Instanz der RegisterClient -Klasse hinzu. Die Methode sollte die folgenden Zeilen enthalten:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        mainActivity = this;
        FirebaseService.createChannelAndHandleNotifications(getApplicationContext());
        fcm = FirebaseInstanceId.getInstance();
        registerClient = new RegisterClient(this, BACKEND_ENDPOINT);
        setContentView(R.layout.activity_main);
    }
    
  6. Fügen Sie der Datei MainActivity.java die folgenden import-Anweisungen hinzu:

    import android.util.Base64;
    import android.view.View;
    import android.widget.EditText;
    
    import android.widget.Button;
    import android.widget.ToggleButton;
    import java.io.UnsupportedEncodingException;
    import android.content.Context;
    import java.util.HashSet;
    import android.widget.Toast;
    import org.apache.http.client.ClientProtocolException;
    import java.io.IOException;
    import org.apache.http.HttpStatus;
    
    import android.os.AsyncTask;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.DefaultHttpClient;
    
    import android.app.AlertDialog;
    import android.content.DialogInterface;
    
    import com.google.firebase.iid.FirebaseInstanceId;
    import com.google.firebase.iid.InstanceIdResult;
    import com.google.android.gms.tasks.OnSuccessListener;
    import java.util.concurrent.TimeUnit;
    
  7. Ersetzen Sie den Code in der onStart-Methode durch den folgenden Code:

    super.onStart();
    Button sendPush = (Button) findViewById(R.id.sendbutton);
    sendPush.setEnabled(false);
    
  8. Fügen Sie dann die folgenden Methoden zum Verarbeiten des Click-Ereignisses der Schaltfläche Anmelden und zum Senden von Pushbenachrichtigungen hinzu.

    public void login(View view) throws UnsupportedEncodingException {
        this.registerClient.setAuthorizationHeader(getAuthorizationHeader());
    
        final Context context = this;
        new AsyncTask<Object, Object, Object>() {
            @Override
            protected Object doInBackground(Object... params) {
                try {
    
                    FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
                        @Override
                        public void onSuccess(InstanceIdResult instanceIdResult) {
                            FCM_token = instanceIdResult.getToken();
                            Log.d(TAG, "FCM Registration Token: " + FCM_token);
                        }
                    });
                    TimeUnit.SECONDS.sleep(1);
                    registerClient.register(FCM_token, new HashSet<String>());
                } catch (Exception e) {
                    DialogNotify("MainActivity - Failed to register", e.getMessage());
                    return e;
                }
                return null;
            }
    
            protected void onPostExecute(Object result) {
                Button sendPush = (Button) findViewById(R.id.sendbutton);
                sendPush.setEnabled(true);
                Toast.makeText(context, "Signed in and registered.",
                        Toast.LENGTH_LONG).show();
            }
        }.execute(null, null, null);
    }
    
    private String getAuthorizationHeader() throws UnsupportedEncodingException {
        EditText username = (EditText) findViewById(R.id.usernameText);
        EditText password = (EditText) findViewById(R.id.passwordText);
        String basicAuthHeader = username.getText().toString()+":"+password.getText().toString();
        basicAuthHeader = Base64.encodeToString(basicAuthHeader.getBytes("UTF-8"), Base64.NO_WRAP);
        return basicAuthHeader;
    }
    
    /**
        * This method calls the ASP.NET WebAPI backend to send the notification message
        * to the platform notification service based on the pns parameter.
        *
        * @param pns     The platform notification service to send the notification message to. Must
        *                be one of the following ("wns", "fcm", "apns").
        * @param userTag The tag for the user who will receive the notification message. This string
        *                must not contain spaces or special characters.
        * @param message The notification message string. This string must include the double quotes
        *                to be used as JSON content.
        */
    public void sendPush(final String pns, final String userTag, final String message)
            throws ClientProtocolException, IOException {
        new AsyncTask<Object, Object, Object>() {
            @Override
            protected Object doInBackground(Object... params) {
                try {
    
                    String uri = BACKEND_ENDPOINT + "/api/notifications";
                    uri += "?pns=" + pns;
                    uri += "&to_tag=" + userTag;
    
                    HttpPost request = new HttpPost(uri);
                    request.addHeader("Authorization", "Basic "+ getAuthorizationHeader());
                    request.setEntity(new StringEntity(message));
                    request.addHeader("Content-Type", "application/json");
    
                    HttpResponse response = new DefaultHttpClient().execute(request);
    
                    if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                        DialogNotify("MainActivity - Error sending " + pns + " notification",
                                response.getStatusLine().toString());
                        throw new RuntimeException("Error sending notification");
                    }
                } catch (Exception e) {
                    DialogNotify("MainActivity - Failed to send " + pns + " notification ", e.getMessage());
                    return e;
                }
    
                return null;
            }
        }.execute(null, null, null);
    }
    

    Der login-Handler für die Schaltfläche Anmelden generiert unter Verwendung des eingegebenen Benutzernamens und Kennworts ein Standardauthentifizierungstoken (dies kann ein beliebiges in Ihrem Authentifizierungsschema verwendetes Token sein) und verwendet dann RegisterClient zum Aufrufen des Back-Ends für die Registrierung.

    Die sendPush -Methode ruft das Back-End auf, um basierend auf der Benutzermarkierung eine sichere Benachrichtigung auszulösen. Der Plattformbenachrichtigungsdienst, auf den sendPush verweist, hängt von der übergebenen pns-Zeichenfolge ab.

  9. Fügen Sie der MainActivity-Klasse die folgende DialogNotify-Methode hinzu.

    protected void DialogNotify(String title, String message)
    {
        AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this).create();
        alertDialog.setTitle(title);
        alertDialog.setMessage(message);
        alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
        alertDialog.show();
    }
    
  10. Aktualisieren Sie in der MainActivity-Klasse die sendNotificationButtonOnClick-Methode so, dass sie wie folgt die sendPush-Methode mit den ausgewählten Plattformbenachrichtigungsdiensten des Benutzers aufruft.

    /**
    * Send Notification button click handler. This method sends the push notification
    * message to each platform selected.
    *
    * @param v The view
    */
    public void sendNotificationButtonOnClick(View v)
            throws ClientProtocolException, IOException {
    
        String nhMessageTag = ((EditText) findViewById(R.id.editTextNotificationMessageTag))
                .getText().toString();
        String nhMessage = ((EditText) findViewById(R.id.editTextNotificationMessage))
                .getText().toString();
    
        // JSON String
        nhMessage = "\"" + nhMessage + "\"";
    
        if (((ToggleButton)findViewById(R.id.toggleButtonWNS)).isChecked())
        {
            sendPush("wns", nhMessageTag, nhMessage);
        }
        if (((ToggleButton)findViewById(R.id.toggleButtonFCM)).isChecked())
        {
            sendPush("fcm", nhMessageTag, nhMessage);
        }
        if (((ToggleButton)findViewById(R.id.toggleButtonAPNS)).isChecked())
        {
            sendPush("apns", nhMessageTag, nhMessage);
        }
    }
    
  11. Fügen Sie dem Abschnitt android in der Datei build.gradle nach dem Abschnitt buildTypes die folgende Zeile hinzu:

    useLibrary 'org.apache.http.legacy'
    
  12. Wenn Ihre App auf API-Ebene 28 (Android 9.0) oder höher ausgerichtet ist, schließen Sie die folgende Deklaration in das <application>-Element von AndroidManifest.xml ein.

    <uses-library
        android:name="org.apache.http.legacy"
        android:required="false" />
    
  13. Erstellen Sie das Projekt.

Testen der App

  1. Führen Sie die Anwendung unter Verwendung von Android Studio auf einem Gerät oder einen Emulator aus.

  2. Geben Sie in der Android-App einen Benutzernamen und ein Kennwort ein. Beide müssen den gleichen Zeichenfolgenwert aufweisen und dürfen keine Leerzeichen oder Sonderzeichen enthalten.

  3. Tippen Sie in der Android-App auf Anmelden. Warten Sie, bis die Popupmeldung Angemeldet und registriertangezeigt wird. Dadurch wird die Schaltfläche Send Notification (Benachrichtigung senden) aktiviert.

    Screenshot of an emulator showing what the Notification Hubs Notify Users app looks like after logging in.

  4. Klicken Sie auf die Umschaltflächen, um alle Plattformen zu aktivieren, auf denen Sie die App ausgeführt und einen Benutzer registriert haben.

  5. Geben Sie den Namen des Benutzers ein, der die Benachrichtigungsmeldung erhält. Dieser Benutzer muss für Benachrichtigungen auf dem Zielgerät registriert werden.

  6. Geben Sie eine Nachricht für den Benutzer ein, die als Pushbenachrichtigungsmeldung empfangen wird.

  7. Tippen Sie auf Send Notification. Die Pushbenachrichtigung wird auf jedem Gerät empfangen, das für die übereinstimmende Benutzernamensmarkierung registriert ist.

Nächste Schritte

In diesem Tutorial haben Sie gelernt, wie Sie Pushbenachrichtigungen an bestimmte Benutzer senden, deren Registrierungen Tags zugeordnet sind. Um zu erfahren, wie Sie standortbasierte Pushbenachrichtigungen senden, fahren Sie mit dem folgenden Tutorial fort: