Partager via


Implémentation d’un relais d’appareil pour Android

La fonctionnalité Relais d’appareil de Project Rome se compose d’un ensemble d’API qui prennent en charge deux fonctionnalités principales : le lancement à distance (également appelé commande) et les services d’application.

Les API de lancement à distance prennent en charge les scénarios où un processus sur un appareil distant est démarré à partir d’un appareil local. Par exemple, un utilisateur peut écouter la radio sur son téléphone dans la voiture, mais lorsqu’il rentre chez lui, il utilise son téléphone pour transférer la lecture vers sa Xbox qui est connectée à la stéréo de la maison.

Les API App Services permettent à une application d’établir un pipeline persistant entre deux appareils via lesquels des messages contenant du contenu arbitraire peuvent être envoyés. Par exemple, une application de partage de photos s’exécutant sur un appareil mobile peut établir une connexion avec le PC de l’utilisateur afin de récupérer des photos.

Les fonctionnalités de Project Rome sont prises en charge par une plateforme sous-jacente appelée plateforme d’appareils connectés. Ce guide fournit les étapes nécessaires pour commencer à utiliser la plateforme Appareils connectés, puis explique comment utiliser la plateforme pour implémenter les fonctionnalités associées à Device Relay.

Ces étapes ci-dessous référencent le code de l’exemple d’application Android Project Rome.

Pour toutes les fonctionnalités d’appareils connectés, vous aurez besoin d’un IDE de développement d’applications Android et d’un appareil Android avec l’une des architectures prises en charge (armeabi-v7a, arm64-v8a, x86 ou x86_64) ou un émulateur. Le système doit exécuter Android 4.4.2 ou version ultérieure.

Configuration préliminaire de la plateforme et des notifications des appareils connectés

Avant d’implémenter la connectivité à distance, vous devez effectuer quelques étapes pour permettre à votre application Android de se connecter à des appareils distants, ainsi que d’envoyer et de recevoir des notifications.

Inscrire votre application

L'authentification du compte Microsoft (MSA) ou Azure Active Directory (AAD) est requise pour presque toutes les fonctionnalités du Project Rome SDK (l'exception étant les API de partage à proximité). Si vous n’avez pas encore de MSA et que vous souhaitez en utiliser un, inscrivez-vous sur account.microsoft.com.

Remarque

Les comptes Azure Active Directory (AAD) ne sont pas pris en charge avec les API Device Relay.

À l’aide de votre méthode d’authentification choisie, vous devez inscrire votre application auprès de Microsoft en suivant les instructions du portail d’inscription d’application. Si vous n’avez pas de compte de développeur Microsoft, vous devez en créer un.

Lorsque vous inscrivez une application à l’aide d’un MSA, vous devez recevoir une chaîne d’ID client. Enregistrez-le pour plus tard. Cela permet à votre application d’accéder aux ressources de la plateforme Appareils connectés de Microsoft. Si vous utilisez AAD, consultez les bibliothèques d’authentification Azure Active Directory pour obtenir des instructions sur l’obtention de la chaîne d’ID client.

Ajouter le Kit de développement logiciel (SDK)

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

allprojects {
    repositories {
        jcenter()
    }
}

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

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

Dans le fichier AndroidManifest.xml de votre projet, ajoutez les autorisations suivantes à l’intérieur de l’élément <manifest> (s’ils ne sont pas déjà présents). Cela donne à votre application l’autorisation de se connecter à Internet et d’activer la découverte Bluetooth sur votre appareil.

Notez que les autorisations bluetooth sont uniquement nécessaires pour l’utilisation de la découverte Bluetooth ; elles ne sont pas nécessaires pour les autres fonctionnalités de la plateforme Appareils connectés. En outre, ACCESS_COARSE_LOCATION n'est requis que sur les SDK Android 21 et versions ultérieures. Sur les kits SDK Android 23 et versions ultérieures, le développeur doit également inviter l’utilisateur à accorder l’accès à l’emplacement au moment de l’exécution.

<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 à la ou les classes d’activité où vous souhaitez que la fonctionnalité Appareils connectés soit active. Importez les packages suivants.

import com.microsoft.connecteddevices;
import com.microsoft.connecteddevices.remotesystems;
import com.microsoft.connecteddevices.remotesystems.commanding;

Configurer l’authentification et la gestion des comptes

La plateforme Appareils connectés nécessite 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 de gestion des jetons OAuth. Toutefois, pour aider les développeurs à commencer à utiliser la plateforme, nous avons inclus un fournisseur d’authentification dans le cadre de l’exemple d’application Android qui génère et gère des jetons d’actualisation pour votre commodité.

Si vous souhaitez implémenter l’interface ConnectedDevicesAccountManager vous-même, notez les informations suivantes :

Si vous utilisez un MSA, vous devez inclure les étendues suivantes dans votre demande de connexion : "wl.offline_access", "ccs.ReadWrite", "dds.read", "dds.register", "wns.connect", "asimovrome.telemetry", et "https://activity.windows.com/UserActivity.ReadWrite.CreatedByApp".

Si vous utilisez un compte AAD, vous devez demander les audiences suivantes : "https://cdpcs.access.microsoft.com", "https://cs.dds.microsoft.com", "https://wns.windows.com/" et "https://activity.microsoft.com".

Remarque

Les comptes Azure Active Directory (AAD) ne sont pas pris en charge avec les API Device Relay.

Que vous utilisiez l’implémentation ConnectedDevicesAccountManager fournie ou non, si vous utilisez AAD, vous devez spécifier les autorisations suivantes dans l’inscription de votre application sur le portail Azure (portal.azure.com > inscriptions d’applications Azure Active Directory > ) :

  • Service de flux d’activité Microsoft
    • Remettre et modifier des notifications utilisateur pour cette application
    • Lire et écrire l’activité de l’application dans le flux d’activités des utilisateurs
  • Service de Notifications Windows
    • Connecter votre appareil au service de notification Windows
  • Service d’annuaire d’appareils Microsoft
    • Afficher votre liste d’appareils
    • Être ajouté à votre liste d’appareils et d’applications
  • Service de commandes Microsoft
    • Communiquer avec les appareils de l’utilisateur
    • Lire les appareils de l’utilisateur

Inscription de votre application pour les notifications Push

Inscrivez votre application auprès de Google pour la prise en charge de Firebase Cloud Messaging . Veillez à noter l’ID d’expéditeur et la clé de serveur que vous recevez ; vous en aurez besoin plus tard.

Une fois inscrit, vous devez associer des fonctionnalités de notification Push à la plateforme Appareils connectés dans votre application.

mNotificationRegistration = new ConnectedDevicesNotificationRegistration();
mNotificationRegistration.setType(ConnectedDevicesNotificationType.FCM);
mNotificationRegistration.setToken(token);
mNotificationRegistration.setAppId(Secrets.FCM_SENDER_ID);
mNotificationRegistration.setAppDisplayName("SampleApp");

Inscrire votre application dans le Centre de développement Microsoft Windows pour les expériences inter-appareils

Important

Cette étape n’est requise que si vous souhaitez utiliser les fonctionnalités de Project Rome pour accéder aux données à partir ou effectuer des demandes d’appareils non-Windows. Si vous ciblez uniquement des appareils Windows, vous n’avez pas besoin d’effectuer cette étape.

Accédez au tableau de bord du Centre de développement, accédez à Expériences inter-appareils dans le volet de navigation de gauche, puis sélectionnez configuration d’une nouvelle application inter-appareils, comme indiqué ci-dessous. Tableau de bord du Centre de développement – Expériences inter-appareils

Le processus d’intégration du Centre de développement nécessite les étapes suivantes :

  • Sélectionnez les plateformes prises en charge : sélectionnez les plateformes où votre application aura une présence et sera activée pour les expériences inter-appareils. Dans le cas de l’intégration des notifications Graph, vous pouvez sélectionner à partir de Windows, Android et/ou iOS. Expériences inter-appareils – Plateformes prises en charge

  • Fournir des ID d’application : fournissez des ID d’application pour chacune des plateformes où votre application a une présence. Pour les applications Android, il s’agit du nom du package que vous avez affecté à votre application lorsque vous avez créé le projet. Le nom du package se trouve dans votre console Firebase sous Vue d’ensemble du projet -> Général. Vous pouvez ajouter des ID différents (jusqu’à dix) par plateforme : il s’agit du cas où vous disposez de plusieurs versions de la même application, voire d’applications différentes, qui souhaitent être en mesure de recevoir les mêmes notifications envoyées par votre serveur d’applications ciblant le même utilisateur. Expériences inter-appareils – ID d’application

  • Fournissez ou sélectionnez les ID d’application à partir des enregistrements d'applications MSA et/ou AAD. Ces ID clients correspondant à l’inscription d’application MSA ou AAD ont été obtenus dans les étapes précédentes de l’inscription d’application MSA/AAD ci-dessus. Expériences multiplateformes – enregistrements d’applications MSA et AAD

  • Les notifications Graph et d’autres fonctionnalités de plateforme d’appareils connectés tirent parti de chacune des plateformes de notification natives sur les principales plateformes pour envoyer des notifications aux points de terminaison du client d’application, à savoir WNS (pour Windows UWP), FCM (pour Android) et APNS (pour iOS). Fournissez vos informations d’identification pour ces plateformes de notification pour permettre aux notifications Graph de remettre les notifications pour votre serveur d’applications lorsque vous publiez des notifications ciblées par l’utilisateur. Pour Android, l’activation du service Cloud Messaging est une condition préalable à l’utilisation des notifications Microsoft Graph. Notez également que l’ID d’expéditeur requis correspond à l’ID d’expéditeur firebase Cloud Messaging, et que la clé API correspond à la clé de serveur héritée. Les deux sont disponibles dans la console Firebase - Projet ->> Paramètres, sous l’onglet Cloud Messaging, comme illustré dans la capture d’écran. Expériences inter-appareils : informations d’identification Push

  • La dernière étape consiste à vérifier votre domaine d’application inter-appareils, qui sert de processus de vérification pour prouver que votre application a la propriété de ce domaine qui agit comme une identité d’application inter-appareils pour l’application que vous avez inscrite. Expériences multi-appareils – Vérification de domaine

Utilisation de la plateforme

Créer la plateforme

Pour commencer, instanciez simplement la plateforme.

ConnectedDevicesPlatform sPlatform = new ConnectedDevicesPlatform(context);

S’abonner aux événements ConnectedDevicesAccountManager pour gérer le compte d’utilisateur

La plateforme nécessite qu’un utilisateur authentifié accède à la plateforme. Vous devez vous abonner aux événements ConnectedDevicesAccountManager pour vous assurer qu’un compte valide est utilisé.

 ConnectedDevicesPlatform sPlatform.getAccountManager().accessTokenRequested().subscribe((accountManager, args) -> {

    // Get access token
}
 ConnectedDevicesPlatform sPlatform.getAccountManager().accessTokenInvalidated().subscribe((accountManager, args) -> {

    // Refresh and renew existing access token
}

S’abonner aux événements ConnectedDevicesNotificationRegistrationManager

De même, la plateforme utilise des notifications pour remettre des commandes entre les appareils. Par conséquent, vous devez vous abonner aux événements ConnectedDevicesNotificationRegistrationManager pour vous assurer que les états d’inscription cloud sont valides pour le compte utilisé. Vérifier l’état à l’aide de ConnectedDevicesNotificationRegistrationState

ConnectedDevicesPlatform sPlatform.getNotificationRegistrationManager().notificationRegistrationStateChanged().subscribe((notificationRegistrationManager, args) -> {
    
     // Check state using ConnectedDevicesNotificationRegistrationState enum

}

Démarrer la plateforme

Maintenant que la plateforme est initialisée et que les gestionnaires d’événements sont en place, vous êtes prêt à commencer à découvrir des appareils système distants.

ConnectedDevicesPlatform sPlatform.start();

Récupérer des comptes d’utilisateur connus de l’application

Il est important de s’assurer que la liste des comptes d’utilisateur connus de l’application est correctement synchronisée avec ConnectedDevicesAccountManager.

Utilisez ConnectedDevicesAccountManager.addAccountAsync pour ajouter un nouveau compte d’utilisateur.

 public synchronized AsyncOperation<ConnectedDevicesAddAccountResult> addAccountToAccountManagerAsync(ConnectedDevicesAccount account) {
        return ConnectedDevicesPlatform sPlatform.getAccountManager().addAccountAsync(account);
    }

Pour supprimer un compte non valide, vous pouvez utiliser ConnectedDevicesAccountManager.removeAccountAsync

 public synchronized AsyncOperation<ConnectedDevicesAddAccountResult> removeAccountToAccountManagerAsync(ConnectedDevicesAccount account) {
        return ConnectedDevicesPlatform sPlatform.getAccountManager().removeAccountAsync(account);
    }

Découvrir des appareils et applications distants

Une instance RemoteSystemWatcher gère les fonctionnalités principales de cette section. Déclarez-le dans la classe qui consiste à découvrir les systèmes distants.

private RemoteSystemWatcher mWatcher = null;

Avant de créer un observateur et de commencer à découvrir des appareils, vous pouvez ajouter des filtres de découverte pour déterminer les types d’appareils que votre application ciblera. Celles-ci peuvent être déterminées par l’entrée utilisateur ou codées en dur dans l’application, en fonction de votre cas d’usage.

private void onStartWatcherClicked() {
    // RemoteSystemWatcher cannot be started unless the platform is 
    // initialized and the user is logged in. It may be helpful to use
    // methods like these to track the state of the application.
    // See the sample app for their implementations.
    if (!getMainActivity().isSignedIn()) {
        return;
    }
    if (!getMainActivity().isPlatformInitialized()) {
        return;
    }

    // create and populate a list of filters. The filter choices below are arbitrary.
    ArrayList<RemoteSystemFilter> filters = new ArrayList<>();

    /*  RemoteSystemDiscoveryType filters can be used to filter the types of Remote Systems you discover.
    Possible values:
        ANY(0),
        PROXIMAL(1),
        CLOUD(2),
        SPATIALLY_PROXIMAL(3)
    */
    filters.add(new RemoteSystemDiscoveryTypeFilter(RemoteSystemDiscoveryType.ANY));

    /*  RemoteSystemStatusType filters can be used to filter the status of Remote Systems you discover.
    Possible values:
        ANY(0),
        AVAILABLE(1)
    */
    filters.add(new RemoteSystemStatusTypeFilter(RemoteSystemStatusType.AVAILABLE));


    /*  RemoteSystemKindFilter can filter the types of devices you want to discover.
    Possible values are members of the RemoteSystemKinds class.
    */
    String[] kinds = new String[] { RemoteSystemKinds.Phone(), RemoteSystemKinds.Tablet() };

    RemoteSystemKindFilter kindFilter = new RemoteSystemKindFilter(kinds);
    filters.add(kindFilter);

    /*  RemoteSystemAuthorizationKind determines the category of user whose system(s) you want to discover.
    Possible values:
        SAME_USER(0),
        ANONYMOUS(1)
    */
    filters.add(new RemoteSystemAuthorizationKindFilter(RemoteSystemAuthorizationKind.SAME_USER)); 
    // ...

À ce stade, l’application peut initialiser l’objet observateur qui détermine la façon dont votre application analyse et interagit avec les appareils découverts.

    // ...

    // Create a RemoteSystemWatcher
    mWatcher = new RemoteSystemWatcher(filters.toArray(new RemoteSystemFilter[filters.size()]));
    }

    // ...

Il est recommandé que votre application conserve un ensemble d’appareils découverts (représentés par des instances RemoteSystem ) et affiche des informations sur les appareils disponibles et leurs applications (par exemple, le nom d’affichage et le type d’appareil) sur l’interface utilisateur.

Les stubs de classe suivants peuvent être utilisés comme écouteurs d’événements pour l’instance observateur.

private class RemoteSystemAddedListener implements EventListener<RemoteSystemWatcher, RemoteSystem> {
    @Override
    public void onEvent(RemoteSystemWatcher remoteSystemWatcher, RemoteSystem remoteSystem) {
        // add instance "remoteSystem" to program memory. See sample for full implementation.
    }
}

private class RemoteSystemUpdatedListener implements EventListener<RemoteSystemWatcher, RemoteSystem> {
    @Override
    public void onEvent(RemoteSystemWatcher remoteSystemWatcher, RemoteSystem remoteSystem) {
        // update instance "remoteSystem" in program memory. See sample for full implementation.
    }
}

private class RemoteSystemRemovedListener implements EventListener<RemoteSystemWatcher, RemoteSystem> {
    @Override
    public void onEvent(RemoteSystemWatcher remoteSystemWatcher, RemoteSystem remoteSystem) {
        // remove instance "remoteSystem" from program memory. See sample for full implementation.
    }
}

private class RemoteSystemWatcherErrorOccurredListener implements EventListener<RemoteSystemWatcher, RemoteSystemWatcherError> {
    @Override
    public void onEvent(RemoteSystemWatcher remoteSystemWatcher, RemoteSystemWatcherError remoteSystemWatcherError) {
        // handle the error
    }
}

Une fois mWatcher.start appelé, il commence à surveiller l’activité du système distant et déclenche des événements lorsque les appareils sont découverts, mis à jour ou supprimés de l’ensemble d’appareils découverts. Il analyse en continu en arrière-plan, il est donc recommandé d’arrêter l’observateur quand vous n’en avez plus besoin pour éviter les communications réseau inutiles et le drainage de la batterie.

// if you call this from the activity's onPause method, you ensure that
// it will stop when the activity exits the foreground.
public void stopWatcher() {
    if (mWatcher == null) {
        return;
    }
    mWatcher.stop();
}

Exemple de cas d’usage : implémentation du lancement à distance et des services d’application distants

À ce stade de votre code, vous devez disposer d’une liste de travail d’objets RemoteSystem qui font référence aux appareils disponibles. Ce que vous faites avec ces appareils dépend de la fonction de votre application. Les principaux types d’interaction sont le lancement à distance et les services d’application distants. Elles sont expliquées dans les sections suivantes.

A) Lancement à distance

Le code suivant montre comment sélectionner l’un de ces appareils (dans l’idéal, cela s’effectue via un contrôle d’interface utilisateur), puis utiliser RemoteLauncher pour lancer une application sur celle-ci en transmettant un URI compatible avec l’application.

Il est important de noter qu’un lancement distant peut cibler un appareil distant (auquel cas l’appareil hôte lance l’URI donné avec son application par défaut pour ce schéma d’URI) ou une application distante spécifique sur cet appareil.

Comme l’a montré la section précédente, la découverte se produit d’abord au niveau de l’appareil (un RemoteSystem représente un appareil), mais vous pouvez appeler la getApplications méthode sur une instance RemoteSystem Pour obtenir un tableau d’objets RemoteSystemApp, qui représentent des applications sur l’appareil distant qui ont été inscrites pour utiliser la plateforme d’appareils connectés (tout comme vous avez inscrit votre propre application dans les étapes préliminaires ci-dessus). RemoteSystem et RemoteSystemApp peuvent être utilisés pour construire une remoteSystemConnectionRequest, ce qui est nécessaire pour lancer un URI.

// this could be a RemoteSystemApp instead. Either way, it 
// must be defined somewhere in the application before the launch operation
// is called.
private RemoteSystem target; 

// ...

/**
* Responsible for calling into the Rome API to launch the given URI and provides
* the logic to handle the RemoteLaunchUriStatus response.
* @param uri URI to launch
* @param target The target for the launch URI request
*/
private void launchUri(final String uri, final RemoteSystem target, final long messageId)
{
    RemoteLauncher remoteLauncher = new RemoteLauncher();

    AsyncOperation<RemoteLaunchUriStatus> resultOperation = remoteLauncher.launchUriAsync(new RemoteSystemConnectionRequest(target), uri);
    // ...

Utilisez l'AsyncOperation retournée pour traiter le résultat de la tentative de lancement.

    // ...
    resultOperation.whenCompleteAsync(new AsyncOperation.ResultBiConsumer<RemoteLaunchUriStatus, Throwable>() {
        @Override
        public void accept(RemoteLaunchUriStatus status, Throwable throwable) throws Throwable {
            if (throwable != null) {
                // handle the exception, referencing "throwable"
            } else {
                if (status == RemoteLaunchUriStatus.SUCCESS) {
                    // report the success case
                } else {
                    // report the non-success case, referencing "status"
                }
            }
        }
    });
}

Selon l’URI envoyé, vous pouvez lancer une application dans un état ou une configuration spécifique sur un appareil distant. Cela permet de continuer une tâche utilisateur, comme regarder un film, sur un autre appareil sans interruption.

Selon votre cas d’usage, vous devrez peut-être couvrir les cas dans lesquels aucune application sur le système ciblé ne peut gérer l’URI, ou plusieurs applications peuvent la gérer. La classe RemoteLauncher et la classe RemoteLauncherOptions décrivent comment procéder.

B) Services d’application distants

Votre application Android peut utiliser le portail appareils connectés interagir avec les services d’application sur d’autres appareils. Cela offre de nombreuses façons de communiquer avec d’autres appareils, sans avoir besoin d’apporter une application au premier plan de l’appareil hôte.

Configurer le service d’application sur l’appareil cible

Ce guide utilise l’application de test romain pour Windows comme service d’application cible. Par conséquent, le code ci-dessous amènera l'application Android à rechercher ce service d'application spécifique sur le système distant spécifié. Si vous souhaitez tester ce scénario, téléchargez l’application de test romain sur un appareil Windows et vérifiez que vous êtes connecté avec le même MSA que celui que vous avez utilisé dans les étapes préliminaires ci-dessus.

Pour obtenir des instructions sur l’écriture de votre propre service d’application UWP, consultez Créer et consommer un service d’application (UWP). Vous devez apporter quelques modifications pour rendre le service compatible avec les appareils connectés. Consultez le guide UWP pour les services d’application distants pour obtenir des instructions sur la façon de procéder.

Ouvrir une connexion App Service sur l’appareil client

Votre application Android doit acquérir une référence à un appareil distant ou une application. Comme la section de lancement, ce scénario nécessite l’utilisation d’une remoteSystemConnectionRequest, qui peut être construite à partir d’un RemoteSystem ou d’une RemoteSystemApp représentant une application disponible sur le système.

// this could be a RemoteSystemApp instead. Either way, it 
// must be defined somewhere in the application before the app service
// connection is opened.
private RemoteSystem target = null;

En outre, votre application doit identifier son service d’application ciblé à l’aide de deux chaînes : le nom du service d’application et l’identificateur de package. Ceux-ci se trouvent dans le code source du fournisseur app service (consultez Créer et consommer un service d’application (UWP) pour plus d’informations sur l’obtention de ces chaînes pour les services d’application Windows. Ensemble, ces chaînes construisent appServiceDescription, qui est transmise à une instance AppServiceConnection .

// this is defined below
private AppServiceConnection connection = null; 


/**
* Creates an AppService connection with the current identifier and service name and opens the
* app service connection.
*/
private void onNewConnectionButtonClicked()
{
    connection = new AppServiceConnection();

    // these hard-coded strings must be defined elsewhere in the app
    connection.setAppServiceDescription(new AppServiceDescription(mAppServiceName, mPackageIdentifier));

    // this method is defined below
    openAppServiceConnection();
}
/**
* Establish an app service connection.
* Opens the given AppService connection using the connection request. Once the connection is
* opened, it adds the listeners for request-received and close. Catches all exceptions
* to show behavior of API surface exceptions.
*/
private void openAppServiceConnection()
{
    // optionally report outbound request
    // ...

    RemoteSystemConnectionRequest connectionRequest = new RemoteSystemConnectionRequest(target));

    /* Will asynchronously open the app service connection using the given connection request
    * When this is done, we log the traffic in the UI for visibility to the user (for sample purposes)
    * We can check the status of the connection to determine whether or not it was successful, and show 
    * some UI if it wasn't (in this case it is part of the list item).
    */
    connection.openRemoteAsync(connectionRequest)
        .thenAcceptAsync(new AsyncOperation.ResultConsumer<AppServiceConnectionStatus>() {
            @Override
            public void accept(AppServiceConnectionStatus appServiceConnectionStatus) throws Throwable {
                // optionally report inbound response
                // ...

                if (appServiceConnectionStatus != AppServiceConnectionStatus.SUCCESS) {
                    // report the error, referencing "appServiceConnectionStatus"
                    return;
                }
            }
        })
        .exceptionally(new AsyncOperation.ResultFunction<Throwable, Void>() {
            @Override
            public Void apply(Throwable throwable) throws Throwable {
                // report the exception
                return null;
            }
        });
}

Créer un message à envoyer au service d’application

Déclarez une variable pour stocker le message à envoyer. Sur Android, les messages que vous envoyez aux services d’application distants seront de type Carte .

private Map<String, Object> mMessagePayload = null;

Remarque

Lorsque votre application communique avec les services d’application sur d’autres plateformes, la plateforme d’appareils connectés traduit la carte en construction correspondante sur la plateforme de réception. Par exemple, une carte envoyée à partir de cette application à un service d’application Windows est traduite en objet ValueSet (du .NET Framework), qui peut ensuite être interprété par le service d’application. Les informations transmises dans l’autre sens subissent la traduction inverse.

La méthode suivante compose un message pouvant être interprété par le service d'application de test Roman pour Windows.

/**
* Send the current message payload through all selected AppService connections on a non-UI
* thread as to not block user interaction, a result of the delay between API calls.
*/
private void onMessageButtonClicked()
{
    mMessagePayload = new HashMap<>();
    // Add the required fields of RomanApp on Windows
    DateFormat df = new SimpleDateFormat(DATE_FORMAT);
    mMessagePayload.put("Type", "ping");
    mMessagePayload.put("CreationDate", df.format(new Date()));
    mMessagePayload.put("TargetId", "check if this field needs to be included");

    // this method is defined below.
    sendMessage(connection, mMessagePayload);
}

Important

Les mappages transmis entre les applications et les services dans le scénario des services d'application distants doivent respecter le format suivant: les clés doivent être des chaînes, et les valeurs possibles incluent des chaînes, des types numériques encapsulés (entiers ou flottants), des booléens encapsulés, android.graphics.Point, android.graphics.Rect, java.util.Date, java.util.UUID, des tableaux homogènes de l'un de ces types ou d'autres objets Map conformes à cette spécification.

Envoyer un message au service d’application

Une fois la connexion app service établie et le message créé, l’envoyer au service d’application est simple et peut être effectué n’importe où dans l’application qui a une référence à l’instance de connexion app service et le message.


// When assigning message IDs, use an incremental counter
private AtomicInteger mMessageIdAppServices = new AtomicInteger(0);

// ...

/**
* Send a message using the app service connection
* Send the given Map object through the given AppServiceConnection. Uses an internal messageId
* for logging purposes.
* @param connection AppServiceConnection to send the Map payload
* @param message Payload to be translated to a ValueSet
*/
private void sendMessage(final AppServiceConnection connection, Map<String, Object> message)
{
    final long messageId = mMessageIdAppServices.incrementAndGet();

    connection.sendMessageAsync(message)
        .thenAcceptAsync(new AsyncOperation.ResultConsumer<AppServiceResponse>() {
            @Override
            public void accept(AppServiceResponse appServiceResponse) throws Throwable {
                // optionally report an inbound response

                // this method is defined below
                handleAppServiceResponse(appServiceResponse, messageId);
            }
        })
        .exceptionally(new AsyncOperation.ResultFunction<Throwable, Void>() {
            @Override
            public Void apply(Throwable throwable) throws Throwable {
                // report the exception, referencing "throwable"

                return null;
            }
        });

    // optionally log the outbound message request here, referencing 
    // connection.getAppServiceDescription().getName() as the recipient.
}

La réponse du service d’application est reçue et interprétée par la méthode suivante.

private void handleAppServiceResponse(AppServiceResponse appServiceResponse, long messageId)
{
    AppServiceResponseStatus status = appServiceResponse.getStatus();
    if (status == AppServiceResponseStatus.SUCCESS)
    {
        // the message was delivered successfully; interpret the response.
        Map<String, Object> response;
        response = appServiceResponse.getMessage();

        // in the Roman App case, the response contains the date it was created.
        String dateStr = (String)response.get("CreationDate");
        DateFormat df = new SimpleDateFormat(DATE_FORMAT, Locale.getDefault());

        // in this very simple use case, we compare the dates to get the total
        // transit time of the message response.
        try {
            Date startDate = df.parse(dateStr);
            Date nowDate = new Date();
            long diff = nowDate.getTime() - startDate.getTime();
            // do something with "diff"
        } catch (ParseException e) { e.printStackTrace(); }
    }
}

Dans le cas de l’application romaine, la réponse contient la date à laquelle elle a été créée. Dans ce cas d’usage très simple, nous pouvons comparer les dates pour obtenir le temps de transit total de la réponse du message.

Cela conclut un échange de messages unique avec un service d’application distant.

Terminer la communication du service d'application

Lorsque votre application a terminé d'interagir avec le service d'application de l'appareil cible, fermez la connexion entre les deux appareils.

// Close the given AppService connection
private void closeAppServiceConnection()
{
    connection.close();
}