Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
La funcionalidad De retransmisión de dispositivos de Project Rome consta de un conjunto de API que admiten dos características principales: el inicio remoto (también conocido como comandos) y los servicios de aplicaciones.
Las API de inicio remoto admiten escenarios en los que se inicia un proceso en un dispositivo remoto desde un dispositivo local. Por ejemplo, un usuario podría estar escuchando la radio en su teléfono en el coche, pero cuando llega a casa usa su teléfono para transferir la reproducción a su Xbox que está enlazada al estéreo doméstico.
Las API de App Services permiten a una aplicación establecer una canalización persistente entre dos dispositivos a través de los cuales se pueden enviar mensajes que contengan contenido arbitrario. Por ejemplo, una aplicación de uso compartido de fotos que se ejecuta en un dispositivo móvil podría establecer una conexión con el equipo del usuario para recuperar fotos.
Las características de Project Rome son compatibles con una plataforma subyacente denominada Plataforma de dispositivos conectados. En esta guía se proporcionan los pasos necesarios para empezar a usar la plataforma de dispositivos conectados y, a continuación, se explica cómo usar la plataforma para implementar características relacionadas con Device Relay.
En estos pasos se hace referencia al código de la aplicación de ejemplo de Android de Project Rome.
Para todas las características de dispositivos conectados, necesitará 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 un emulador. El sistema debe ejecutar Android 4.4.2 o posterior.
Configuración preliminar de la plataforma y las notificaciones de dispositivos conectados
Antes de implementar la conectividad remota, hay algunos pasos que debe seguir para proporcionar a la aplicación Android la capacidad de conectarse a dispositivos remotos, así como enviar y recibir notificaciones.
Registro de la aplicación
La autenticación de la cuenta Microsoft (MSA) o Azure Active Directory (AAD) es necesaria para casi todas las características del SDK de Project Rome (la excepción es las API de uso compartido cercanas). Si aún no tiene una MSA y desea usar una, regístrese en account.microsoft.com.
Nota:
Las cuentas de Azure Active Directory (AAD) no se admiten con las API de Device Relay.
Con el método de autenticación elegido, debe registrar la aplicación con Microsoft siguiendo las instrucciones del Portal de registro de aplicaciones. Si no tiene una cuenta de desarrollador de Microsoft, deberá crear una.
Al registrar una aplicación mediante una MSA, debe recibir una cadena de identificador de cliente. Guárdelo para más adelante. Esto permitirá que la aplicación acceda a los recursos de la Plataforma de dispositivos conectados de Microsoft. Si usa AAD, consulte Bibliotecas de autenticación de Azure Active Directory para obtener instrucciones sobre cómo obtener la cadena de identificador de cliente.
Adición del SDK
Inserte las referencias del repositorio siguientes en el archivo build.gradle en la raíz del proyecto.
allprojects {
repositories {
jcenter()
}
}
A continuación, inserte 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, agregue los siguientes permisos dentro del <manifest>
elemento (si aún no están presentes). Esto concede a la aplicación permiso para conectarse a Internet y habilitar la detección de Bluetooth en el dispositivo.
Tenga en cuenta que los permisos relacionados con Bluetooth solo son necesarios para usar la detección de Bluetooth; no son necesarios para las otras características de la plataforma de dispositivos conectados. Además, ACCESS_COARSE_LOCATION
solo se requiere en los SDK de Android 21 y versiones posteriores. En los SDK de Android 23 y versiones 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, vaya a la clase(es) de actividad donde desea que viva la funcionalidad Dispositivos conectados. Importe 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 use un token de OAuth válido en el proceso de registro. Puede usar el método preferido para generar y administrar los tokens de 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 genera y administra tokens de actualización para su comodidad.
Si desea implementar la interfaz ConnectedDevicesAccountManager usted mismo, tome nota de la siguiente información:
Si usa una MSA, deberá 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 usa una cuenta de AAD, deberá solicitar las siguientes audiencias: "https://cdpcs.access.microsoft.com"
, "https://cs.dds.microsoft.com"
, "https://wns.windows.com/"
, y "https://activity.microsoft.com"
.
Nota:
Las cuentas de Azure Active Directory (AAD) no se admiten con las API de Device Relay.
Tanto si usa la implementación proporcionada de ConnectedDevicesAccountManager o no, si usa AAD, deberá especificar los siguientes permisos en el registro de su aplicación en el Azure Portal (portal.azure.com > Azure Active Directory > registros de aplicaciones):
- Servicio de flujo de actividades de Microsoft
- Entrega y modificación de notificaciones de 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
- Conexión del dispositivo al servicio de notificaciones de Windows
- Servicio de directorio de dispositivos de Microsoft
- Ver la lista de dispositivos
- Se agregará a la lista de dispositivos y aplicaciones.
- Servicio de comandos de Microsoft
- Comunicarse con los dispositivos del usuario
- Leer los dispositivos del usuario
Registro de la aplicación para notificaciones push
Registre su aplicación con Google para soporte de Firebase Cloud Messaging. Asegúrese de anotar el identificador del remitente y la clave de servidor que recibe; los necesitará más adelante.
Una vez registrado, debe asociar la funcionalidad de notificación push a la Plataforma de Dispositivos Conectados en tu aplicación.
mNotificationRegistration = new ConnectedDevicesNotificationRegistration();
mNotificationRegistration.setType(ConnectedDevicesNotificationType.FCM);
mNotificationRegistration.setToken(token);
mNotificationRegistration.setAppId(Secrets.FCM_SENDER_ID);
mNotificationRegistration.setAppDisplayName("SampleApp");
Registrar la aplicación en el Centro de desarrollo de Microsoft Windows para experiencias entre dispositivos
Importante
Este paso solo es necesario si desea usar las características de Project Rome para acceder a los datos o realizar solicitudes de dispositivos que no son Windows. Si solo tiene como destino dispositivos Windows, no es necesario completar este paso.
Vaya al Panel del Centro de desarrollo, vaya a Experiencias entre dispositivos en el panel de navegación izquierdo y seleccione Configurar una nueva aplicación entre dispositivos, como se muestra a continuación.
El proceso de incorporación del Centro de desarrollo requiere los pasos siguientes:
Seleccione plataformas admitidas: seleccione las plataformas en las que la aplicación tendrá presencia y se habilitará para experiencias entre dispositivos. En el caso de la integración de notificaciones de Graph, puede seleccionar desde las plataformas Windows, Android y/o iOS.
Proporcionar identificadores de aplicación: proporcione identificadores de aplicación para cada una de las plataformas donde la aplicación tenga presencia. En el caso de las aplicaciones Android, este es el nombre del paquete que asignó a la aplicación al crear el proyecto. El nombre del paquete se puede encontrar en la consola de Firebase en Información general del proyecto:> General. Puede agregar identificadores diferentes (hasta diez) por plataforma: en caso de que tenga varias versiones de la misma aplicación, o incluso aplicaciones diferentes, que quieran poder recibir las mismas notificaciones enviadas por el servidor de aplicaciones destinado al mismo usuario.
Proporcione o seleccione los identificadores de aplicación de MSA o registros de aplicaciones de AAD. Estos identificadores de cliente correspondientes al registro de aplicaciones de MSA o AAD se obtuvieron en los pasos previos de registro de aplicaciones mencionados arriba.
Las notificaciones de Graph y otras funcionalidades de la plataforma de dispositivos conectados utilizan cada una de las plataformas de notificación nativas en las principales plataformas para enviar notificaciones a los puntos de conexión del cliente de la aplicación, a saber, WNS (para UWP de Windows), FCM (para Android) y APNS (para iOS). Proporcione sus credenciales para estas plataformas de notificación para habilitar las notificaciones de Graph y entregar las notificaciones para su servidor de aplicaciones cuando publique notificaciones dirigidas al usuario. Para Android, habilitar el servicio de mensajería en la nube es un requisito previo para usar las notificaciones de Microsoft Graph. Además, tenga en cuenta que el identificador de remitente necesario corresponde al identificador de remitente de Firebase Cloud Messaging y la clave de API corresponde a la clave de servidor heredado. Ambos se pueden encontrar en Firebase Console - Project - Settings (Consola de Firebase:> Proyecto:> configuración), en la pestaña Mensajería en la nube, como se muestra en la captura de pantalla.
El último paso es comprobar el dominio de la aplicación entre dispositivos, que actúa como un proceso de comprobación para demostrar que la aplicación tiene la propiedad de este dominio que actúa como una identidad de aplicación entre dispositivos para la aplicación que registró.
Uso de la plataforma
Creación de la plataforma
Para empezar, sencillamente instancie la plataforma.
ConnectedDevicesPlatform sPlatform = new ConnectedDevicesPlatform(context);
Suscríbase a eventos ConnectedDevicesAccountManager para controlar la cuenta de usuario.
La plataforma requiere que un usuario autenticado acceda a la plataforma. Deberá suscribirse a eventos ConnectedDevicesAccountManager para asegurarse de que se usa una cuenta válida.
ConnectedDevicesPlatform sPlatform.getAccountManager().accessTokenRequested().subscribe((accountManager, args) -> {
// Get access token
}
ConnectedDevicesPlatform sPlatform.getAccountManager().accessTokenInvalidated().subscribe((accountManager, args) -> {
// Refresh and renew existing access token
}
Suscribirse a los eventos de ConnectedDevicesNotificationRegistrationManager
Del mismo modo, la plataforma usa notificaciones para entregar comandos entre dispositivos. Por lo tanto, debe suscribirse a los eventos ConnectedDevicesNotificationRegistrationManager para asegurarse de que los estados de registro en la nube son válidos para la cuenta que se usa. Comprobación del estado mediante ConnectedDevicesNotificationRegistrationState
ConnectedDevicesPlatform sPlatform.getNotificationRegistrationManager().notificationRegistrationStateChanged().subscribe((notificationRegistrationManager, args) -> {
// Check state using ConnectedDevicesNotificationRegistrationState enum
}
Inicio de la plataforma
Ahora que la plataforma se inicializa y los controladores de eventos están en su lugar, está listo para empezar a detectar dispositivos del sistema remoto.
ConnectedDevicesPlatform sPlatform.start();
Recuperación de cuentas de usuario conocidas para la aplicación
Es importante asegurarse de que la lista de cuentas de usuario conocidas para la aplicación se sincronice correctamente con ConnectedDevicesAccountManager.
Use ConnectedDevicesAccountManager.addAccountAsync para agregar una nueva cuenta de usuario.
public synchronized AsyncOperation<ConnectedDevicesAddAccountResult> addAccountToAccountManagerAsync(ConnectedDevicesAccount account) {
return ConnectedDevicesPlatform sPlatform.getAccountManager().addAccountAsync(account);
}
Para quitar una cuenta no válida, puede usar ConnectedDevicesAccountManager.removeAccountAsync
public synchronized AsyncOperation<ConnectedDevicesAddAccountResult> removeAccountToAccountManagerAsync(ConnectedDevicesAccount account) {
return ConnectedDevicesPlatform sPlatform.getAccountManager().removeAccountAsync(account);
}
Detección de dispositivos y aplicaciones remotos
Una instancia de RemoteSystemWatcher controlará la funcionalidad principal de esta sección. Decláralo en la clase que está destinada a descubrir sistemas remotos.
private RemoteSystemWatcher mWatcher = null;
Antes de crear un monitor e iniciar la detección de dispositivos, es posible que quiera agregar filtros de detección para determinar qué tipos de dispositivos tendrá como destino la aplicación. Estos se pueden determinar mediante la entrada del usuario o codificadas de forma rígida en la aplicación, en función de su caso de uso.
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));
// ...
En este momento, la aplicación puede inicializar el objeto watcher que determina cómo analizará la aplicación e interactuará con los dispositivos detectados.
// ...
// Create a RemoteSystemWatcher
mWatcher = new RemoteSystemWatcher(filters.toArray(new RemoteSystemFilter[filters.size()]));
}
// ...
Se recomienda que la aplicación mantenga un conjunto de dispositivos detectados (representados por instancias de RemoteSystem ) y muestre información sobre los dispositivos disponibles y sus aplicaciones (como el nombre para mostrar y el tipo de dispositivo) en la interfaz de usuario.
Las siguientes plantillas de clase se pueden usar como escuchas de eventos para la instancia del observador.
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
}
}
Una vez que se invoque mWatcher.start
, comenzará a observar la actividad remota del sistema y generará eventos cuando los dispositivos sean detectados, actualizados o eliminados del conjunto de dispositivos detectados. Se escaneará continuamente en segundo plano, por lo que se recomienda detener el observador cuando ya no lo necesite para evitar la comunicación de red innecesaria y el consumo de batería.
// 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();
}
Caso de uso de ejemplo: implementación del inicio remoto y servicios de aplicaciones remotos
En este punto del código, debe tener una lista de trabajo de objetos RemoteSystem que hacen referencia a los dispositivos disponibles. Lo que hace con estos dispositivos dependerá de la función de la aplicación. Los principales tipos de interacción son el inicio remoto y los servicios de aplicaciones remotos. Se explican en las secciones siguientes.
A) Inicio remoto
En el código siguiente se muestra cómo seleccionar uno de estos dispositivos (lo ideal es hacerlo a través de un control de interfaz de usuario) y, a continuación, usar RemoteLauncher para iniciar una aplicación en él pasando un URI compatible con la aplicación.
Es importante tener en cuenta que un inicio remoto puede tener como destino un dispositivo remoto (en cuyo caso el dispositivo host iniciará el URI dado con su aplicación predeterminada para ese esquema de URI) o una aplicación remota específica en ese dispositivo.
Como se mostró en la sección anterior, la detección se produce primero en el nivel de dispositivo (un remoteSystem representa un dispositivo), pero puede llamar al getApplications
método en una instancia de RemoteSystem para obtener una matriz de objetos RemoteSystemApp , que representan aplicaciones en el dispositivo remoto que se han registrado para usar la plataforma de dispositivos conectados (al igual que registró su propia aplicación en los pasos preliminares anteriores).
RemoteSystem y RemoteSystemApp se pueden usar para construir un RemoteSystemConnectionRequest, que es lo que se necesita para iniciar 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);
// ...
Utiliza el AsyncOperation devuelto para gestionar el resultado del intento de inicio.
// ...
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"
}
}
}
});
}
Dependiendo del URI que se envíe, puede iniciar una aplicación en un estado o configuración específico en un dispositivo remoto. Esto permite continuar con una tarea de usuario, como ver una película, en un dispositivo diferente sin interrupción.
Según el caso de uso, es posible que tenga que cubrir los casos en los que ninguna aplicación del sistema de destino pueda controlar el URI o varias aplicaciones pueden controlarlo. La clase RemoteLauncher y la clase RemoteLauncherOptions describen cómo hacerlo.
B) Servicios de aplicaciones remotos
La aplicación Android puede usar el Portal de dispositivos conectados para interactuar con los servicios de aplicaciones en otros dispositivos. Esto proporciona muchas maneras de comunicarse con otros dispositivos, todo ello sin necesidad de llevar una aplicación al primer plano del dispositivo host.
Configuración del servicio de aplicaciones en el dispositivo de destino
En esta guía se usará la aplicación de prueba romana para Windows como servicio de aplicaciones de destino. Por lo tanto, el código siguiente hará que una aplicación Android busque ese servicio de aplicaciones específico en el sistema remoto determinado. Si quiere probar este escenario, descargue la aplicación De prueba romana en un dispositivo Windows y asegúrese de que ha iniciado sesión con la misma MSA que usó en los pasos preliminares anteriores.
Para obtener instrucciones sobre cómo escribir su propio servicio de aplicaciones para UWP, consulta Crear y consumir un servicio de aplicaciones (UWP). Tendrá que realizar algunos cambios para que el servicio sea compatible con dispositivos conectados. Consulta la guía de UWP para servicios de aplicaciones remotas para obtener instrucciones sobre cómo hacerlo.
Apertura de una conexión de App Service en el dispositivo cliente
La aplicación Android debe adquirir una referencia a un dispositivo o aplicación remotos. Al igual que la sección de inicio, este escenario requiere el uso de remoteSystemConnectionRequest, que se puede construir a partir de un RemoteSystem o remoteSystemApp que representa una aplicación disponible en el sistema.
// 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;
Además, la aplicación tendrá que identificar su servicio de aplicaciones de destino mediante dos cadenas: el nombre del servicio de aplicaciones y el identificador del paquete. Estos se encuentran en el código fuente del proveedor de servicios de aplicaciones (consulta Crear y consumir un servicio de aplicaciones (UWP) para obtener más información sobre cómo obtener estas cadenas para los servicios de aplicaciones de Windows). Juntas, estas cadenas construyen appServiceDescription, que se introduce en una instancia de 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;
}
});
}
Creación de un mensaje para enviar al servicio de aplicaciones
Declare una variable para almacenar el mensaje que se va a enviar. En Android, los mensajes que envíe a servicios de aplicaciones remotos serán del tipo de mapa .
private Map<String, Object> mMessagePayload = null;
Nota:
Cuando la aplicación se comunica con los servicios de aplicaciones en otras plataformas, la plataforma de dispositivos conectados convierte el mapa en la construcción coincidente en la plataforma receptora. Por ejemplo, un mapa enviado desde esta aplicación a un servicio de aplicaciones de Windows se traduce en un objeto ValueSet (de .NET Framework), que después el servicio de aplicaciones puede interpretar. La información pasada en la otra dirección se somete a la traducción inversa.
El método siguiente compone un mensaje que puede interpretar el servicio de aplicaciones de Roman Test App para 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);
}
Importante
Los mapas que se pasan entre aplicaciones y servicios en el escenario de servicios de aplicaciones remotos deben cumplir el siguiente formato: Las claves deben ser Cadenas, y los valores pueden ser: Cadenas, tipos numéricos encapsulados (enteros o puntos flotantes), booleanos encapsulados, android.graphics.Point, android.graphics.Rect, java.util.Date, java.util.UUID, arreglos homogéneos de cualquiera de estos tipos, u otros objetos Map que cumplan esta especificación.
Envío de un mensaje al servicio de aplicaciones
Una vez establecida la conexión de App Service y se crea el mensaje, enviarlo al servicio de aplicaciones es sencillo y se puede realizar desde cualquier lugar de la aplicación que tenga una referencia a la instancia de conexión de App Service y el mensaje.
// 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.
}
El método siguiente recibirá e interpretará la respuesta del Servicio de aplicaciones.
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(); }
}
}
En el caso de la aplicación romana, la respuesta contiene la fecha en que se creó, por lo que en este caso de uso muy sencillo, podemos comparar las fechas para obtener el tiempo total de tránsito de la respuesta del mensaje.
Esto concluye un intercambio de mensajes único con un servicio de aplicaciones remoto.
Finalizar la comunicación del App Service
Cuando la aplicación termine de interactuar con el servicio de aplicaciones del dispositivo de destino, cierre la conexión entre los dos dispositivos.
// Close the given AppService connection
private void closeAppServiceConnection()
{
connection.close();
}