Partilhar via


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

Nota

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

Este tutorial mostra-lhe como utilizar os Hubs de Notificação do Azure para enviar notificações push para um utilizador específico da aplicação num dispositivo específico. Um back-end WebAPI de ASP.NET é utilizado para autenticar clientes e gerar notificações, conforme mostrado no artigo de documentação de orientação Registar-se a partir do back-end da aplicação. Este tutorial baseia-se no hub de notificação que você criou no Tutorial: Notificações por push para dispositivos Android usando os Hubs de Notificação do Azure e o Firebase Cloud Messaging.

Neste tutorial, siga os seguintes passos:

  • Criar o projeto de back-end WebAPI que autentica os utilizadores.
  • Atualizar a aplicação Android.
  • Testar a aplicação

Pré-requisitos

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

Criar o projeto WebAPI

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

  • Autenticar os clientes: é adicionado um processador de mensagens para autenticar os pedidos dos clientes e associar os utilizadores aos pedidos.
  • Registar-se para receber notificações ao utilizar o back-end de WebAPI: é adicionado um controlador para processar registos novos, para que um dispositivo de cliente receba notificações. O nome de utilizador autenticado é adicionado automaticamente ao registo como uma etiqueta.
  • Enviar notificações para os clientes: é adicionado um controlador para permitir que os utilizadores acionem um envio seguro para dispositivos e clientes associados à etiqueta.

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

Para confirmar, inicie o Visual Studio. No menu Ferramentas, selecione Extensões e Atualizações. Procure o Gestor de Pacotes de NuGet na sua versão do Visual Studio e verifique se tem a versão mais recente. Se a sua versão não for a versão mais recente, desinstale-a e, em seguida, reinstale o Gestor de Pacotes de NuGet.

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

Nota

Verifique que tem instalado o Azure SDK para Visual Studio para implementação de Website.

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

  2. Selecione Explorador de Servidores e inicie sessão na sua conta do Azure. Para criar os recursos do site na sua conta, tem de ter sessão iniciada.

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

  4. Digite API da Web na caixa de pesquisa.

  5. Selecione o modelo de projeto ASP.NET Core Web API e selecione Next.

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

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

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

Remova os arquivos de modelo WeatherForecast

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

Na janela Configurar Aplicação Web do Microsoft Azure, selecione uma subscrição e, em seguida, na lista Plano do Serviço de Aplicações, efetue uma das seguintes 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 aplicações e, em seguida, crie um.

Não precisa de uma base de dados para este tutorial. Depois de selecionar o seu plano do serviço de aplicações, selecione OK para criar o projeto.

The Configure Microsoft Azure Web App window

Se você não vir esta página para configurar o plano de serviço de aplicativo, continue com o tutorial. Você pode configurá-lo enquanto publica o aplicativo mais tarde.

Autenticar clientes no back-end de WebAPI

Nesta secção, crie uma nova classe de processadores de mensagens com o nome AuthenticationTestHandler para o back-end novo. Esta classe é derivada de DelegatingHandler e adicionada como um processador de mensagens, para processar todos os pedidos enviados para o back-end.

  1. No Explorador de Soluções, clique com o botão direito do rato no projeto AppBackend, selecione Adicionar e, em seguida, selecione Classe.

  2. Dê o nome AuthenticationTestHandler.cs à classe e selecione Adicionar para gerar a classe. Esta classe autentica utilizadores com a Autenticação Básica, para simplicidade. A sua aplicação pode utilizar qualquer esquema de autenticação.

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

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

    O processador autoriza o pedido quando se verificarem as três condições seguintes:

    • O pedido inclui o cabeçalho Autorização.
    • O pedido utiliza a autenticação básica.
    • A cadeia de nome de utilizador e a cadeia de palavra-passe são a mesma cadeia.

    Caso contrário, o pedido é rejeitado. Esta autenticação não é uma verdadeira abordagem de autenticação e autorização. É apenas um exemplo simples para este tutorial.

    Se AuthenticationTestHandler autenticar e autorizar a mensagem do pedido, o utilizador de autenticação básica é anexado ao pedido atual em HttpContext. As informações do utilizador em HttpContext serão utilizadas por outro controlador (RegisterController) mais tarde, para adicionar uma etiqueta ao pedido de registo 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;
        }
    }
    

    Nota

    Nota de segurança: a classe AuthenticationTestHandler não fornece uma autenticação verdadeira. É utilizada apenas para imitar a autenticação básica e não é segura. Tem de implementar um mecanismo de autenticação segura nos seus serviços e aplicações de produção.

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

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

Utilizar o back-end de WebAPI para registar notificações

Nesta secção, adicione um controlador novo ao back-end de WebAPI para processar pedidos de registo de um utilizador e de um dispositivo para as notificações, através da biblioteca de cliente dos hubs de notificação. O controlador adiciona uma etiqueta de utilizador para o utilizador que AuthenticationTestHandler autenticou e anexou a HttpContext. A etiqueta tem o formato de cadeia "username:<actual username>".

  1. No Explorador de Soluções, clique com o botão direito no projeto AppBackend e, em seguida, selecione Gerir Pacotes de NuGet.

  2. No painel esquerdo, selecione Online e, na caixa Procurar, escreva Microsoft.Azure.NotificationHubs.

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

    Esta ação adiciona uma referência ao SDK dos Hubs de Notificação do Azure mediante a utilização do Pacote NuGet Microsoft.Azure.Notification Hubs.

  4. Crie um ficheiro de classe novo que represente a ligação ao hub de notificação utilizado para enviar notificações. No Explorador de Soluções, clique com o botão direito do rato na pasta Modelos, selecione Adicionar e, em seguida, selecione Classe. Dê o nome Notifications.cs à classe nova e selecione Adicionar para gerá-la.

    The Add New Item window

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

    using Microsoft.Azure.NotificationHubs;
    
  6. Substitua a definição de classe Notifications pelo código seguinte e substitua os dois marcadores de posição pela cadeia de ligação (com acesso total) do seu 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 controlador novo com o nome RegisterController. No Explorador de Soluções, clique com o botão direito do rato na pasta Controladores, selecione Adicionar e, em seguida, selecione Controlador.

  8. Selecione API Controller - Empty e, em seguida, selecione Add.

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

    The Add Controller window.

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

    using Microsoft.Azure.NotificationHubs;
    using Microsoft.Azure.NotificationHubs.Messaging;
    using AppBackend.Models;
    using System.Threading.Tasks;
    using System.Web;
    
  11. Adicione o código seguinte dentro da definição de classe RegisterController. Neste código, adicione uma etiqueta de utilizador para o utilizador que está anexado a HttpContext. O utilizador foi autenticado e anexado a HttpContext através do filtro de mensagem que adicionou, AuthenticationTestHandler. Também pode adicionar verificações opcionais para confirmar que o utilizador tem direitos para se registar nas etiquetas pedidas.

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

Enviar notificações a partir do back-end de WebAPI

Nesta secção, irá adicionar um novo controlador que indica uma forma de os dispositivos de cliente enviarem uma notificação. A notificação baseia-se na etiqueta de nome de utilizador que utiliza a Biblioteca .NET dos Hubs de Notificação do Azure no back-end de ASP.NET WebAPI.

  1. Crie outro controlador novo com o nome NotificationsController da mesma forma que criou o RegisterController na secção anterior.

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

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

    Este código envia um tipo de notificação com base no parâmetro pns do Serviço de Notificação de Plataforma (PNS). O valor de to_tag é utilizado para definir a etiqueta nome de utilizador na mensagem. Esta etiqueta tem de corresponder a uma etiqueta de nome de utilizador de um registo de hub de notificação ativo. A mensagem da notificação é retirada do corpo do pedido POST e formatada para o PNS de destino.

    Consoante o PNS que os seus dispositivos suportados utilizam para receber notificações, estas são suportadas com vários formatos. Por exemplo, em dispositivos Windows, poderá utilizar uma notificação de alerta com WNS que não seja diretamente suportada por outro PNS. Nesse caso, o seu back-end tem de formatar a notificação de modo a que seja suportada pelo PNS dos dispositivos que pretende incluir. Em seguida, utilize a API de envio adequada 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 a aplicação e garantir a precisão do seu trabalho até ao momento, prima a tecla F5. A aplicação abre um browser e é apresentada na home page do ASP.NET.

Publicar o back-end de WebAPI novo

Em seguida, implemente a aplicação num site do Azure para que seja acessível a partir de todos os dispositivos.

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

  2. Selecione Serviço de Aplicações do Microsoft Azure como o destino da publicação e selecione \*\*Publicar. A janela Criar Serviço de Aplicações é aberta. Aí, pode criar todos os recursos do Azure necessários para executar a aplicação Web ASP.NET no Azure.

    The Microsoft Azure App Service tile

  3. Na janela Criar Serviço de Aplicações, selecione a sua conta do Azure. Selecione Alterar Tipo>Aplicação Web. Mantenha o Nome da Aplicação Web predefinido e, em seguida, selecione a Subscrição, o Grupo de Recursos e o Plano do Serviço de Aplicações.

  4. Selecione Criar.

  5. Anote a propriedade URL do Site, na secção Resumo. Este URL será o seu ponto final de back-end mais adiante no tutorial.

  6. Selecione Publicar.

Depois de concluir o assistente, este publica a aplicação Web ASP.NET no Azure e, em seguida, abre a aplicação no browser predefinido. A aplicação é visualizável nos Serviços Aplicacionais do Azure.

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

Criar o Projeto para Android

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

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

    Adiciona novos controlos EditText para iniciar sessão como um utilizador. Também é adicionado um campo para uma etiqueta username que irá fazer parte de notificações que enviar:

    <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 e substitua a definição pelas seguintes linhas que redefinem a send_button cadeia de caracteres para o res/values/strings.xml send_button e adicionam cadeias de caracteres para os 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>
    

    Seu main_activity.xml layout gráfico agora deve se parecer com a seguinte imagem:

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

  3. Crie uma nova classe nomeada RegisterClient no mesmo pacote que sua MainActivity classe. Utilize o código abaixo para o ficheiro da nova 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;
        }
    }
    

    Este componente implementa as chamadas REST necessárias para entrar em contato com o back-end do aplicativo para se registrar para notificações por push. Também armazena localmente os registrationIds criados pelo Hub de Notificação conforme detalhado em Registar-se a partir do back-end da aplicação. Ele usa um token de autorização armazenado no armazenamento local quando você clica no botão Entrar .

  4. Na sua MainActivity classe, e adicione um campo para a classe e uma cadeia de caracteres para o RegisterClient ponto de extremidade do back-end ASP.NET. Certifique-se de que substitui o <Enter Your Backend Endpoint> pelo ponto final 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 acrescente delimitadores de comentário à inicialização do campo hub e à chamada para o método registerWithNotificationHubs. Em seguida, adicione código para inicializar uma instância da classe RegisterClient. O método deverá conter as seguintes linhas:

    @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 seguintes instruções import ao ficheiro 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 seguinte código:

    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 login manipulador para o botão Entrar 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 seu esquema de autenticação) e, em seguida, ele usa RegisterClient para chamar o back-end para registro.

    O método sendPush chama o back-end para acionar uma notificação segura para o utilizador com base na etiqueta do mesmo. O serviço de notificação de plataforma visado por sendPush depende da cadeia pns transmitida.

  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. Na sua classe MainActivity, atualize o método sendNotificationButtonOnClick para chamar o método sendPush com os serviços de notificação de plataforma selecionados do utilizador do seguinte modo.

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

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

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

Testar a aplicação

  1. Execute a aplicação num dispositivo ou num emulador com o Android Studio.

  2. Na aplicação Android, introduza um nome de utilizador e uma palavra-passe. Ambos têm de ter o mesmo valor de cadeia e nenhum deles pode conter espaços ou carateres especiais.

  3. Na aplicação Android, clique em Iniciar sessão. Aguarde uma mensagem do sistema informando Conectado e registrado. Esta ativa o botão Send Notification.

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

  4. Clique nos botões de alternar para ativar todas as plataformas em que executou a aplicação e registou um utilizador.

  5. Introduza o nome do utilizador que recebe a mensagem de notificação. Esse utilizador tem de estar registado para receber notificações nos dispositivos de destino.

  6. Introduza uma mensagem para o utilizador receber como uma mensagem de notificação push.

  7. Clique em Send Notification. Cada dispositivo que tiver um registo com a etiqueta de nome de utilizador correspondente receberá a notificação push.

Próximos passos

Neste tutorial, aprendeu a enviar notificações push para utilizadores específicos que têm etiquetas associadas aos respetivos registos. Para saber como enviar notificações push com base na localização, avance para o seguinte tutorial: