Guía paso a paso: Integración con las notificaciones de Graph (Android)
Las notificaciones de Graph permiten a la aplicación enviar y administrar notificaciones destinadas al usuario en múltiples dispositivos.
Con el SDK del lado cliente de Project Rome en Android, tu aplicación de Android puede registrarse para recibir notificaciones publicadas desde tu servidor de aplicaciones destinadas a un usuario conectado. El SDK permite al cliente de la aplicación recibir nuevas cargas útiles de notificaciones entrantes, administrar el estado de las notificaciones existentes y recuperar el historial de notificaciones. Para obtener más información acerca de las notificaciones y cómo permiten la entrega de notificaciones centradas en las personas, consulta Notificaciones de Microsoft Graph.
Todas las características del SDK de Project Rome, incluidas las notificaciones de Graph y otras, están construidas sobre una plataforma subyacente llamada plataforma de dispositivos conectados. Esta guía está diseñada para guiarte por los pasos necesarios para empezar a utilizar la plataforma de dispositivos conectados y para explicar cómo consumir API en el SDK para implementar características específicas de las notificaciones de Graph.
Consulta en la página de referencia de API los vínculos a los documentos de referencia pertinentes para escenarios de notificación.
Los pasos siguientes hacen referencia a código de la aplicación de ejemplo de Android para Project Rome.
En todas las características de dispositivos conectados necesitarás un IDE de desarrollo de aplicaciones Android y un dispositivo Android con una de las arquitecturas admitidas (armeabi-v7a, arm64 v8a, x86 o x86_64) o bien un emulador. El sistema debe ejecutar Android 4.4.2 o versiones posteriores.
Configuración preliminar para la plataforma de dispositivos conectados y las notificaciones
Antes de implementar la conectividad remota, debes seguir unos pasos para que la aplicación Android disponga de la funcionalidad para conectarse a dispositivos remotos, así como para enviar y recibir notificaciones.
Registro de la aplicación
La mayoría de las características del SDK de Project Rome (a excepción de las API de Uso compartido en proximidad) necesitan la autenticación de la cuenta de Microsoft (MSA) o Azure Active Directory (AAD). Si aún no tienes una cuenta MSA y deseas usarla, regístrate en account.microsoft.com.
Nota
No se admiten cuentas de Azure Active Directory (AAD) con las API de Retransmisión de dispositivo.
A partir del método de autenticación elegido, debes registrar la aplicación con Microsoft; para ello, sigue las instrucciones del Portal de registro de aplicaciones. Si no tienes una cuenta de desarrollador de Microsoft, antes debes crearla.
Al registrar una aplicación con MSA, deberías recibir una cadena de id. de cliente. Guárdala para más adelante. Este dato permitirá que la aplicación acceda a los recursos de la plataforma de dispositivos conectados de Microsoft. Si usas AAD, consulta en Bibliotecas de autenticación de Azure Active Directory las instrucciones sobre cómo obtener la cadena de id. de cliente.
Incorporación del SDK
Inserta las siguientes referencias de repositorio en el archivo build.gradle situado en la raíz del proyecto.
allprojects {
repositories {
jcenter()
}
}
A continuación, inserta la siguiente dependencia en el archivo build.gradle que se encuentra en la carpeta del proyecto.
dependencies {
...
implementation 'com.microsoft.connecteddevices:connecteddevices-sdk:+'
}
En el archivo AndroidManifest.xml del proyecto, agrega los siguientes permisos dentro del elemento <manifest>
(si no están ya incluidos). Esto permite que la aplicación se conecte a Internet y habilite la detección de Bluetooth en el dispositivo.
Ten en cuenta que los permisos relacionados con Bluetooth solo son necesarios para usar la detección de Bluetooth; no se necesitan para las demás características de la plataforma de dispositivos conectados. Además, ACCESS_COARSE_LOCATION
solo es necesario en los niveles de Android SDK 21 y posteriores. En los niveles de Android SDK 23 y posteriores, el desarrollador también debe pedir al usuario que conceda acceso a la ubicación en tiempo de ejecución.
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
A continuación, ve a las clases de actividad donde deseas incluir la funcionalidad de dispositivos conectados. Importa los siguientes paquetes.
import com.microsoft.connecteddevices;
import com.microsoft.connecteddevices.remotesystems;
import com.microsoft.connecteddevices.remotesystems.commanding;
Configuración de la autenticación y la administración de cuentas
La plataforma de dispositivos conectados requiere que se utilice un token OAuth válido en el proceso de registro. Puedes usar el método preferido para generar y administrar los tokens OAuth. Sin embargo, para ayudar a los desarrolladores a empezar a usar la plataforma, hemos incluido un proveedor de autenticación como parte de la aplicación de ejemplo de Android que se encarga de generar y administrar los tokens de actualización.
Si deseas implementar tú mismo la interfaz ConnectedDevicesAccountManager, tome nota de la siguiente información:
Si usas una cuenta MSA, debes incluir los siguientes ámbitos en la solicitud de inicio de sesión: "wl.offline_access"
, "ccs.ReadWrite"
, "dds.read"
, "dds.register"
, "wns.connect"
, "asimovrome.telemetry"
y "https://activity.windows.com/UserActivity.ReadWrite.CreatedByApp"
.
Si usas una cuenta de AAD, deberás solicitar los siguientes destinatarios: "https://cdpcs.access.microsoft.com"
, "https://cs.dds.microsoft.com"
, "https://wns.windows.com/"
y "https://activity.microsoft.com"
.
Nota
No se admiten cuentas de Azure Active Directory (AAD) con las API de Retransmisión de dispositivo.
Tanto si usa la implementación de ConnectedDevicesAccountManager proporcionada como si no, si usa AAD tendrá que especificar los siguientes permisos en el registro de la aplicación en Azure Portal (portal.azure.com > Azure Active Directory > Registros de aplicaciones):
- Microsoft Activity Feed Service (Servicio de fuentes de actividad de Microsoft)
- Entregar y modificar notificaciones del usuario para esta aplicación
- Leer y escribir la actividad de la aplicación en la fuente de actividades de los usuarios
- Servicio de notificaciones de Windows
- Conectar su dispositivo al Servicio de notificaciones de Windows
- Microsoft Device Directory Service (Servicio de directorios de dispositivo de Microsoft)
- Ver la lista de dispositivos
- Se agregará a su lista de dispositivos y aplicaciones
- Microsoft Command Service (Servicio de comandos de Microsoft)
- Comunicarse con los dispositivos de usuario
- Leer dispositivos de usuario
Registro de la aplicación para notificaciones push
Registra la aplicación con Google para la compatibilidad con Firebase Cloud Messaging. No olvides anotar el id. del remitente y la clave de servidor que recibas; los necesitarás más adelante.
Una vez efectuado el registro, debes asociar la funcionalidad de notificaciones push con la plataforma de dispositivos conectados de tu aplicación.
mNotificationRegistration = new ConnectedDevicesNotificationRegistration();
mNotificationRegistration.setType(ConnectedDevicesNotificationType.FCM);
mNotificationRegistration.setToken(token);
mNotificationRegistration.setAppId(Secrets.FCM_SENDER_ID);
mNotificationRegistration.setAppDisplayName("SampleApp");
Registro de la aplicación en el Centro de desarrollo de Microsoft Windows para experiencias multidispositivo
Importante
Este paso solo es necesario si deseas usar características de Project Rome para acceder a datos de dispositivos que no sean Windows o realizar solicitudes en ellos. Si solo vas a trabajar con dispositivos Windows, no es necesario que realices este paso.
Ve al Panel del Centro de desarrollo y allí, a Cross-Device Experiences (Experiencias multidispositivo) en el panel de navegación del lado izquierdo; selecciona la opción de configuración de una nueva aplicación multidispositivo, tal como se muestra a continuación.
El proceso de incorporación del Centro de desarrollo requiere los siguientes pasos:
Select supported platforms (Seleccionar plataformas compatibles): selecciona las plataformas donde la aplicación estará presente y habilitada para experiencias multidispositivo. En el caso de la integración con las notificaciones de Graph, puedes seleccionar Windows, Android o iOS.
Provide app IDs (Proporcionar id. de la aplicación): proporciona los id. de la aplicación para cada una de las plataformas donde la aplicación estará presente. En las aplicaciones Android, es el nombre del paquete que asignaste a la aplicación al crear el proyecto. Puede encontrar el nombre del paquete en la consola de Firebase, en Información general del proyecto -> General. Puedes agregar varios id. (hasta diez) por plataforma; esto se aplica en el caso de tener varias versiones de la misma aplicación, o incluso diferentes aplicaciones, que quieres que reciban las mismas notificaciones enviadas por el servidor de aplicaciones destinadas al mismo usuario.
Proporciona o selecciona los id. de la aplicación de los registros de la aplicación con MSA o AAD. Estas identificaciones de cliente correspondientes al registro de la aplicación con AAD o MSA se obtuvieron en los pasos de registro de la aplicación con MSA o AAD anteriores, indicados más arriba.
Las notificaciones de Graph y otras funcionalidades de la plataforma de dispositivos conectados aprovechan cada una de las plataformas de notificación nativas de las principales plataformas para enviar notificaciones hasta los puntos de conexión cliente de la aplicación, es decir, WNS (para Windows UWP), FCM (para Android) y APNS (para iOS). Proporciona tus credenciales para estas plataformas de notificación para permitir que Notificaciones de Graph entregue las notificaciones para el servidor de aplicaciones al publicar notificaciones destinadas al usuario. En Android, debe habilitarse el servicio Cloud Messaging para usar Notificaciones de Microsoft Graph. Además, ten en cuenta que el id. del remitente requerido se corresponde con el valor de Sender ID (id. del remitente) de Firebase Cloud Messaging y que la clave de API se corresponde con el valor de Legacy Server Key (Clave del servidor heredado). Ambos pueden encontrarse en la consola de Firebase -> Proyecto -> Configuración, en la pestaña Mensajería en la nube, tal como se muestra en la captura de pantalla.
El último paso consiste en comprobar el dominio de la aplicación multidispositivo; sirve como proceso de verificación para confirmar que la aplicación tiene la propiedad de este dominio, que actúa como identidad de aplicación multidispositivo para la aplicación que registraste.
Inicialización de un canal de notificaciones de Graph
El SDK de Project Rome permite que la aplicación se suscriba a diferentes canales para recibir y administrar diferentes tipos de datos de usuario, incluidas las notificaciones de Graph y las actividades de usuario entre otras. Todos ellos se almacenan y sincronizan en UserDataFeed. UserNotification es la clase y el tipo de datos correspondiente a una notificación destinada al usuario enviada mediante las notificaciones de Graph. Para la integración con las notificaciones de Graph y comenzar a recibir la UserNotification publicada por tu servidor de aplicaciones, primero es necesario inicializar la fuente de datos de usuario mediante la creación de una clase UserNotificationChannel. Debes tratar este paso como el paso anterior de inicialización de la plataforma: debe comprobarse y, posiblemente, rehacerse siempre que la aplicación pasa al primer plano (pero no antes de la inicialización de la plataforma).
Los siguientes métodos inicializan una clase UserNotificationChannel.
private UserNotificationChannel mNotificationChannel;
private UserDataFeed mUserDataFeed;
// ...
/**
* Initializes the UserNotificationFeed.
*/
public void initializeUserNotificationFeed() {
// define what scope of data this app needs
SyncScope[] scopes = { UserNotificationChannel.getSyncScope() };
// Get a reference to the UserDataFeed. This method is defined below
mUserDataFeed = getUserDataFeed(scopes, new EventListener<UserDataFeed, Void>() {
@Override
public void onEvent(UserDataFeed userDataFeed, Void aVoid) {
if (userDataFeed.getSyncStatus() == UserDataSyncStatus.SYNCHRONIZED) {
// log synchronized.
} else {
// log synchronization not completed.
}
}
});
// this method is defined below
mNotificationChannel = getUserNotificationChannel();
}
// instantiate the UserDataFeed
private UserDataFeed getUserDataFeed(SyncScope[] scopes, EventListener<UserDataFeed, Void> listener) {
UserAccount[] accounts = AccountProviderBroker.getSignInHelper().getUserAccounts();
if (accounts.length <= 0) {
// notify the user that sign-in is required
return null;
}
// use the initialized Platform instance, along with the cross-device app ID.
UserDataFeed feed = UserDataFeed.getForAccount(accounts[0], PlatformBroker.getPlatform(), Secrets.APP_HOST_NAME);
feed.addSyncStatusChangedListener(listener);
feed.addSyncScopes(scopes);
// sync data with the server
feed.startSync();
return feed;
}
// use the UserDataFeed reference to create a UserActivityChannel
@Nullable
private UserNotificationChannel getUserNotificationChannel() {
UserNotificationChannel channel = null;
try {
// create a UserNotificationChannel for the signed in account
channel = new UserNotificationChannel(mUserDataFeed);
} catch (Exception e) {
e.printStackTrace();
// handle exception
}
return channel;
}
En este momento, deberías tener una referencia a la clase UserNotificationChannel en mNotificationChannel
.
Creación de una clase UserNotificationReader para recibir UserNotifications entrantes y acceder al historial de UserNotification.
Como se mostró anteriormente, la notificación inicial de Google Cloud Messaging que llega al cliente de la aplicación solo contiene un toque de atención, y es necesario pasar esa carga útil del toque de atención a la plataforma de dispositivos conectados para que el SDK realice una sincronización completa con el servidor de dispositivos conectados, que contiene todas las UserNotifications publicadas por el servidor de aplicaciones. Esto reducirá la carga útil de la notificación completa publicada por tu servidor de aplicaciones correspondiente a ese toque de atención (y en caso de que se publicaran notificaciones previas pero no se recibieran en este cliente de la aplicación debido a la conectividad del dispositivo u otros problemas, también se reducirán). Con estas sincronizaciones en tiempo real realizadas constantemente por el SDK, el cliente de la aplicación puede tener acceso a una caché local de la fuente de datos de UserNotification del usuario que ha iniciado sesión. En este caso, una clase UserNotificationReader permite al cliente de la aplicación acceder a esta fuente de datos para recibir la última carga útil de la notificación a través de la escucha de eventos; o bien para acceder a la colección completa de UserNotification que puede utilizarse como modelo de visualización del historial de notificaciones del usuario.
Recepción de UserNotifications
Primero es necesario crear una instancia de UserNotificationReader y obtener todas las UserNotifications existentes ya en la escucha si estás interesado en consumir esa información para la experiencia que estás intentando habilitar. Es seguro asumir siempre que el servidor de aplicaciones ya ha publicado notificaciones a este usuario conectado, ya que el punto de conexión de este dispositivo puede no ser el único o el primer punto de conexión en el que el usuario ha instalado su aplicación.
private static UserNotificationReader mReader;
private static final ArrayList<UserNotification> mHistoricalNotifications = new ArrayList<>();
// Instantiate UserNotificationReader
UserNotificationReaderOptions options = new UserNotificationReaderOptions();
mReader = mNotificationChannel.createReaderWithOptions(options);
// Read any previously published UserNotifications that have not expired yet
mReader.readBatchAsync(Long.MAX_VALUE).thenAccept(new AsyncOperation.ResultConsumer<UserNotification[]>() {
@Override
public void accept(UserNotification[] userNotifications) throws Throwable {
synchronized (mHistoricalNotifications) {
for (UserNotification notification : userNotifications) {
if (notification.getReadState() == UserNotificationReadState.UNREAD) {
mHistoricalNotifications.add(notification);
}
}
}
if (RunnableManager.getHistoryUpdated() != null) {
activity.runOnUiThread(RunnableManager.getHistoryUpdated());
}
}
});
Ahora, agrega una escucha de eventos que se activará cuando la plataforma de dispositivos conectados complete una sincronización y tenga nuevos cambios que notificarte. En el caso de las notificaciones de Graph, los nuevos cambios pueden ser nuevas UserNotifications entrantes publicadas por tu servidor de aplicaciones; o bien actualizaciones, eliminaciones y expiraciones de UserNotifcation que ocurrieron desde el servidor o desde otros puntos de conexión registrados en los que inició sesión el mismo usuario.
Sugerencia
En esta escucha de eventos es donde se controla la lógica principal del negocio y "consume" el contenido de la carga útil de la notificación en función en tus escenarios. Si utilizas el mensaje de datos de Google Cloud Messaging para crear una notificación visual en la bandeja de notificaciones a nivel de sistema operativo o si utilizas el contenido de la notificación para actualizar una interfaz de usuario en la aplicación, este es el lugar para hacerlo.
mReader.addDataChangedListener(new EventListener<UserNotificationReader, Void>() {
@Override
public void onEvent(UserNotificationReader userNotificationReader, Void aVoid) {
userNotificationReader.readBatchAsync(Long.MAX_VALUE).thenAccept(new AsyncOperation.ResultConsumer<UserNotification[]>() {
@Override
public void accept(UserNotification[] userNotifications) throws Throwable {
boolean updatedNew = false;
boolean updatedHistorical = false;
synchronized (sHistoricalNotifications) {
for (final UserNotification notification : userNotifications) {
if (notification.getStatus() == UserNotificationStatus.ACTIVE && notification.getReadState() == UserNotificationReadState.UNREAD) {
switch (notification.getUserActionState()) {
case NO_INTERACTION:
// Brand new notification
// Insert business logic to construct a new visual notification in Android notification tray for the user to see
// ...
case DISMISSED:
// Existing notification that is marked as dismissed
// An app client receive this type of changes because another app client logged in by the same user has marked the notification as dismissed and the change is fanned-out to everywhere
// This state sync across app clients on different devices enable universal dismiss of notifications and other scenarios across multiple devices owned by the same user
// Insert business logic to dismiss the corresponding visual notification inside Android system notification tray, to make sure users don’t have to deal with redundant information across devices, and potentially insert this notification in your app’s notification history view
// ...
default:
// Unexpected
}
} else {
// ...
}
}
}
}
});
}
});
Actualización del estado de una clase UserNotification existente
En la sección anterior se mencionó que a veces un cambio en UserNotification recibido a través de la escucha puede ser una actualización de estado de una UserNotification existente, independientemente de si está marcada como descartada o como leída. En este caso, el cliente de la aplicación puede elegir qué hacer; por ejemplo, habilitar el descarte universal al eliminar la notificación visual correspondiente en este dispositivo concreto. Dando un paso atrás, el cliente de la aplicación es a menudo el que inició esta actualización de cambio de UserNotification desde otro dispositivo. Puedes elegir la hora para actualizar el estado de tus UserNotifications, pero normalmente se actualizan cuando el usuario controla la notificación visual correspondiente en ese dispositivo o en alguna experiencia en la aplicación que habilites. A continuación, se muestra un ejemplo del aspecto del flujo: el servidor de aplicaciones publica una notificación destinada al usuario A, y este usuario recibe esta notificación tanto en su PC como en el teléfono donde están instalados los clientes de la aplicación. El usuario hace clic en la notificación en su PC y se dirige a la aplicación para controlar la tarea correspondiente. El cliente de la aplicación en su PC llamará al SDK de la plataforma de dispositivos conectados para actualizar el estado de la UserNotification correspondiente con el fin de sincronizar esta actualización en todos los dispositivos de este usuario. Los demás clientes de la aplicación, al recibir esta actualización de estado en tiempo real, eliminarán la alerta visual, mensaje o notificación del sistema correspondiente del centro de notificación, la bandeja de notificación o el centro de actividades del dispositivo. Así es como las notificaciones se descartan universalmente en los dispositivos de un usuario.
Sugerencia
Actualmente, la clase UserNotification proporciona dos tipos de actualizaciones de estado: puedes modificar UserNotificationReadState o UserNotificationUserActionState y definir tu propia lógica sobre lo que debe ocurrir cuando se actualizan las notificaciones. Por ejemplo, puedes marcar UserActionState para que esté activada o descartada y basarte en ese valor para implementar el descarte universal. Si lo prefieres, o al mismo tiempo, puedes marcar ReadState como leído o no leído y, en función de ello, determinar qué notificaciones deben aparecer en la vista del historial de notificaciones en la aplicación. El fragmento de código siguiente muestra cómo marcar el elemento UserNotificationUserActionState de una notificación como desestimado.
public void dismissNotification(int position) {
final UserNotification notification = mNewNotifications.get(position);
notification.setUserActionState(UserNotificationUserActionState.DISMISSED);
notification.saveAsync();
}