Intégrez votre application Android au Kit de développement logiciel (SDK) côté client pour les notifications utilisateur (déconseillé)

Importante

L’API de notifications Microsoft Graph est déconseillée et a cessé de retourner des données en janvier 2022. Pour une autre expérience de notification, consultez Microsoft Azure Notification Hubs. Pour plus d’informations, consultez le billet de blog Retrait de l’ API de notifications de Microsoft Graph (bêta).

Après avoir inscrit votre application dans le centre d'administration Microsoft Entra et intégré vos expériences inter-appareils dans le Centre de développement partenaires, l’étape suivante consiste à intégrer votre application cliente au SDK côté client pour les applications Android.

Avec le Kit de développement logiciel (SDK) côté client, votre application peut accomplir les étapes d’inscription nécessaires pour commencer à recevoir des notifications publiées par votre serveur d’applications ciblant l’utilisateur actuellement connecté. Le Kit de développement logiciel (SDK) gère ensuite les notifications côté client, en recevant les nouvelles notifications entrantes, en vérifiant l’état des notifications, par exemple, pour le masquage universel, et en récupérant l’historique complet des notifications.

Flux de nouvelle notification entrante

Le flux de données pour la réception de nouvelles notifications entrantes est présenté dans le diagramme suivant.

Flux de nouvelle notification pour application Android

Le processus implique quelques composants :

  • Serveur d’applications : serveur principal de votre application
  • Client de l’application : serveur frontal de votre application (application UWP, application Android ou application iOS)
  • Notifications de Microsoft Graph : composant de service qui active la publication, le stockage et la synchronisation des notifications à l’utilisateur dans différentes instances de clients de l’application sur divers appareils et plateformes.
  • FCM : Firebase Cloud Messaging, le service de notifications Push fourni par Android dans le cadre des Google Play Services. Les notifications de Microsoft Graph utilisent ce service pour signaler aux clients d’applications Android des modifications des données de notification à l’utilisateur.

Le diagramme présente les étapes suivantes :

  1. Logique d’application. Cette étape capture ce qui déclenche la publication de la notification à l’utilisateur. Il s’agit d’une logique spécifique de l’application. Ce peut être un événement ou une mise à jour de données concernant quelque chose d’autre dans Microsoft Graph, tel qu’un nouvel événement ou une nouvelle tâche de calendrier, ou quelque chose que votre application souhaite notifier à l’utilisateur.
  2. Le serveur d’applications publie une notification à l’utilisateur ciblé via l’API de notifications de Microsoft Graph. Pour plus d’informations, voir l’intégration côté serveur.
  3. À la réception de la demande web contenant la nouvelle notification, l’API de notifications de Microsoft Graph conserve le contenu de la notification en sécurité dans le cloud pour cette application et cet utilisateur.
  4. Pour chaque instance de client de l’application qui s’abonne pour recevoir des notifications destinées à cet utilisateur, l’API de notifications de Microsoft Graph envoie un signal pour notifier le client de l’application via le service de notifications Push natif du système d’exploitation. En l’occurrence, l’application est une application Android qui utilise le message de données FCM pour envoyer le signal.
  5. Une fois l’application signalée par la notification Push entrante, elle demande au Kit de développement logiciel (SDK) d’extraire les modifications du magasin de notifications à l’utilisateur.
  6. Le Kit de développement logiciel (SDK) établit une connexion sécurisée et conforme avec le magasin de notifications à l’utilisateur dans Microsoft Graph.
  7. Le Kit de développement logiciel (SDK) récupère les modifications des données, en l’occurrence, le contenu de la nouvelle notification.
  8. Le kit de développement logiciel (SDK) déclenche les rappels d’événements pour notifier l’application une fois les modifications récupérées.
  9. Logique d’application. Cette étape capture ce que votre application choisit de faire dans le rappel d’événement. Généralement, cela entraîne des modifications des données de l’application locale et des mises à jour de l’interface utilisateur locale. Dans ce cas, l’application construit généralement une fenêtre contextuelle de notification toast pour informer l’utilisateur du contenu de la notification.

Flux de mise à jour de notification

L’un des principaux avantages liés à l’utilisation de l’API de notifications de Microsoft Graph est qu’elle conserve les notifications en sécurité dans le cloud et les convertit en un type de ressource avec état. Elle peut donc aider votre application à gérer et à synchroniser l’état correct des notifications sur différents appareils pour le même utilisateur connecté dans un contexte inter-appareils. Quand une notification est marquée comme masquée ou lue sur un appareil, les autres appareils peuvent être notifiés en temps réel. L’approche « traité une fois, masqué partout » peut devenir réellement prometteuse dans le cadre de l’expérience de notification pour vos utilisateurs.

Le diagramme suivant illustre le flux de données pour le changement de l’état d’une notification ou la suppression de celle-ci sur un appareil, ainsi que pour la réception/gestion du changement d’état ou de la suppression sur un autre appareil.

Mettre à jour le flux de notification pour une application Android

Notez que la deuxième partie du flux est similaire au flux de traitement des nouvelles notifications entrantes. Il s’agit d’une conception : le modèle de programmation du KIT de développement logiciel (SDK) est conçu pour que le client d’application puisse gérer tous les types de modifications des données de notification utilisateur (nouvelles notifications entrantes, changements d’état de notification, notification supprimée) de la même façon.

Le diagramme présente les étapes suivantes :

  1. Logique d’application. Quelque chose déclenche la modification ou la suppression de la notification. En général, tout événement peut déclencher une modification de notification.
  2. Application faisant appel au Kit de développement logiciel (SDK) client pour mettre à jour ou supprimer une notification. Actuellement, nous exposons deux propriétés concernant les changements d’état (userActionState et readState) mais votre application peut définir ces états et le moment où ils doivent être mis à jour. Par exemple, quand un utilisateur masque la fenêtre contextuelle de notification, vous pouvez mettre à jour l’état userActionState afin qu’il soit masqué. Quand un utilisateur clique sur la fenêtre contextuelle de notification et lance l’application pour utiliser le contenu correspondant, vous pouvez mettre à jour l’état userActionState en le définissant comme Activé, et l’état readState en le définissant comme Lu.
  3. Une fois l’API correspondante appelée pour mettre à jour ou supprimer une notification, le Kit de développement logiciel (SDK) fait appel au magasin de notifications à l’utilisateur dans le cloud pour propager ce changement aux autres instances du client de l’application avec le même utilisateur connecté.
  4. Lors de la réception de la demande de mise à jour/suppression d’un client, l’API de notifications de Microsoft Graph met à jour le magasin de notifications et identifie les autres instances du client de l’application abonnées à cette modification.
  5. Pour chaque abonnement client, l’API de notifications de Microsoft Graph envoie un signal pour notifier le client de l’application via le service de notifications Push natif du système d’exploitation. En l’occurrence, il s’agit d’une application Android qui utilise le message de données FCM pour envoyer le signal.
  6. Une fois l’application signalée par la notification Push entrante, elle demande au Kit de développement logiciel (SDK) d’extraire les modifications du magasin de notifications à l’utilisateur.
  7. Le Kit de développement logiciel (SDK) établit une connexion sécurisée et conforme avec le magasin de notifications à l’utilisateur dans Microsoft Graph.
  8. Le Kit de développement logiciel (SDK) récupère les modifications des données, en l’occurrence les mises à jour d’état de notification ou les suppressions de notification.
  9. Le kit de développement logiciel (SDK) déclenche les rappels d’événements pour notifier l’application une fois les modifications récupérées.
  10. Logique d’application. Cette étape capture ce que votre application choisit de faire dans le rappel d’événement. Généralement, cela entraîne des modifications des données de l’application locale et des mises à jour de l’interface utilisateur locale. Dans ce cas, étant donné qu’il existe des mises à jour de notification, l’application doit mettre à jour l’interface utilisateur localement afin qu’elle reflète le changement d’état. Par exemple, si une notification est marquée comme activée, vous pouvez supprimer le message de notification correspondant dans la barre de notification d’Android conformément à l’approche « traité une fois, masqué partout ».

Pour plus d’informations sur les notifications de Microsoft Graph, voir la vue d’ensemble des notifications de Microsoft Graph. Pour plus d’informations sur la procédure à suivre pour l’intégration de bout en bout avec l’API de notifications de Microsoft Graph, voir la vue d’ensemble de l’intégration de l’API de notifications de Microsoft Graph.

Environnement de développement et configuration requise

Pour utiliser les notifications de Microsoft Graph, vous devez disposer d’un environnement de développement intégré (IDE) d’applications Android et d’un appareil Android doté de l’une des architectures prises en charge (armeabi-v7a, arm64-v8a, x86 ou x86_64) ou d’un émulateur. Le système doit exécuter Android 4.4.2 ou une version ultérieure.

Ajout du Kit de développement logiciel (SDK) à votre projet

Insérez les références de référentiel suivantes dans le fichier build.gradle situé à la racine de votre projet.

allprojects {
    repositories {
    jcenter()
    maven { url 'https://maven.google.com' }
    maven { url 'https://projectrome.bintray.com/maven/' }
    }
}

Ensuite, insérez la dépendance suivante dans le fichier build.gradle situé dans le dossier de votre projet.

dependencies { 
    ...
    implementation 'com.microsoft.connecteddevices:connecteddevices-sdk:+'
}

Si vous souhaitez utiliser ProGuard dans votre application, ajoutez les règles ProGuard pour ces nouvelles API. Créez un fichier appelé proguard-rules.txt dans le dossier App de votre projet, puis collez le contenu de ProGuard_Rules_for_Android_Rome_SDK.txt. Dans le fichier AndroidManifest.xml de votre projet, ajoutez les autorisations suivantes dans l’élément manifest (si elles n’y figurent pas encore). Cela autorise votre application à se connecter à Internet et à activer la détection Bluetooth sur votre appareil. Notez que les autorisations liées à Bluetooth ne sont nécessaires que pour utiliser la détection Bluetooth. Elles ne sont pas nécessaires pour d’autres fonctionnalités de la plateforme des appareils connectés. De plus, ACCESS_COARSE_LOCATION n’est requis que sur les kits de développement logiciel (SDK) Android 21 et ultérieurs. Sur les kits de développement logiciel (SDK) Android 23 et ultérieurs, vous devez également inviter l’utilisateur a accorder l’accès à l’emplacement au moment de l’exécution du runtime.

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

Ensuite, accédez aux classes d’activité dans lesquelles vous souhaitez que la fonctionnalité Appareils connectés soit située. Importez les espaces de noms suivants.

import com.microsoft.connecteddevices;
import com.microsoft.connecteddevices.userdata;
import com.microsoft.connecteddevices.userdata.usernotifications;

Initialisation des plateformes d’appareils connectés

Le Kit de développement logiciel (SDK) côté client est construit sur une infrastructure appelée plateforme d’appareil connecté. Pour qu’une fonctionnalité soit utilisable, la plateforme doit être initialisée dans votre application. Les étapes d’initialisation doivent avoir lieu dans votre méthode OnCreate de la classe principale, car elles sont indispensables pour l’exécution des scénarios de notification.

Vous devez construire et initialiser la plateforme en instanciant la classe ConnectedDevicesPlatform. Avant cela, veillez à raccorder les gestionnaires d’événements car, une fois la plateforme démarrée, les événements pourraient commencer à se déclencher.

ConnectedDevicesPlatform platform = new ConnectedDevicesPlatform(context);

platform.getAccountManager().accessTokenRequested().subscribe((accountManager, args) -> onAccessTokenRequested(accountManager, args));
platform.getAccountManager().accessTokenInvalidated().subscribe((accountManager, args) -> onAccessTokenInvalidated(accountManager, args));
platform.getNotificationRegistrationManager().notificationRegistrationStateChanged().subscribe((notificationRegistrationManager, args) -> onNotificationRegistrationStateChanged(notificationRegistrationManager, args));

platform.start();

Gestion de jeton d’accès au compte

Tous les appels web effectués par le Kit de développement logiciel (SDK), par exemple, pour la récupération du contenu d’une nouvelle notification entrante ou la mise à jour d’états de notification, lisent ou écrivent des données de l’utilisateur. Ils nécessitent donc toujours un jeton d’accès valide. Le Kit de développement logiciel (SDK) requiert que vous gériez les événements suivants (appelés quand un jeton d’accès est demandé ou invalidé) pour vous assurer qu’une fois la plateforme initialisée, votre jeton d’accès pour l’utilisateur soit correctement géré.

accessTokenRequested

Pour une implémentation complète, voir l’exemple d’application Android.

private void onAccessTokenRequested(ConnectedDevicesAccountManager sender, ConnectedDevicesAccessTokenRequestedEventArgs args) {
    ConnectedDevicesAccessTokenRequest request = args.getRequest();
    List<String> scopes = request.getScopes();

    // We always need to complete the request, even if a matching account is not found
    if (account == null) {
        request.completeWithErrorMessage("The app could not find a matching ConnectedDevicesAccount to get a token");
        return;
    }

    // Complete the request with a token
    account.getAccessTokenAsync(scopes)
        .thenAcceptAsync((String token) -> {
            request.completeWithAccessToken(token);
        }).exceptionally(throwable -> {
            request.completeWithErrorMessage("The Account could not return a token with those scopes");
            return null;
    });
}

accessTokenInvalidated

Pour une implémentation complète, voir l’exemple d’application Android.

private void onAccessTokenInvalidated(ConnectedDevicesAccountManager sender, ConnectedDevicesAccessTokenInvalidatedEventArgs args, List<Account> accounts) {
    Log.i(TAG, "Token invalidated for account: " + args.getAccount().getId());
}

Gestion de l’expiration d’inscription de notification Push

L’API de notifications de Microsoft Graph utilise FCM, la plateforme de notifications Push native d’Android, pour signaler à l’application cliente les modifications des données des notifications à l’utilisateur. Cela se produit quand de nouvelles notifications entrantes sont publiées à partir de votre serveur d’applications ou quand l’état d’une notification est mis à jour sur un autre appareil du même utilisateur connecté dans un contexte inter-appareils.

Par conséquent, un jeton FCM valide permettant le passage des messages de notification de données est requis. Le rappel d’événement suivant gère les expirations de jeton Push de Firebase Cloud Messaging (FCM).

notificationRegistrationStateChanged

Pour une implémentation complète, voir l’exemple d’application Android.

Connexion de votre utilisateur

Les notifications de Microsoft Graph, ainsi que celles de nombreux autres types de ressources dans Microsoft Graph, sont centralisées autour des utilisateurs. Pour que votre application puisse s’abonner au notifications destinées à l’utilisateur connecté et commencer à les recevoir, vous devez commencer par obtenir un jeton OAuth valide à utiliser dans le processus d’inscription. Vous pouvez utiliser votre méthode préférée de génération et gestion des jetons OAuth. L’exemple d’application a utilisé une bibliothèque d’authentification Active Directory (ADAL).

Si vous utilisez un compte Microsoft, vous devez inclure dans votre demande de connexion les autorisations suivantes : wl.offline_access", ccs.ReadWrite, wns.connect, asimovrome.telemetry et https://activity.windows.com/UserActivity.ReadWrite.CreatedByApp.

Si vous utilisez un compte Microsoft Entra, vous devez demander l’audience suivante : https://cdpcs.access.microsoft.com.

Ajout du compte d’utilisateur à la plateforme

Vous devez inscrire le compte d’utilisateur connecté avec le Kit de développement logiciel (SDK), ce qui implique l’ajout du compte et l’inscription d’un canal de notifications Push pour recevoir les notifications Push initiales via FCM.

public AsyncOperation<Boolean> prepareAccountAsync(final Context context) {
    // Accounts can be in 3 different scenarios:
    // 1: cached account in good standing (initialized in the SDK and our token cache).
    // 2: account missing from the SDK but present in our cache: Add and initialize account.
    // 3: account missing from our cache but present in the SDK. Log the account out async

    // Subcomponents (e.g. UserDataFeed) can only be initialized when an account is in both the app cache
    // and the SDK cache.
    // For scenario 1, initialize our subcomponents.
    // For scenario 2, subcomponents will be initialized after InitializeAccountAsync registers the account with the SDK.
    // For scenario 3, InitializeAccountAsync will unregister the account and subcomponents will never be initialized.
    switch (mState) {
        // Scenario 1
        case IN_APP_CACHE_AND_SDK_CACHE:
            mUserNotificationsManager = new UserNotificationsManager(context, mAccount, mPlatform);
            return registerAccountWithSdkAsync();
        // Scenario 2
        case IN_APP_CACHE_ONLY: {
            // Add the this account to the ConnectedDevicesPlatform.AccountManager
            return mPlatform.getAccountManager().addAccountAsync(mAccount).thenComposeAsync((ConnectedDevicesAddAccountResult result) -> {
                // We failed to add the account, so exit with a failure to prepare bool
                if (result.getStatus() != ConnectedDevicesAccountAddedStatus.SUCCESS) {
                    result.getStatus());
                    return AsyncOperation.completedFuture(false);
                }

                // Set the registration state of this account as in both app and sdk cache
                mState = AccountRegistrationState.IN_APP_CACHE_AND_SDK_CACHE;
                mUserNotificationsManager = new UserNotificationsManager(context, mAccount, mPlatform);
                return registerAccountWithSdkAsync();
            });
        }
        // Scenario 3
        case IN_SDK_CACHE_ONLY:
            // Remove the account from the SDK since the app has no knowledge of it
            mPlatform.getAccountManager().removeAccountAsync(mAccount);
            // This account could not be prepared
            return AsyncOperation.completedFuture(false);
        default:
            // This account could not be prepared
            Log.e(TAG, "Failed to prepare account " + mAccount.getId() + " due to unknown state!");
            return AsyncOperation.completedFuture(false);
    }
}
public AsyncOperation<Boolean> registerAccountWithSdkAsync() {
    if (mState != AccountRegistrationState.IN_APP_CACHE_AND_SDK_CACHE) {
        AsyncOperation<Boolean> toReturn = new AsyncOperation<>();
        toReturn.completeExceptionally(new IllegalStateException("Cannot register this account due to bad state: " + mAccount.getId()));
        return toReturn;
    }

    // Grab the shared GCM/FCM notification token from this app's BroadcastReceiver
    return RomeNotificationReceiver.getNotificationRegistrationAsync().thenComposeAsync((ConnectedDevicesNotificationRegistration notificationRegistration) -> {
        // Perform the registration using the NotificationRegistration
        return mPlatform.getNotificationRegistrationManager().registerAsync(mAccount, notificationRegistration)
            .thenComposeAsync((result) -> {
                if (result.getStatus() == ConnectedDevicesNotificationRegistrationStatus.SUCCESS) {
                    Log.i(TAG, "Successfully registered account " + mAccount.getId() + " for cloud notifications");
                } else {
                    // It would be a good idea for apps to take a look at the different statuses here and perhaps attempt some sort of remediation.
                    // For example, token request failed could mean that the user needs to sign in again. An app could prompt the user for this action 
                    // and retry the operation afterwards.
                    Log.e(TAG, "Failed to register account " + mAccount.getId() + " for cloud notifications!");
                    return AsyncOperation.completedFuture(false);
                }

                return mUserNotificationsManager.registerForAccountAsync();
            });
    });
}

Abonnement pour recevoir les notifications à l’utilisateur

Vous devez instancier un objet UserDataFeed pour votre application pour cet utilisateur connecté. Votre application est identifiée par l’ID d’application multiplateforme que vous avez fourni durant l’intégration d’expériences inter-appareils.

public UserNotificationsManager(@NonNull Context context, @NonNull ConnectedDevicesAccount account, @NonNull ConnectedDevicesPlatform platform)
{
    Context context = new Context;
    UserDataFeed feed = UserDataFeed.getForAccount(account, platform, Secrets.APP_HOST_NAME);
    UserNotificationChannel channel = new UserNotificationChannel(feed);
    UserNotificationReader reader = channel.createReader();
    reader.dataChanged().subscribe((reader, aVoid) -> readFromCache(reader));
    }
}

Réception et gestion de notifications à l’utilisateur

Le diagramme de flux présenté plus haut dans cette rubrique montre que les modèles de programmation pour gérer une nouvelle notification entrante provenant d’un serveur d’applications ou une mise à jour ou suppression de notification lancée par une autre instance du client de l’application sont similaires. Les étapes ci-après ont trait à la gestion de ces modifications des données.

Traitement du signal de notification Push entrante

Tous les types de modifications des données de notification à l’utilisateur génèrent un signal qui est transmis aux clients de l’application sous forme de notification Push. Pour les applications Android, le signal est délivré en temps que message de données de notification Push FCM. Lors de la réception du signal de message de données, l’application doit appeler la méthode TryParse pour déclencher l’extraction par le Kit de développement logiciel (SDK) des modifications des données à partir du service de notifications de Microsoft Graph.

public void onMessageReceived(RemoteMessage message) {
    Map data = message.getData();
    ConnectedDevicesNotification notification = ConnectedDevicesNotification.tryParse(data);

    if (notification != null) {
        try {
            ConnectedDevicesPlatform platform = ConnectedDevicesManager.getConnectedDevicesManager(getApplicationContext()).getPlatform();

            // NOTE: it may be useful to attach completion to this async in order to know when the notification is done being processed.
            // This would be a good time to stop a background service or otherwise cleanup.
            platform.processNotificationAsync(notification);
        } catch (Exception e) {
            Log.e(TAG, "Failed to process FCM notification" + e.getMessage());
        }
    }
}

Gestion des modifications des données de notification à l’utilisateur

Après que le Kit de développement logiciel (SDK) a extrait les modifications des données, un rappel d’événement est lancé, et le client de l’application doit gérer la création, la mise à jour ou la suppression de la notification.

private void readFromCache(final UserNotificationReader reader)
{
    reader.readBatchAsync(Long.MAX_VALUE).thenAccept(notifications -> {
        synchronized (this) {
            for (final UserNotification notification : notifications) {
                if (notification.getStatus() == UserNotificationStatus.ACTIVE) {
                    removeIf(mNewNotifications, item -> notification.getId().equals(item.getId()));

                    if (notification.getUserActionState() == UserNotificationUserActionState.NO_INTERACTION) {
                        mNewNotifications.add(notification);
                        if (notification.getReadState() != UserNotificationReadState.READ) {
                            clearNotification(mContext.getApplicationContext(), notification.getId());
                            addNotification(mContext.getApplicationContext(), notification.getContent(), notification.getId());
                        }
                    } else {
                        clearNotification(mContext.getApplicationContext(), notification.getId());
                    }

                    removeIf(mHistoricalNotifications, item -> notification.getId().equals(item.getId()));
                    mHistoricalNotifications.add(0, notification);
                } else {
                    removeIf(mNewNotifications, item -> notification.getId().equals(item.getId()));
                    removeIf(mHistoricalNotifications, item -> notification.getId().equals(item.getId()));
                    clearNotification(mContext.getApplicationContext(), notification.getId());
                }
            }
        }

    });
}

Mettre à jour l’état d’une notification

Si un changement d’état d’une notification est déclenché par cette instance du client de l’application (par exemple, si la fenêtre contextuelle de notification toast sur cet appareil est activée par l’utilisateur), l’application doit appeler le Kit de développement logiciel (SDK) pour mettre à jour l’état de la notification afin que ce changement d’état soit synchronisé sur tous les appareils utilisés par le même utilisateur.

notification.setUserActionState(UserNotificationUserActionState.ACTIVATED);
notification.saveAsync().whenCompleteAsync((userNotificationUpdateResult, throwable) -> {
    if (throwable == null && userNotificationUpdateResult != null && userNotificationUpdateResult.getSucceeded()) {
        Log.d(TAG, "Successfully activated the notification");
    }
});

Supprimer une notification

Si une suppression de notification est déclenchée par cette instance de client de l’application (par exemple, si la tâche correspondant à cette notification est marquée comme terminée et supprimée de la base de données de votre application), l’application doit appeler le Kit de développement logiciel (SDK) pour supprimer la notification afin que cette opération de suppression soit synchronisée sur tous les appareils utilisés par le même utilisateur.

Une notification n’est supprimée du magasin de notifications à l’utilisateur que si elle a expiré ou été explicitement supprimée. Une notification à l’utilisateur n’est pas supprimée quand vous mettez à jour l’état UserActionState sur Masqué, car la définition sémantique de celui-ci est définie par l’application elle-même.

channel.deleteUserNotificationAsync(notification.getId()).whenCompleteAsync((userNotificationUpdateResult, throwable) -> {
    if (throwable == null && userNotificationUpdateResult != null && userNotificationUpdateResult.getSucceeded()) {
        Log.d(TAG, "Successfully deleted the notification");
    }
});