Tutorial: Enviar notificações por push para aplicativos Android específicos usando os Hubs de Notificação do Azure

Observação

Para obter informações sobre as etapas de substituição e migração do Firebase Cloud Messaging, confira Migração do Google Firebase Cloud Messaging.

Este tutorial mostra como usar os Hubs de Notificação do Azure para enviar notificações por push a um usuário específico do aplicativo em um dispositivo específico. Um back-end da API Web ASP.NET é usado para autenticar clientes e gerar notificações, conforme mostrado no artigo de diretrizes Registrando-se por meio do back-end do aplicativo. Este tutorial se baseia no hub de notificação e que você criou no Tutorial: Enviar notificações por push para dispositivos Android usando os Hubs de Notificação do Microsoft Azure e o Firebase Cloud Messaging.

Neste tutorial, você deve executar as seguintes etapas:

  • Crie o projeto de API da Web de back-end que autentica os usuários.
  • Atualize o aplicativo Android.
  • Testar o aplicativo

Pré-requisitos

Conclua o Tutorial: Enviar notificações por push para dispositivos Android usando Hubs de Notificação do Microsoft Azure e o Firebase Cloud Messaging antes de realizar este tutorial.

Criar o projeto WebAPI

As seções a seguir abordam a criação de um novo back-end WebAPI ASP.NET. Esse processo tem três objetivos principais:

  • Autenticar clientes: adicione um manipulador de mensagens para autenticar solicitações de cliente e associar o usuário à solicitação.
  • Registrar para receber notificações usando o back-end WebAPI: adicione um controlador para lidar com novos registros para que um dispositivos clientes recebam notificações. O nome de usuário autenticado é automaticamente adicionado ao registro como uma marca.
  • Enviar notificações aos clientes: adicione um controlador para permitir aos usuários disparar um envio por push seguro para dispositivos e clientes associados à marca.

Crie o novo back-end da API Web do ASP.NET 6.0 Core executando estas ações:

Para verificar, inicie o Visual Studio. No menu Ferramentas, selecione Extensões e Atualizações. Pesquise por Gerenciador de Pacotes NuGet na sua versão do Visual Studio e verifique se a versão mais recente está instalada. Se a versão não for a versão mais recente, desinstale-a e reinstale o Gerenciador de Pacotes NuGet.

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

Observação

Verifique se você instalou o SDK do Azure do Visual Studio para implantação de site.

  1. Inicie o Visual Studio ou o Visual Studio Express.

  2. Selecione Gerenciador de Servidores e entre na sua conta do Azure. Para criar os recursos de site na sua conta, você precisará estar conectado.

  3. No menu Arquivo do Visual Studio, selecione Novo>Projeto.

  4. Insira API Web na caixa de pesquisa.

  5. Selecione o modelo do projeto da API Web do ASP.NET Core e, em seguida, Avançar.

  6. Na caixa de diálogo Configurar o novo projeto, nomeie o projeto AppBackend e selecione Avançar.

  7. Na caixa de diálogo Informações adicionais:

    • Confirme se o Framework é o .NET 6.0 (suporte de longo prazo).
    • Confirme se a caixa de seleção para Usar controladores (desmarcar para usar APIs mínimas) está marcada.
    • Desmarque Habilitar suporte a OpenAPI.
    • Selecione Criar.

Remover os arquivos de modelo WeatherForecast

  1. Remova os arquivos de exemplo WeatherForecast.cs e Controllers/WeatherForecastController.cs do novo projeto AppBackend.
  2. Abra Properties\launchSettings.json.
  3. Altere as propriedades launchUrl de weatherforcast para appbackend.

Na janela Configurar o Aplicativo Web do Microsoft Azure, selecione uma assinatura e, na lista Plano do Serviço de Aplicativo, execute uma destas ações:

  • Selecione um plano do Serviço de Aplicativo do Azure que você já criou.
  • Selecione Criar um novo plano do serviço de aplicativo para criar um.

Não é necessário um banco de dados para este tutorial. Depois que você tiver selecionado o seu plano de serviço de aplicativo, selecione OK para criar o projeto.

The Configure Microsoft Azure Web App window

Se você não vir essa página para configurar o plano do serviço de aplicativo, continue com o tutorial. Você pode configurá-la ao publicar o aplicativo mais tarde.

Autenticar clientes para o back-end da WebAPI

Nesta seção, você cria uma nova classe de manipulador de mensagens denominada AuthenticationTestHandler para o novo back-end. Essa classe é derivada de DelegatingHandler e adicionada como um manipulador de mensagens para poder processar todas as solicitações que chegam ao back-end.

  1. No Gerenciador de Soluções, clique com botão direito do mouse no projeto AppBackend, selecione Adicionare selecione Classe.

  2. Nomeie a nova classe AuthenticationTestHandler.cs e selecione Adicionar para gerar a classe. Essa classe usa Autenticação Básica para manter a simplicidade na autenticação dos usuários. Seu aplicativo pode utilizar qualquer esquema de autenticação.

  3. Em AuthenticationTestHandler.cs, adicione as seguintes instruções using:

    using System.Net.Http;
    using System.Threading;
    using System.Security.Principal;
    using System.Net;
    using System.Text;
    using System.Threading.Tasks;
    
  4. Em AuthenticationTestHandler.cs, substitua a definição da classe AuthenticationTestHandler pelo código a seguir:

    Esse manipulador autoriza a solicitação quando as três seguintes condições a seguir forem verdadeiras:

    • A solicitação inclui um cabeçalho de Autorização.
    • A solicitação usa a autenticação básica .
    • A cadeia de caracteres de nome de usuário e a cadeia de caracteres de senha são iguais.

    Caso contrário, a solicitação é rejeitada. Essa não é uma abordagem de autenticação e autorização verdadeira. É apenas um exemplo simples para este tutorial.

    Se a mensagem de solicitação for autenticada e autorizada pelo AuthenticationTestHandler, o usuário de autenticação básica será anexado à solicitação atual no HttpContext. As informações do usuário no HttpContext serão usadas por outro controlador (RegisterController) posteriormente para adicionar uma marca à solicitação de registro de notificação.

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

    Observação

    Nota de segurança: a classe AuthenticationTestHandler não oferece autenticação verdadeira. Ela é usada somente para imitar a autenticação básica e não é segura. Você deve implementar um mecanismo de autenticação seguro em seus aplicativos e serviços de produção.

  5. Para registrar o manipulador de mensagens, adicione o seguinte código ao final do método Register no arquivo Program.cs:

    config.MessageHandlers.Add(new AuthenticationTestHandler());
    
  6. Salve suas alterações.

Registrar para receber notificações usando o back-end da WebAPI

Nesta seção, você adiciona um novo controlador ao back-end WebAPI para manipular solicitações e registrar um usuário e um dispositivo para notificações usando a biblioteca de cliente dos hubs de notificação. O controlador adiciona uma marca de usuário ao usuário que foi autenticado e anexado a HttpContext pelo AuthenticationTestHandler. A marca tem o formato de cadeia de caracteres, "username:<actual username>".

  1. No Gerenciador de Soluções, clique com o botão direito do mouse no projeto AppBackend e selecione Gerenciar Pacotes NuGet.

  2. No painel esquerdo, selecione Online e, na caixa Pesquisa, digite Microsoft.Azure.NotificationHubs.

  3. Na lista de resultados, selecione Hubs de Notificação do Microsoft Azure e selecione Instalar. Conclua a instalação e, por fim, feche a janela Gerenciador de Pacotes NuGet.

    Essa ação adiciona uma referência ao SDK dos Hubs de Notificação do Azure usando o pacote NuGet Microsoft.Azure.Notification Hubs.

  4. Crie um novo arquivo de classe que representa a conexão com o hub de notificação usado para enviar notificações. No Gerenciador de Soluções, clique com o botão direito do mouse na pasta Modelos, selecione Adicionar e Classe. Nomeie a nova classe como Notifications.cs e selecione Adicionar para gerar a classe.

    The Add New Item window

  5. Em Notifications.cs, adicione a seguinte instrução using à parte superior do arquivo:

    using Microsoft.Azure.NotificationHubs;
    
  6. Substitua a definição da classe Notifications pelo seguinte e substitua os dois espaços reservados pela cadeia de conexão (com acesso completo) para o hub de notificação e o nome do hub (disponível no portal do Azure):

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

    Importante

    Insira o nome e a DefaultFullSharedAccessSignature do seu hub antes de prosseguir.

  7. Em seguida, crie um novo controlador chamado RegisterController. No Gerenciador de Soluções, clique com o botão direito do mouse na pasta Controladores, selecione Adicionar e Controlador.

  8. Selecione Controlador da API – Vazio e Adicionar.

  9. Na caixa Nome do controlador, digite RegisterController para nomear a nova classe e selecione Adicionar.

    The Add Controller window.

  10. Em RegisterController.cs, adicione as seguintes instruções using :

    using Microsoft.Azure.NotificationHubs;
    using Microsoft.Azure.NotificationHubs.Messaging;
    using AppBackend.Models;
    using System.Threading.Tasks;
    using System.Web;
    
  11. Adicione o código a seguir à definição de classe RegisterController . Nesse código, você adiciona uma marca de usuário para o usuário anexado a HttpContext. O usuário foi autenticado e anexado a HttpContext pelo filtro de mensagens que você adicionou, AuthenticationTestHandler. Você também pode adicionar verificações opcionais para conferir se o usuário tem direitos para registro das tags requeridas.

    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. Salve suas alterações.

Enviar notificações do back-end da WebAPI

Nesta seção, você adiciona um novo controlador que expõe uma maneira de os dispositivos clientes enviarem uma notificação. A notificação se baseia na marca de nome de usuário que usa a Biblioteca .NET dos Hubs de Notificação do Azure no back-end WebAPI ASP.NET.

  1. Crie outro novo controlador chamado NotificationsController da mesma maneira que você criou RegisterController na seção anterior.

  2. Em NotificationsController.cs, adicione as seguintes instruções using :

    using AppBackend.Models;
    using System.Threading.Tasks;
    using System.Web;
    
  3. Adicione o seguinte método à classe NotificationsController:

    Esse código envia um tipo de notificação com base no parâmetro pns do PNS (Platform Notification Service). O valor de to_tag é usado para definir a marca username na mensagem. Essa marca deve corresponder a uma marca de nome de usuário de um registro de hub de notificação ativo. A mensagem de notificação é recuperada do corpo da solicitação POST e formatada para o PNS de destino.

    Dependendo do PNS que seus dispositivos com suporte usam para receber notificações, as notificações têm suporte por vários formatos diferentes. Por exemplo, em dispositivos do Windows, você pode usar uma notificação do sistema com WNS que não tenha suporte direto de outro PNS. Nesse caso, o back-end precisa formatar a notificação em uma notificação com suporte para o PNS de dispositivos aos quais você planeja dar suporte. Em seguida, use a API de envio apropriada na classe 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. Para executar o aplicativo e garantir a precisão de seu trabalho até aqui, selecione a tecla F5. O aplicativo abre um navegador da Web e será exibido na home page do ASP.NET.

Publicar o novo back-end da API Web

Em seguida, implante o aplicativo em um site do Azure para poder ser acessado por todos os dispositivos.

  1. Clique com o botão direito do mouse no projeto AppBackend e selecione Publicar.

  2. Escolha Serviço de Aplicativo do Microsoft Azure como destino de publicação e selecione **Publicar. A janela Criar Serviço de Aplicativo é aberta. Aqui, você pode criar todos os recursos do Azure necessários para executar o aplicativo Web ASP.NET no Azure.

    The Microsoft Azure App Service tile

  3. Na janela Criar Serviço de Aplicativo, selecione sua conta do Azure. Selecione Alterar Tipo>Aplicativo Web. Mantenha o Nome do Aplicativo Web padrão e selecione a Assinatura, o Grupo de Recursos e o Plano do Serviço de Aplicativo.

  4. Selecione Criar.

  5. Anote a propriedade URL do Site na seção Resumo. Essa URL será seu ponto de extremidade de back-end mais adiante no tutorial.

  6. Selecione Publicar.

Depois de concluir o assistente, ele publica o aplicativo Web ASP.NET no Azure e abre o aplicativo no navegador padrão. Seu aplicativo pode ser exibido nos Serviços de Aplicativo do Azure.

A URL usa o nome do aplicativo Web especificado anteriormente, com o formato http://<app_name>.azurewebsites.net.

Criar o projeto Android

A próxima etapa é atualizar o aplicativo Android criado na Tutorial: Enviar notificações por push para dispositivos Android usando os Hubs de Notificação do Microsoft Azure e o Firebase Cloud Messaging.

  1. Abra seu arquivo res/layout/activity_main.xml, substitua as seguintes definições de conteúdo:

    Ele adiciona novos controles EditText para fazer logon como um usuário. Além disso, um campo é adicionado para uma marca username, que fará parte das notificações enviadas:

    <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. Abra o arquivo res/values/strings.xml e substitua a definição send_button pelas linhas a seguir, que redefinem a cadeia de caracteres para o send_button e adicione cadeias de caracteres aos outros controles:

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

    Os layouts geográficos main_activity.xml agora devem ter a aparência como a da seguinte imagem:

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

  3. Crie uma classe chamada RegisterClient no mesmo pacote que a classe MainActivity. Use o código a seguir para o novo arquivo de classe.

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

    Esse componente implementa as chamadas do REST necessárias para entrar em contato com o back-end do aplicativo para se registrar para as notificações por push. Ele também armazena localmente os registrationIds criados pelo Hub de Notificação, conforme detalhado em Registrando-se por meio do back-end do aplicativo. Ele usa um token de autorização armazenado localmente quando você clica no botão Entrar.

  4. Na sua classe MainActivity, adicione um campo para a classe RegisterClient e uma cadeia de caracteres para seu ponto de extremidade do back-end ASP.NET. Certifique-se de substituir <Enter Your Backend Endpoint> pelo ponto de extremidade de back-end real obtido anteriormente. Por exemplo, http://mybackend.azurewebsites.net.

    private RegisterClient registerClient;
    private static final String BACKEND_ENDPOINT = "<Enter Your Backend Endpoint>";
    FirebaseInstanceId fcm;
    String FCM_token = null;
    
  5. Na sua classe MainActivity, no método onCreate, remova ou comente a inicialização do campo hub e a chamada ao método registerWithNotificationHubs. Em seguida, adicione código para inicializar uma instância da classe RegisterClient . O método deve conter as linhas a seguir:

    @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. Adicione as instruções import a seguir ao arquivo 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. Substitua o código no método onStart pelo código a seguir:

    super.onStart();
    Button sendPush = (Button) findViewById(R.id.sendbutton);
    sendPush.setEnabled(false);
    
  8. Em seguida, adicione os seguintes métodos para manipular o evento de clique do botão Entrar e enviar notificações por push.

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

    O manipulador login para o botão Iniciar Sessão gera um token de autenticação Básica usando o nome de usuário e a senha de entrada (ele representa qualquer token usado pelo esquema de autenticação) e depois usa RegisterClient para chamar o back-end para registro.

    O método sendPush chama o back-end para disparar uma notificação segura para o usuário com base na marca user. O serviço de notificação de plataforma que sendPush tem como destino depende da cadeia de caracteres pns passada.

  9. Adicione o seguinte método DialogNotify à classe 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. Em sua classe MainActivity, atualize o método sendNotificationButtonOnClick para chamar o método sendPush com aos serviços de notificação de plataforma selecionados do usuário a seguir.

    /**
    * 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. No arquivo build.gradle, adicione a seguinte linha à seção android após a seção buildTypes.

    useLibrary 'org.apache.http.legacy'
    
  12. Se o aplicativo estiver direcionando o nível da API 28 (Android 9.0) ou superior, inclua a seguinte declaração dentro do elemento <application> de AndroidManifest.xml.

    <uses-library
        android:name="org.apache.http.legacy"
        android:required="false" />
    
  13. Compile o projeto.

Testar o aplicativo

  1. Execute o aplicativo em um dispositivo ou em um emulador usando o Studio Android.

  2. No aplicativo Android, insira um nome de usuário e uma senha. Eles devem ter o mesmo valor de cadeia de caracteres e não devem conter espaços ou caracteres especiais.

  3. No aplicativo Android, clique em Entrar. Aguarde uma mensagem de notificação do sistema que afirma Conectado e registrado. Isso habilita o botão Enviar Notificação.

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

  4. Clique nos botões de alternância para habilitar todas as plataformas onde você executou o aplicativo e registrou um usuário.

  5. Insira o nome do usuário que recebe a mensagem de notificação. Esse usuário deverá estar registrados para notificações nos dispositivos de destino.

  6. Insira uma mensagem para o usuário a ser recebida como uma mensagem de notificação por push.

  7. Clique em Enviar Notificação. Cada dispositivo com um registro com a marca username correspondente recebe a notificação de push.

Próximas etapas

Neste tutorial, você aprendeu como enviar notificações por push para usuários específicos que têm tags associadas seus registros. Para saber como enviar notificações por push, vá para o tutorial a seguir: