Guía paso a paso: Integración con las notificaciones de Graph (iOS)

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 iOS, tu aplicación de iOS 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.

Los pasos siguientes hacen referencia a código de la aplicación de ejemplo para iOS de Project Rome, disponible en GitHub.

Consulta en la página de referencia de API los vínculos a los documentos de referencia pertinentes para escenarios de notificación.

Configuración de la plataforma de dispositivos conectados y las 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

La manera más sencilla de agregar la plataforma de dispositivos conectados a la aplicación iOS es hacerlo a través del administrador de dependencias CocoaPods. Ve al archivo Podfile del proyecto de iOS e inserta la siguiente entrada:

platform :ios, "10.0"
workspace 'iOSSample'

target 'iOSSample' do
  # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
  # use_frameworks!

	pod 'ProjectRomeSdk'

  # Pods for iOSSample

Nota

Para utilizar CocoaPod, debes usar el archivo xcworkspace en el proyecto.

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 iOS que puedes usar para generar y administrar los tokens de actualización de la aplicación.

Si no usas el código proporcionado, deberás encargarte de implementar la interfaz MCDConnectedDevicesAccountManager.

Si usas una cuenta MSA, incluye 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".

Nota

No se admiten cuentas de Azure Active Directory (AAD) con las API de Retransmisión de dispositivo.

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

Tanto si usa la implementación de MCDConnectedDevicesAccountManager 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 Apple para conseguir la compatibilidad con Apple Push Notification. No olvides anotar el id. del remitente y la clave de servidor que recibas, ya que 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.

self.notificationRegistration = [[MCDConnectedDevicesNotificationRegistration alloc] init];
    if ([[UIApplication sharedApplication] isRegisteredForRemoteNotifications])
    {
        self.notificationRegistration.type = MCDNotificationTypeAPN;
    }
    else
    {
        self.notificationRegistration.type = MCDNotificationTypePolling;
    }
    self.notificationRegistration.appId = [[NSBundle mainBundle] bundleIdentifier];
    self.notificationRegistration.appDisplayName = (NSString*)[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
    self.notificationRegistration.token = deviceToken;
    self.isRegisteredWithToken = YES;

Registro de la aplicación en el Centro de desarrollo de Microsoft Windows para experiencias multidispositivo

Advertencia

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.

Registra la aplicación para acceder a la característica de experiencias multidispositivo del Panel de desarrolladores de Microsoft. Se sigue un procedimiento diferente al registro de la aplicación con MSA y AAD anterior. El objetivo principal de este proceso consiste en asignar las identidades de la aplicación específicas de la plataforma a una identidad de aplicación multiplataforma que se reconozca en la plataforma de dispositivos conectados. Este paso también permitirá enviar notificaciones mediante los servicios de notificación push nativos correspondientes a las plataformas móviles que utilice la aplicación. En iOS, permite que las notificaciones se envíen a los puntos de conexión de la aplicación iOS mediante APNS (Apple Push Notification Service).

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. Panel del Centro de desarrollo: experiencias multidispositivo

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, en función de las plataformas que utilices. Experiencias multidispositivo: plataformas compatibles

  • Proporciona los id. de la aplicación: proporciona los id. de la aplicación para cada plataforma que utilices. En las aplicaciones iOS, es el nombre del paquete que asignaste a la aplicación al crear el proyecto. Ten en cuenta que 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. Experiencias multidispositivo: id. de la aplicación

  • Proporciona o selecciona los id. de la aplicación de los registros de la aplicación con MSA o AAD obtenidos en los pasos de registro de la aplicación con AAD/MSA anteriores. Experiencias multidispositivo: registros de la aplicación con MSA y AAD

  • Indica tus credenciales para las plataformas de notificación nativas relevantes para la aplicación (es decir, WNS para Windows, FCM para Android o APNS para iOS), para permitir la entrega de notificaciones desde el servidor de aplicaciones al publicar notificaciones destinadas al usuario. Experiencias multidispositivo: credenciales de notificaciones push

  • Por último, comprueba el dominio de la aplicación multidispositivo para asegurarte de que la aplicación tiene la propiedad del dominio y puede utilizarlo como una identidad multidispositivo para la aplicación. Experiencias multidispositivo: verificación del dominio

Uso de la plataforma

Creación de una instancia de la plataforma

Para empezar, simplemente crea una instancia de la plataforma.

MCDConnectedDevicesPlatform* platform = [MCDConnectedDevicesPlatform new];

Suscripción a MCDConnectedDevicesAccountManager

La plataforma requiere un usuario autenticado para acceder a la plataforma. Deberás suscribirte a eventos MCDConnectedDevicesAccountManager para garantizar que se usa una cuenta válida.

[MCDConnectedDevicesPlatform* platform.accountManager.accessTokenRequested
     subscribe:^(MCDConnectedDevicesAccountManager* _Nonnull manager __unused,
                 MCDConnectedDevicesAccessTokenRequestedEventArgs* _Nonnull request __unused) {

                    // Get access token

                 }
[MCDConnectedDevicesPlatform* platform.platform.accountManager.accessTokenInvalidated
     subscribe:^(MCDConnectedDevicesAccountManager* _Nonnull manager __unused,
                 MCDConnectedDevicesAccessTokenInvalidatedEventArgs* _Nonnull request) {

                      // Refresh and renew existing access token

                 }

Suscripción a MCDConnectedDevicesNotificationRegistrationManager

De forma similar, la plataforma utiliza notificaciones para entregar comandos entre dispositivos. Por lo tanto, debes suscribirte a los eventos MCDConnectedDevicesNotificationRegistrationManager para garantizar que los estados de registro en la nube son válidos para la cuenta utilizada. Comprueba el estado con MCDConnectedDevicesNotificationRegistrationState.

[MCDConnectedDevicesPlatform* platform.notificationRegistrationManager.notificationRegistrationStateChanged
     subscribe:^(MCDConnectedDevicesNotificationRegistrationManager* manager __unused,
                 MCDConnectedDevicesNotificationRegistrationStateChangedEventArgs* args __unused) {

                     // Check state using MCDConnectedDevicesNotificationRegistrationState enum

                 }

Inicio de la plataforma

Ahora que la plataforma se ha inicializado y ya dispones de los controladores de evento, puedes comenzar a detectar los dispositivos del sistema remoto.

[MCDConnectedDevicesPlatform* platform start];

Recuperación de cuentas de usuario conocidas por la aplicación

Es importante asegurarse de que la lista de cuentas de usuario conocidas por la aplicación se sincronizan correctamente con la clase MCDConnectedDevicesAccountManager.

Usa MCDConnectedDevicesAccountManager.addAccountAsync para agregar una nueva cuenta de usuario.

[MCDConnectedDevicesPlatform* platform.accountManager
     addAccountAsync:self.mcdAccount
     callback:^(MCDConnectedDevicesAddAccountResult* _Nonnull result, NSError* _Nullable error) {

     // Check state using **MCDConnectedDevicesAccountAddedStatus** enum

     }

Para quitar una cuenta no válida, puedes usar MCDConnectedDevicesAccountManager.removeAccountAsync.

 [MCDConnectedDevicesPlatform* platform.accountManager
     removeAccountAsync:existingAccount
     callback:^(MCDConnectedDevicesRemoveAccountResult* _Nonnull result __unused, NSError* _Nullable error) {

                    // Remove invalid user account

     }

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 MCDUserDataFeed. MCDUserNotification 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 MCDUserNotification publicada por tu servidor de aplicaciones, primero es necesario inicializar la fuente de datos de usuario mediante la creación de una clase MCDUserNotificationChannel. 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 MCDUserNotificationChannel.

// You must be logged in to use UserNotifications
NSArray<MCDUserAccount*>* accounts = [[AppDataSource sharedInstance].accountProvider getUserAccounts];
if (accounts.count > 0)
{
    // Get a UserNotification channel, getting the default channel
    NSLog(@"Creating UserNotificationChannel");
    NSArray<MCDUserAccount*>* accounts = [[AppDataSource sharedInstance].accountProvider getUserAccounts];
    MCDUserDataFeed* userDataFeed = [MCDUserDataFeed userDataFeedForAccount:accounts[0]
        platform:[AppDataSource sharedInstance].platform
        activitySourceHost:CROSS_PLATFORM_APP_ID];
    NSArray<MCDSyncScope*>* syncScopes = @[ [MCDUserNotificationChannel syncScope] ];
    [userDataFeed addSyncScopes:syncScopes];
    self.channel = [MCDUserNotificationChannel userNotificationChannelWithUserDataFeed:userDataFeed];
}
else
{
    NSLog(@"Must log in to receive notifications for the logged in user!");
    self.createNotificationStatusField.text = @"Need to be logged in!";
}

En este momento, deberías tener una referencia a la clase MCDUserNotificationChannel en channel.

Creación de una clase MCDUserNotificationReader para recibir MCDUserNotifications entrantes y acceder al historial de MCDUserNotification.

Como se mostró anteriormente, la notificación inicial de APNS 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 MCDUserNotifications 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 MCDUserNotification del usuario que ha iniciado sesión. En este caso, una clase MCDUserNotificationReader 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 MCDUserNotification que puede utilizarse como modelo de visualización del historial de notificaciones del usuario.

Recepción de MCDUserNotifications

Primero es necesario crear una instancia de MCDUserNotificationReader y obtener todas las MCDUserNotifications 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. A continuación, 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 MCDUserNotifications entrantes publicadas por tu servidor de aplicaciones; o bien actualizaciones, eliminaciones y expiraciones de MCDUserNotifcation 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 la notificación sin procesar de APNS para crear una notificación visual en el centro 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.

// Instantiate the reader from a MCDUserNotificationChannel
// Add a data change listener to subscribe to new changes when new notifications or notification updates are received
- (void)setupWithAccount:(MCDUserAccount*)account {
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
        @synchronized (self) {
            MCDUserDataFeed* dataFeed = [MCDUserDataFeed userDataFeedForAccount:account platform:_platform activitySourceHost:@"graphnotifications.sample.windows.com"];
            [dataFeed addSyncScopes:@[[MCDUserNotificationChannel syncScope]]];
            self.channel = [MCDUserNotificationChannel userNotificationChannelWithUserDataFeed:dataFeed];
            self.reader = [self.channel createReader];
            
            __weak typeof(self) weakSelf = self;
            _readerRegistrationToken = [self.reader addDataChangedListener:^(__unused MCDUserNotificationReader* source) {
                NSLog(@"ME123 Got a change!");
                if (weakSelf) {
                    [weakSelf forceRead];
                } else {
                    NSLog(@"ME123 WEAKSELF FOR CHANGES IS NULL!!!");
                }
            }];
            
            [self forceRead];
        }
    });
}

// this is your own business logic when the event listener is fired
// In this case, the app reads the existing batch of notifications in the store and handle any new incoming notifications or notification updates after that
- (void)forceRead {
    NSLog(@"ME123 Forced to read!");
    [self.reader readBatchAsyncWithMaxSize:NSUIntegerMax completion:^(NSArray<MCDUserNotification *> * _Nullable notifications, NSError * _Nullable error) {
        if (error) {
            NSLog(@"ME123 Failed to read batch with error %@", error);
        } else {
            [self _handleNotifications:notifications];
            NSLog(@"ME123 Have %ld listeners", self.listenerMap.count);
            for (void (^listener)(void) in self.listenerMap.allValues) {
                NSLog(@"ME123 Calling a listener about an update!");
                listener();
            }
        }
    }];
}

Actualización del estado de una clase MCDUserNotification existente

En la sección anterior se mencionó que a veces un cambio en MCDUserNotification recibido a través de la escucha puede ser una actualización de estado de una MCDUserNotification 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 MCDUserNotification desde otro dispositivo. Puedes elegir la hora para actualizar el estado de tus MCDUserNotifications, 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 notificación de usuario 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 MCDUserNotification proporciona dos tipos de actualizaciones de estado: puedes modificar MCDUserNotificationReadState o MCDUserNotificationUserActionState y definir tu propia lógica sobre lo que debe ocurrir cuando se actualizan las notificaciones. Por ejemplo, puedes marcar la acción 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 el estado de lectura 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.

- (void)dismissNotification:(MCDUserNotification*)notification {
    @synchronized (self) {
        notification.userActionState = MCDUserNotificationUserActionStateDismissed;
        [notification saveAsync:^(__unused MCDUserNotificationUpdateResult * _Nullable result, __unused NSError * _Nullable err) {
            NSLog(@"ME123 Dismiss notification with result %d error %@", result.succeeded, err);
        }];
    }
}