Samouczek: wysyłanie powiadomień wypychanych do określonych aplikacji systemu Android przy użyciu usługi Azure Notification Hubs

Uwaga

Aby uzyskać informacje na temat wycofywania i migracji usługi Firebase Cloud Messaging, zobacz Migracja usługi Google Firebase Cloud Messaging.

W tym samouczku pokazano, jak wysyłać powiadomienia push do użytkownika konkretnej aplikacji na konkretnym urządzeniu za pomocą usługi Azure Notification Hubs. Zaplecze ASP.NET interfejsu WebAPI jest używane do uwierzytelniania klientów oraz generowania powiadomień, jak pokazano w artykule ze wskazówkami Rejestrowanie z poziomu zaplecza aplikacji. Ten samouczek opiera się na centrum powiadomień utworzonym w artykule Samouczek: wypychanie powiadomień do urządzeń z systemem Android przy użyciu usług Azure Notification Hubs i Firebase Cloud Messaging.

W tym samouczku wykonasz następujące kroki:

  • Tworzenie projektu zaplecza interfejsu WebAPI, które będzie uwierzytelniać użytkowników.
  • Aktualizowanie aplikacji systemu Android.
  • Testowanie aplikacji

Wymagania wstępne

Ukończ samouczek: wysyłanie powiadomień wypychanych do urządzeń z systemem Android przy użyciu usług Azure Notification Hubs i Firebase Cloud Messaging przed wykonaniem tego samouczka.

Tworzenie projektu interfejsu WebAPI

W poniższych sekcjach omówiono proces tworzenia nowego zaplecza interfejsu WebAPI platformy ASP.NET. Ten proces ma trzy główne cele:

  • Uwierzytelnianie klientów: procedura obsługi komunikatów jest dodawana w celu uwierzytelnienia żądań klientów i kojarzenia użytkownika z żądaniem.
  • Rejestrowanie do używania powiadomień za pomocą zaplecza interfejsu WebAPI: kontroler jest dodawany w celu obsługi nowych rejestracji, aby urządzenie klienckie mogło otrzymywać powiadomienia. Nazwa uwierzytelnionego użytkownika jest automatycznie dodawana do rejestracji jako tag.
  • Wysyłanie powiadomień do klientów: jest dodawany kontroler udostępniający użytkownikom możliwość wyzwalania bezpiecznej operacji wypychania do urządzeń i klientów skojarzonych z tagiem.

Utwórz nowe zaplecze internetowego interfejsu API platformy ASP.NET Core 6.0, wykonując następujące czynności:

Aby to sprawdzić, uruchom program Visual Studio. W menu Narzędzia wybierz pozycję Rozszerzenia i aktualizacje. Wyszukaj pozycję Menedżer pakietów NuGet w swojej wersji programu Visual Studio i sprawdź, czy masz najnowszą wersję. Jeśli nie używasz najnowszej wersji, odinstaluj ją i ponownie zainstaluj Menedżera pakietów NuGet.

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

Uwaga

Upewnij się, że masz zainstalowany zestaw Azure SDK programu Visual Studio na potrzeby wdrażania witryny internetowej.

  1. Uruchom program Visual Studio lub Visual Studio Express.

  2. Wybierz pozycję Eksplorator serwera i zaloguj się do konta platformy Azure. Aby tworzyć zasoby witryny internetowej na swoim koncie, musisz się zalogować.

  3. W menu Plik programu Visual Studio wybierz pozycję Nowy>projekt.

  4. Wprowadź internetowy interfejs API w polu wyszukiwania.

  5. Wybierz szablon projektu internetowego interfejsu API platformy ASP.NET Core, a następnie wybierz pozycję Dalej.

  6. W oknie dialogowym Konfigurowanie nowego projektu nadaj projektowi nazwę AppBackend i wybierz pozycję Dalej.

  7. W oknie dialogowym Dodatkowe informacje:

    • Upewnij się, że platforma .NET 6.0 (obsługa długoterminowa).
    • Upewnij się, że pole wyboru Użyj kontrolerów (usuń zaznaczenie pola wyboru, aby używać minimalnych interfejsów API) jest zaznaczone.
    • Usuń zaznaczenie pola wyboru Włącz obsługę interfejsu OpenAPI.
    • Wybierz pozycję Utwórz.

Usuwanie plików szablonów WeatherForecast

  1. Usuń przykładowe pliki WeatherForecast.cs i Controllers/WeatherForecastController.cs z nowego projektu AppBackend .
  2. Otwórz plik Properties\launch Ustawienia.json.
  3. Zmień właściwości launchUrl z weatherforcast na appbackend.

W oknie Konfigurowanie aplikacji internetowej platformy Microsoft Azure wybierz subskrypcję, a następnie na liście Plan usługi App Service wykonaj jedną z następujących akcji:

  • Wybierz plan usługi aplikacja systemu Azure, który został już utworzony.
  • Wybierz pozycję Utwórz nowy plan usługi App Service, a następnie utwórz plan.

Ten samouczek nie wymaga bazy danych. Po wybraniu planu usługi App Service kliknij przycisk OK, aby utworzyć projekt.

The Configure Microsoft Azure Web App window

Jeśli nie widzisz tej strony na potrzeby konfigurowania planu usługi App Service, przejdź do samouczka. Można ją skonfigurować podczas publikowania aplikacji później.

Uwierzytelnianie klientów w zapleczu interfejsu WebAPI

W tej sekcji tworzysz nową klasę procedury obsługi komunikatów o nazwie AuthenticationTestHandler dla nowego zaplecza. Ta klasa pochodzi od klasy DelegatingHandler i jest dodawana jako procedura obsługi komunikatów, aby umożliwić przetwarzanie wszystkich żądań przychodzących do zaplecza.

  1. W Eksploratorze rozwiązań kliknij prawym przyciskiem myszy projekt AppBackend, wybierz polecenie Dodaj, a następnie wybierz pozycję Klasa.

  2. Nadaj nowej klasie nazwę AuthenticationTestHandler.cs, a następnie wybierz pozycję Dodaj, aby wygenerować klasę. Ta klasa służy do uwierzytelniania użytkowników za pomocą Uwierzytelniania podstawowego dla uproszczenia. Twoja aplikacja może używać dowolnego schematu uwierzytelniania.

  3. W klasie AuthenticationTestHandler.cs dodaj następujące instrukcje using:

    using System.Net.Http;
    using System.Threading;
    using System.Security.Principal;
    using System.Net;
    using System.Text;
    using System.Threading.Tasks;
    
  4. W klasie AuthenticationTestHandler.cs zastąp definicję klasy AuthenticationTestHandler następującym kodem:

    Ta procedura obsługi autoryzuje żądanie, gdy następujące trzy warunki zostaną spełnione:

    • Żądanie zawiera nagłówek Authorization.
    • Żądanie używa uwierzytelniania basic.
    • Ciąg nazwy użytkownika i ciąg hasła to ten sam ciąg.

    W przeciwnym razie żądanie jest odrzucane. To uwierzytelnianie nie reprezentuje rzeczywistego podejścia do uwierzytelniania i autoryzacji. Jest to wyłącznie prosty przykład na potrzeby tego samouczka.

    Jeśli komunikat żądania jest uwierzytelniany i autoryzowany przez klasę AuthenticationTestHandler, użytkownik uwierzytelniania podstawowego jest dołączany do bieżącego żądania w obiekcie HttpContext. Informacje o użytkowniku w obiekcie HttpContext zostaną później użyte przez inny kontroler (RegisterController) w celu dodania tagu do żądania rejestracji powiadomienia.

    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;
        }
    }
    

    Uwaga

    Uwaga dotycząca zabezpieczeń: klasa AuthenticationTestHandler nie zapewnia rzeczywistego uwierzytelniania. Jest ona używana tylko do naśladowania uwierzytelniania podstawowego i nie jest bezpieczna. W swoich aplikacjach i usługach produkcyjnych musisz zaimplementować mechanizm bezpiecznego uwierzytelniania.

  5. Aby zarejestrować procedurę obsługi komunikatów, dodaj następujący kod na końcu Register metody w pliku Program.cs :

    config.MessageHandlers.Add(new AuthenticationTestHandler());
    
  6. Zapisz zmiany.

Rejestrowanie na potrzeby powiadomień za pomocą zaplecza interfejsu WebAPI

W tej sekcji dodajesz nowy kontroler do zaplecza interfejsu WebAPI w celu obsługi żądań rejestracji użytkownika i urządzenia do otrzymywania powiadomień przy użyciu biblioteki klienta dla centrów powiadomień. Kontroler dodaje tag użytkownika, który został uwierzytelniony i dołączony do obiektu HttpContext przez klasę AuthenticationTestHandler. Tag ma format ciągu "username:<actual username>".

  1. W Eksploratorze rozwiązań kliknij prawym przyciskiem myszy projekt AppBackend, a następnie wybierz polecenie Zarządzaj pakietami NuGet.

  2. W okienku po lewej stronie wybierz pozycję Online, a następnie w polu Wyszukaj wpisz ciąg Microsoft.Azure.NotificationHubs.

  3. Na liście wyników wybierz pozycję Microsoft Azure Notification Hubs, a następnie wybierz pozycję Instaluj. Zakończ instalację, a następnie zamknij okno Menedżera pakietów NuGet.

    Ta akcja spowoduje dodanie odwołania do zestawu SDK usługi Azure Notification Hubs z użyciem pakietu NuGet Microsoft.Azure.Notification Hubs.

  4. Utwórz plik nowej klasy, która reprezentuje połączenie z centrum powiadomień używane do wysyłania powiadomień. W Eksploratorze rozwiązań kliknij prawym przyciskiem myszy folder Modele, wybierz polecenie Dodaj, a następnie kliknij pozycję Klasa. Nadaj nowej klasie nazwę Notifications.cs, a następnie wybierz pozycję Dodaj, aby wygenerować klasę.

    The Add New Item window

  5. W klasie Notifications.cs dodaj następującą instrukcję using na początku pliku:

    using Microsoft.Azure.NotificationHubs;
    
  6. Zastąp definicję klasy Notifications poniższym kodem i zastąp dwa symbole zastępcze parametrami połączenia (z pełnym dostępem) dla Twojego centrum powiadomień i nazwą centrum (dostępną w witrynie 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>");
        }
    }
    

    Ważne

    Wprowadź nazwę i defaultFullSharedAccessSignature centrum przed kontynuowaniem.

  7. Następnie utwórz nowy kontroler o nazwie RegisterController. W Eksploratorze rozwiązań kliknij prawym przyciskiem myszy folder Kontrolery, wybierz polecenie Dodaj, a następnie kliknij pozycję Kontroler.

  8. Wybierz pozycję Kontroler interfejsu API — pusty, a następnie wybierz pozycję Dodaj.

  9. W polu Nazwa kontrolera wpisz ciąg RegisterController, aby nadać nazwę nowej klasie, a następnie wybierz pozycję Dodaj.

    The Add Controller window.

  10. W pliku RegisterController.cs dodaj następujące instrukcje using:

    using Microsoft.Azure.NotificationHubs;
    using Microsoft.Azure.NotificationHubs.Messaging;
    using AppBackend.Models;
    using System.Threading.Tasks;
    using System.Web;
    
  11. Dodaj następujący kod wewnątrz definicji klasy RegisterController. W tym kodzie dodajesz tag użytkownika, który został dołączony do obiektu HttpContext. Użytkownik został uwierzytelniony i dołączony do obiektu HttpContext przez dodany przez Ciebie filtr komunikatów, AuthenticationTestHandler. Można również dodać opcjonalne sprawdzenia w celu weryfikacji, czy użytkownik ma uprawnienia do rejestrowania żądanych tagów.

    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. Zapisz zmiany.

Wysyłanie powiadomień z zaplecza interfejsu WebAPI

W tej sekcji dodasz nowego kontrolera, który opisuje sposób wysyłania powiadomień z urządzeń klienckich. Powiadomienie opiera się na tagu nazwy użytkownika, który używa biblioteki .NET usługi Azure Notification Hubs w zaplecze interfejsu WebAPI na platformie ASP.NET.

  1. Utwórz innego nowego kontrolera o nazwie NotificationsController w taki sam sposób, jak utworzono kontrolera RegisterController w poprzedniej sekcji.

  2. W pliku NotificationsController.cs dodaj następujące instrukcje using:

    using AppBackend.Models;
    using System.Threading.Tasks;
    using System.Web;
    
  3. Dodaj następującą metodę do klasy NotificationsController:

    Ten kod wysyła typ powiadomienia na podstawie parametru pns usługi powiadomień platformy (PNS, Platform Notification Service). Wartość to_tag służy do ustawiania tagu username w komunikacie. Ten tag musi być zgodny z tagiem username aktywnej rejestracji centrum powiadomień. Komunikat powiadomienia jest pobierany z treści żądania POST i formatowany dla docelowej usługi PNS.

    W zależności od usługi PNS używanej do odbierania powiadomień przez obsługiwane urządzenia powiadomienia są obsługiwane przy użyciu różnych formatów. Na przykład w przypadku urządzeń z systemem Windows można użyć wyskakujących powiadomień za pomocą usługi WNS, które nie są bezpośrednio obsługiwane przez inną usługę PNS. W takim przypadku zaplecze musi sformatować powiadomienie jako obsługiwane powiadomienie w przypadku usługi PNS urządzeń, które planujesz obsługiwać. Następnie użyj odpowiedniego interfejsu API wysyłania w klasie NotificationHubClient.

    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. Aby uruchomić aplikację i sprawdzić dokładność pracy wykonanej do tej pory, naciśnij klawisz F5. Aplikacja otwiera przeglądarkę internetową z wyświetloną stroną główną platformy ASP.NET.

Publikowanie nowego zaplecza interfejsu WebAPI

Następnie wdrożysz tę aplikację w witrynie internetowej platformy Azure, aby udostępnić ją wszystkim urządzeniom.

  1. Kliknij prawym przyciskiem myszy projekt AppBackend, a następnie wybierz polecenie Publikuj.

  2. Wybierz pozycję Microsoft Azure App Service jako docelową lokalizację publikacji, a następnie wybierz pozycję \*\*Publikuj. Zostanie otwarte okno Tworzenie usługi App Service. W tym miejscu możesz tworzyć wszystkie niezbędne zasoby platformy Azure służące do uruchamiania aplikacji internetowej ASP.NET na platformie Azure.

    The Microsoft Azure App Service tile

  3. W oknie Tworzenie usługi App Service wybierz swoje konto platformy Azure. Wybierz kolejno pozycje Zmień typ>Aplikacja internetowa. Zachowaj wartość domyślną w polu Nazwa aplikacji internetowej i wybierz wartości w polach Subskrypcja, Grupa zasobów i Plan usługi App Service.

  4. Wybierz pozycję Utwórz.

  5. Zanotuj wartość właściwości Adres URL witryny w sekcji Podsumowanie. Ten adres URL jest Twoim punktem końcowym zaplecza w dalszej części samouczka.

  6. Wybierz Publikuj.

Po ukończeniu pracy z kreatorem aplikacja internetowa ASP.NET zostanie opublikowana na platformie Azure, a następnie otwarta w przeglądarce domyślnej. Twoja aplikacja jest widoczna w usłudze Azure App Services.

Adres URL używa określonej wcześniej nazwy aplikacji internetowej z formatem http://< app_name.azurewebsites.net>.

Tworzenie projektu systemu Android

Następnym krokiem jest zaktualizowanie aplikacji systemu Android utworzonej w artykule Samouczek: wysyłanie powiadomień wypychanych do urządzeń z systemem Android przy użyciu usług Azure Notification Hubs i Firebase Cloud Messaging.

  1. Otwórz plik res/layout/activity_main.xml i zastąp następujące definicje zawartości:

    Spowoduje to dodanie kontrolek EditText na potrzeby logowania się jako użytkownik. Ponadto zostanie dodane pole na potrzeby tagu nazwy użytkownika, które będzie częścią wysyłanych powiadomień:

    <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. Otwórz plik res/values/strings.xml i zastąp definicję kontrolki send_button następującymi wierszami, które ponownie definiują ciąg kontrolki send_button i dodają ciągi dla innych kontrolek:

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

    Twój układ graficzny pliku main_activity.xml powinien wyglądać teraz podobnie do poniższego:

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

  3. Utwórz nową klasę o nazwie RegisterClient w tym samym pakiecie, w którym znajduje się klasa MainActivity. Użyj poniższego kodu dla nowego pliku klasy.

    
    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;
        }
    }
    

    Ten składnik implementuje wywołania REST wymagane do skontaktowania się z zapleczem aplikacji w celu zarejestrowania się w celu otrzymywania powiadomień wypychanych. Ponadto zapisuje lokalnie identyfikatory registrationId utworzone przez centrum powiadomień zgodnie z opisem w sekcji Rejestrowanie z poziomu zaplecza aplikacji. Używa tokenu autoryzacji przechowywanego w magazynie lokalnym po kliknięciu przycisku Zaloguj.

  4. MainActivity W klasie dodaj pole dla RegisterClient klasy i ciąg punktu końcowego zaplecza ASP.NET. Pamiętaj, aby zastąpić ciąg <Enter Your Backend Endpoint> wcześniej pozyskanym, faktycznym punktem końcowym zaplecza. Na przykład http://mybackend.azurewebsites.net.

    private RegisterClient registerClient;
    private static final String BACKEND_ENDPOINT = "<Enter Your Backend Endpoint>";
    FirebaseInstanceId fcm;
    String FCM_token = null;
    
  5. W swojej klasie MainActivity w metodzie onCreate usuń lub oznacz jako komentarz inicjowanie pola hub oraz wywołanie metody registerWithNotificationHubs. Następnie dodaj kod, aby zainicjować wystąpienie klasy RegisterClient. Metoda powinna zawierać następujące wiersze:

    @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. Dodaj następujące instrukcje import do pliku MainActivity.java:

    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. Zastąp kod w metodzie onStart następującym:

    super.onStart();
    Button sendPush = (Button) findViewById(R.id.sendbutton);
    sendPush.setEnabled(false);
    
  8. Następnie dodaj następujące metody do obsługi zdarzenia kliknięcia przycisku Zaloguj i wysyłania powiadomień wypychanych.

    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);
    }
    

    Procedura login obsługi przycisku Zaloguj generuje podstawowy token uwierzytelniania przy użyciu nazwy użytkownika i hasła wejściowego (reprezentuje dowolny token używany przez schemat uwierzytelniania), a następnie używa RegisterClient metody do wywołania zaplecza na potrzeby rejestracji.

    Metoda sendPush wywołuje zaplecze, aby wyzwolić bezpieczne powiadomienie do użytkownika w oparciu o tag użytkownika. Docelowa usługa powiadomień platformy dla metody sendPush zależy od przekazanego ciągu pns.

  9. Dodaj następującą metodę DialogNotify do klasy MainActivity.

    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. W swojej klasie MainActivity zaktualizuj metodę sendNotificationButtonOnClick, aby wywołać metodę sendPush przy użyciu wybranych przez użytkownika usług powiadomień platformy, jak pokazano poniżej.

    /**
    * 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. W pliku build.gradle dodaj następujący wiersz do sekcji android po sekcji buildTypes.

    useLibrary 'org.apache.http.legacy'
    
  12. Jeśli aplikacja jest przeznaczona dla interfejsu API poziomu 28 (Android 9.0) lub nowszego, dołącz następującą deklarację w elemecie <application>AndroidManifest.xml.

    <uses-library
        android:name="org.apache.http.legacy"
        android:required="false" />
    
  13. Skompiluj projekt.

Testowanie aplikacji

  1. Uruchom aplikację na urządzeniu lub emulatorze przy użyciu programu Android Studio.

  2. W aplikacji systemu Android wprowadź nazwę użytkownika i hasło. Oba muszą być taką samą wartością ciągu i nie mogą zawierać spacji ani znaków specjalnych.

  3. W aplikacji dla systemu Android kliknij pozycję Zaloguj. Poczekaj na wyskakujący komunikat z informacją o zalogowaniu i zarejestrowaniu. Spowoduje to włączenie przycisku Send Notification (Wyślij powiadomienie).

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

  4. Kliknij przyciski przełączania, aby włączyć wszystkie platformy, na których uruchomiono aplikację i zarejestrowano użytkownika.

  5. Wprowadź nazwę użytkownika, który odbierze powiadomienie. Ten użytkownik musi być zarejestrowany na potrzeby otrzymywania powiadomień na urządzeniach docelowych.

  6. Wpisz wiadomość dla użytkownika, która zostanie odebrana w formie powiadomienia push.

  7. Kliknij przycisk Send Notification (Wyślij powiadomienie). Każde urządzenie, które zostało zarejestrowane przy użyciu pasującego tagu nazwy użytkownika, otrzyma powiadomienie push.

Następne kroki

W tym samouczku przedstawiono sposób wysyłania powiadomień push do konkretnych użytkowników, którzy mają tagi skojarzone ze swoimi rejestracjami. Aby dowiedzieć się, jak wypychać powiadomienia oparte na lokalizacji, przejdź do następującego samouczka: