Tutorial: Envío de notificaciones push a aplicaciones de Android mediante Azure Notification Hubs
Nota:
Para obtener información sobre los pasos de desuso y migración de Firebase Cloud Messaging, consulte Migración de Google Firebase Cloud Messaging.
Este tutorial muestra cómo puede utilizar los Centros de notificaciones de Azure para enviar notificaciones de inserción a un usuario de aplicaciones determinado en un dispositivo concreto. Se usa un back-end de ASP.NET WebAPI para autenticar clientes y generar notificaciones, tal como se muestra en el artículo de referencia Administración de registros desde un back-end. Este tutorial se basa en el centro de notificaciones que creó en el Tutorial: Envío de notificaciones push a dispositivos Android con Azure Notification Hubs y Firebase Cloud Messaging.
En este tutorial, realizará los siguientes pasos:
- Crear el proyecto de API Web de back-end que autentica a los usuarios.
- Actualizar la aplicación Android.
- Prueba de la aplicación
Requisitos previos
Complete el Tutorial: Envío de notificaciones push a dispositivos Android con Azure Notification y Firebase Cloud Messaging antes de realizar este tutorial.
Creación del proyecto de API web
En las secciones siguientes se describe la creación de un nuevo back-end de ASP.NET WebAPI. Este proceso tiene tres objetivos principales:
- Autenticación de clientes: se agrega un controlador de mensajes para autenticar las solicitudes de cliente y asociar el usuario a la solicitud.
- Registro para recibir notificaciones mediante el back-end de WebAPI: se agrega un controlador para administrar los registros nuevos de un dispositivo cliente para que reciba notificaciones. El nombre de usuario autenticado se agrega automáticamente al registro como etiqueta.
- Envío de notificaciones a los clientes: se agrega un controlador para que los usuarios puedan desencadenar una inserción segura en los dispositivos y clientes asociados con la etiqueta.
Realice las siguientes acciones para crear el nuevo back-end de API web de ASP.NET Core 6.0:
Para comprobarlo, inicie Visual Studio. En el menú Herramientas, seleccione Extensiones y actualizaciones. Busque el Administrador de paquetes NuGet correspondiente a su versión de Visual Studio y asegúrese de que tiene la versión más reciente. Si no es la más reciente, se debe desinstalar y volver a instalar el Administrador de paquetes NuGet.
Nota:
Asegúrese de que ha instalado el SDK de Azure para Visual Studio para la implementación de sitios web.
Inicie Visual Studio o Visual Studio Express.
Seleccione el Explorador de servidores e inicie sesión en su cuenta de Azure. Para crear los recursos del sitio web en su cuenta, tiene que iniciar sesión.
En el menú Archivo de Visual Studio, seleccione Nuevo>Proyecto.
Escriba API web en el cuadro de búsqueda.
Seleccione la plantilla de proyecto ASP.NET Core Web API y, a continuación, Siguiente.
En el cuadro de diálogo Configurar el nuevo proyecto, asigne al proyecto el nombre AppBackend y seleccione Siguiente.
En el cuadro de diálogo Información adicional:
- Confirme que el Marco es .NET 6.0 (Compatibilidad a largo plazo).
- Confirme que la casilla Use controllers(uncheck to use minimal APIs) [Usar controladores (desactivar para usar API mínimas)] está activada.
- Desactive Habilitar compatibilidad con OpenAPI.
- Seleccione Crear.
Eliminación de los archivos de plantilla WeatherForecast
- Quite los archivos de ejemplo WeatherForecast.cs y Controllers/WeatherForecastController.cs del nuevo proyecto AppBackend.
- Abra Properties\launchSettings.json.
- Cambie las propiedades launchUrl de weatherforcast a appbackend.
En la ventana Configurar aplicación web de Microsoft Azure, seleccione una suscripción y, en la listaPlan de App Service, realice una de las siguientes acciones:
- Seleccione un plan de Azure App Service que ya haya creado.
- Seleccione Crear un nuevo plan de App Service para crear uno.
No es necesario una base de datos para este tutorial. Una vez seleccionado el plan de App Service, seleccione Aceptar para crear el proyecto.
Si no ve esta página para configurar el plan de App Service, continúe con el tutorial. Se puede configurar al publicar la aplicación más adelante.
Autenticar clientes en el back-end de WebAPI
En esta sección se crea una clase de controlador de mensajes llamada AuthenticationTestHandler para el nuevo back-end. Esta clase deriva de DelegatingHandler y se agrega como controlador de mensajes para que procese todas las solicitudes que lleguen al back-end.
En el Explorador de soluciones, haga clic con el botón derecho en el proyecto AppBackend, y seleccione Agregar y Clase.
Asigne a la nueva clase el nombre AuthenticationTestHandler.cs y seleccione Agregar para generar la clase. Para simplificar, esta clase autentica a los usuarios con Autenticación básica. La aplicación puede utilizar cualquier esquema de autenticación.
En AuthenticationTestHandler.cs, agregue las siguientes instrucciones
using
:using System.Net.Http; using System.Threading; using System.Security.Principal; using System.Net; using System.Text; using System.Threading.Tasks;
En AuthenticationTestHandler.cs, reemplace la definición de clase
AuthenticationTestHandler
con el código siguiente:Este controlador autoriza la solicitud cuando se cumplen las tres condiciones siguientes:
- La solicitud incluya un encabezado Autorización.
- La solicitud utiliza la autenticación básica .
- La cadena de nombre de usuario y la cadena de contraseña son la misma cadena.
En caso contrario, la solicitud se rechaza. Esta autenticación no es un enfoque de autorización y autenticación real. Es solo un ejemplo sencillo para este tutorial.
Si
AuthenticationTestHandler
autentica y autoriza el mensaje de solicitud, el usuario de autenticación básica se adjuntará a la solicitud actual en HttpContext. Otro controlador (RegisterController) usará después la información de usuario de HttpContext para agregar una etiqueta a la solicitud de registro de notificación.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 seguridad: la clase
AuthenticationTestHandler
no proporciona una autenticación verdadera. Se utiliza únicamente para simular una autenticación básica y no es segura. Debe implementar un mecanismo de autenticación seguro en las aplicaciones y servicios de producción.Para registrar el controlador de mensajes, agregue el siguiente código al final del método
Register
en el archivo Program.cs:config.MessageHandlers.Add(new AuthenticationTestHandler());
Guarde los cambios.
Registrar notificaciones mediante el back-end de WebAPI
En esta sección, agregaremos un nuevo controlador al back-end de WebAPI para administrar las solicitudes de registro de un usuario y un dispositivo para que reciban notificaciones mediante la biblioteca cliente de los centros de notificaciones. El controlador agrega una etiqueta de usuario al usuario que el AuthenticationTestHandler
autenticó y adjuntó a HttpContext. La etiqueta tiene el formato de cadena, "username:<actual username>"
.
En el Explorador de soluciones, haga clic con el botón derecho en el proyecto AppBackend y seleccione Administrar paquetes NuGet.
En el panel izquierdo, seleccione En línea y en el cuadro Buscar, escriba Microsoft.Azure.NotificationHubs.
En la lista de resultados, seleccione Microsoft Azure Notification Hubs e Instalar. Complete la instalación y cierre la ventana del Administrador de paquetes NuGet.
Esta acción agrega una referencia al SDK de Azure Notification Hubs mediante el paquete NuGet Microsoft.Azure.NotificationHubs.
Cree un archivo de clase que represente la conexión con el centro de notificaciones de envío. En el Explorador de soluciones, haga clic con el botón derecho en la carpeta Modelos, seleccione Agregar y Clase. Asigne el nombre a la nueva clase Notifications.cs y seleccione Agregar para generar la clase.
En Notifications.cs, agregue la siguiente instrucción
using
en la parte superior del archivo:using Microsoft.Azure.NotificationHubs;
Reemplace la definición de clase
Notifications
con el código siguiente y los dos marcadores de posición con la cadena de conexión (de acceso total) del centro de notificaciones y el nombre del centro (disponible en el Portal de 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
Escriba el nombre y elemento DefaultFullSharedAccessSignature del centro antes de continuar.
A continuación, cree un controlador denominado RegisterController. En el Explorador de soluciones, haga clic con el botón derecho en la carpeta Controladores, y seleccione Agregar y Controlador.
Seleccione Controlador de API: en blanco y Agregar.
En el cuadro Nombre del controlador, escriba RegisterController para denominar la nueva clase y seleccione Agregar.
En RegisterController.cs, agregue las siguientes instrucciones
using
:using Microsoft.Azure.NotificationHubs; using Microsoft.Azure.NotificationHubs.Messaging; using AppBackend.Models; using System.Threading.Tasks; using System.Web;
Agregue el siguiente código a la definición de clase
RegisterController
. En este código, agregamos una etiqueta de usuario para el usuario asociado a HttpContext. El usuario se autenticó y se asoció a HttpContext mediante un filtro de mensaje que agregó,AuthenticationTestHandler
. También puede realizar comprobaciones opcionales para comprobar que el usuario puede registrarse para las etiquetas solicitadas.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()); } }
Guarde los cambios.
Enviar notificaciones desde el back-end de WebAPI
En esta sección se agrega un nuevo controlador que expone una manera de enviar notificaciones para los dispositivos cliente. La notificación se basa en la etiqueta de nombre de usuario que usa la biblioteca .NET de Microsoft Azure Notification Hubs en el back-end de ASP.NET WebAPI.
Cree otro controlador denominado NotificationsController del mismo modo que creó RegisterController en la sección anterior.
En NotificationsController.cs, agregue las siguientes instrucciones
using
:using AppBackend.Models; using System.Threading.Tasks; using System.Web;
Agregue el método siguiente a la clase NotificationsController:
Este código envía un tipo de notificación basado en el parámetro
pns
del servicio Sistema de notificación de plataforma (PNS). El valor deto_tag
se usa para definir la etiqueta username en el mensaje. Esta etiqueta debe coincidir con una etiqueta de nombre de usuario de un registro de un centro de notificaciones activo. El mensaje de notificación se extrae del cuerpo de la solicitud POST y se formatea para el PNS de destino.Dependiendo del PNS que usen los dispositivos compatibles para recibir notificaciones, se admiten distintos formatos. Por ejemplo, en dispositivos Windows, puede usar una notificación del sistema con WNS que no sea compatible directamente con otro PNS. En este caso, el back-end debe dar un formato a la notificación que sea compatible con el PNS de los dispositivos que prevea admitir. Posteriormente, use la API de envío adecuada en la clase 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); }
Para ejecutar la aplicación y garantizar que hasta ahora todo es correcto, seleccione la tecla F5. La aplicación abre un explorador web y se muestra en la página de inicio de ASP.NET.
Publicación del nuevo back-end de WebAPI
A continuación implementaremos la aplicación en un sitio web de Azure para que todos los dispositivos puedan acceder a ella.
Haga clic con el botón derecho en el proyecto AppBackend y seleccione Publicar.
Seleccione Microsoft Azure App Service como destino de publicación y, luego, \*\*Publicar. La ventana Crear servicio de aplicaciones se abre. Aquí puede crear todos los recursos de Azure necesarios para ejecutar la aplicación web ASP.NET en Azure.
En la ventana Crear servicio de aplicaciones, seleccione la cuenta de Azure. Seleccione Cambiar tipo>Aplicación web. Mantenga el Nombre de aplicación web predeterminado y seleccione los valores de Suscripción, Grupo de recursos y Plan de App Service.
Seleccione Crear.
Anote la propiedad Dirección URL del sitio de la sección Resumen. Esta dirección URL es el punto de conexión de back-end que se utilizará más adelante en el tutorial.
Seleccione Publicar.
Una vez completado el asistente, este publica la aplicación web ASP.NET en Azure y la abre en el explorador predeterminado. La aplicación se puede ver en Azure App Services.
La dirección URL usa el nombre de la aplicación web que especificó anteriormente, con el formato http://<app_name>.azurewebsites.net.
Creación del proyecto Android
El siguiente paso consiste en actualizar la aplicación Android creada en el Tutorial: Envío de notificaciones push a dispositivos Android con Azure Notification Hubs y Firebase Cloud Messaging.
Abra su archivo
res/layout/activity_main.xml
, reemplace las definiciones de contenido siguientes:Así se agregan nuevos controles de EditText para iniciar sesión como usuario. Además, se agrega un campo para una etiqueta de nombre de usuario que formará parte de las notificaciones que envíe:
<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>
Abra el archivo
res/values/strings.xml
y reemplace la definiciónsend_button
con las siguientes líneas, que redefinen la cadena parasend_button
y agregan cadenas para los demás 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>
El diseño gráfico de
main_activity.xml
debe ser similar al de la siguiente imagen:Cree una clase denominada
RegisterClient
en el mismo paquete que su claseMainActivity
. Use el código siguiente para el archivo de la nueva clase.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 las llamadas REST necesarias para ponerse en contacto con el back-end de la aplicación y registrar las notificaciones push. También almacena localmente los identificadores registrationIds creados por el Centro de notificaciones, como se detalla en la sección Administración de registros desde un back-end. Usa un token de autorización almacenado localmente al hacer clic en el botón Iniciar sesión.
En su clase
MainActivity
, agregue un campo para la claseRegisterClient
y una cadena para el punto de conexión del back-end de ASP.NET. Asegúrese de reemplazar<Enter Your Backend Endpoint>
por el punto de conexión del back-end obtenido anteriormente. Por ejemplo,http://mybackend.azurewebsites.net
.private RegisterClient registerClient; private static final String BACKEND_ENDPOINT = "<Enter Your Backend Endpoint>"; FirebaseInstanceId fcm; String FCM_token = null;
En la clase
MainActivity
, en el métodoonCreate
, quite o convierta en comentario la inicialización del campohub
y la llamada al métodoregisterWithNotificationHubs
. A continuación, agregue código para inicializar una instancia de la claseRegisterClient
. El método debe contener las siguientes líneas:@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); }
Agregue las siguientes instrucciones
import
al archivoMainActivity.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;
Reemplace el código del método onStart por el código siguiente:
super.onStart(); Button sendPush = (Button) findViewById(R.id.sendbutton); sendPush.setEnabled(false);
A continuación, agregue los siguientes métodos para controlar el evento de clic del botón Iniciar sesión y enviar notificaciones 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); }
El controlador
login
del botón Iniciar sesión genera un token de autenticación básica que usa el nombre de usuario y la contraseña de entrada (representa cualquier token que use el esquema de autenticación) y, después, usaRegisterClient
para llamar al back-end para el registro.El método
sendPush
llama al back-end para desencadenar una notificación segura al usuario de acuerdo con la etiqueta del usuario. El servicio de notificaciones de plataforma al que apuntasendPush
depende de la cadenapns
transferida.Agregue el siguiente método
DialogNotify
a la claseMainActivity
.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(); }
En la clase
MainActivity
, actualice el métodosendNotificationButtonOnClick
para llamar al métodosendPush
con los servicios de notificaciones de plataforma seleccionados del usuario tal como sigue:/** * 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); } }
En el archivo
build.gradle
agregue la siguiente línea a la secciónandroid
después de la secciónbuildTypes
.useLibrary 'org.apache.http.legacy'
Si su aplicación tiene como destino el nivel 28 de API (Android 9.0) o posterior, incluya la siguiente declaración
<application>
dentro del elementoAndroidManifest.xml
.<uses-library android:name="org.apache.http.legacy" android:required="false" />
Compile el proyecto.
Prueba de la aplicación
Ejecute la aplicación en un dispositivo o un emulador con Android Studio.
En la aplicación de Android, escriba un nombre de usuario y una contraseña. Ambos deben tener el mismo valor de cadena y no pueden contener espacios ni caracteres especiales.
En la aplicación de Android, haga clic en Iniciar sesión. Espere que aparezca un mensaje de aviso que indique que se ha iniciado la sesión y se ha registrado. Así se habilita el botón Enviar notificación.
Haga clic en los botones de alternancia para habilitar todas las plataformas en las que ejecutó la aplicación y registró un usuario.
Escriba el nombre del usuario que recibe el mensaje de notificación. Ese usuario debe estar registrado para recibir notificaciones en los dispositivos de destino.
Escriba un mensaje para que el usuario lo reciba como un mensaje de notificación push.
Haga clic en Enviar notificación. Todos los dispositivos que tienen un registro con la etiqueta de nombre de usuario coincidente recibe la notificación push.
Pasos siguientes
En este tutorial, ha aprendido a enviar notificaciones push a usuarios concretos que tienen etiquetas asociadas a sus registros. Para aprender a enviar notificaciones push en función de la ubicación, pase al tutorial siguiente: