Conectar dispositivos mediante sesiones remotas
La característica Sesiones remotas permite a una aplicación conectarse a otros dispositivos a través de una sesión, ya sea para mensajería explícita de aplicaciones o para el intercambio asincrónico de datos administrados por el sistema, como SpatialEntityStore para el uso compartido holográfico entre dispositivos Windows Holographic.
Cualquier dispositivo Windows puede crear sesiones remotas y cualquier dispositivo Windows puede solicitar unirse (aunque las sesiones pueden tener visibilidad de solo invitación), incluidos los dispositivos iniciados por otros usuarios. En esta guía se proporciona código de ejemplo básico para todos los escenarios principales que usan sesiones remotas. Este código se puede incorporar a un proyecto de aplicación existente y modificarlo según sea necesario. Para obtener una implementación de un extremo a otro, consulta la aplicación de ejemplo De juego de cuestionarios).
Configuración preliminar
Adición de la funcionalidad remoteSystem
Para que la aplicación inicie una aplicación en un dispositivo remoto, debes agregar la remoteSystem
funcionalidad al manifiesto del paquete de la aplicación. Puede usar el diseñador de manifiestos de paquete para agregarlo seleccionando Sistema remoto en la pestaña Capacidades, o bien puede agregar manualmente la siguiente línea al archivo Package.appxmanifest del proyecto.
<Capabilities>
<uap3:Capability Name="remoteSystem"/>
</Capabilities>
Habilitación de la detección entre usuarios en el dispositivo
Las sesiones remotas están orientadas a conectar varios usuarios diferentes, por lo que los dispositivos implicados deberán tener habilitado el uso compartido entre usuarios. Se trata de una configuración del sistema que se puede consultar con un método estático en la clase RemoteSystem :
if (!RemoteSystem.IsAuthorizationKindEnabled(RemoteSystemAuthorizationKind.Anonymous)) {
// The system is not authorized to connect to cross-user devices.
// Inform the user that they can discover more devices if they
// update the setting to "Everyone nearby".
}
Para cambiar esta configuración, el usuario debe abrir la aplicación Configuración . En el menú Compartir experiencias>compartidas del sistema>entre dispositivos, hay un cuadro desplegable con el que el usuario puede especificar con qué dispositivos puede compartir su sistema.
Incluir los espacios de nombres necesarios
Para usar todos los fragmentos de código de esta guía, necesitará las siguientes using
instrucciones en los archivos de clase.
using System.Runtime.Serialization.Json;
using Windows.Foundation.Collections;
using Windows.System.RemoteSystems;
Creación de una sesión remota
Para crear una instancia de sesión remota, debe empezar con un objeto RemoteSystemSessionController. Use el marco siguiente para crear una nueva sesión y controlar las solicitudes de unión desde otros dispositivos.
public async void CreateSession() {
// create a session controller
RemoteSystemSessionController manager = new RemoteSystemSessionController("Bob’s Minecraft game");
// register the following code to handle the JoinRequested event
manager.JoinRequested += async (sender, args) => {
// Get the deferral
var deferral = args.GetDeferral();
// display the participant (args.JoinRequest.Participant) on UI, giving the
// user an opportunity to respond
// ...
// If the user chooses "accept", accept this remote system as a participant
args.JoinRequest.Accept();
};
// create and start the session
RemoteSystemSessionCreationResult createResult = await manager.CreateSessionAsync();
// handle the creation result
if (createResult.Status == RemoteSystemSessionCreationStatus.Success) {
// creation was successful, get a reference to the session
RemoteSystemSession currentSession = createResult.Session;
// optionally subscribe to the disconnection event
currentSession.Disconnected += async (sender, args) => {
// update the UI, using args.Reason
//...
};
// Use session (see later section)
//...
} else if (createResult.Status == RemoteSystemSessionCreationStatus.SessionLimitsExceeded) {
// creation failed. Optionally update UI to indicate that there are too many sessions in progress
} else {
// creation failed for an unknown reason. Optionally update UI
}
}
Creación de una invitación de sesión remota
Si desea evitar que la sesión remota se pueda detectar públicamente, puede hacer que sea de solo invitación. Solo los dispositivos que reciben una invitación podrán enviar solicitudes de unión.
El procedimiento es principalmente el mismo que el anterior, pero al construir la instancia RemoteSystemSessionController, pasará un objeto RemoteSystemSessionOptions configurado.
// define the session options with the invite-only designation
RemoteSystemSessionOptions sessionOptions = new RemoteSystemSessionOptions();
sessionOptions.IsInviteOnly = true;
// create the session controller
RemoteSystemSessionController manager = new RemoteSystemSessionController("Bob's Minecraft game", sessionOptions);
//...
Para enviar una invitación, debe tener una referencia al sistema remoto receptor (adquirido a través de la detección normal del sistema remoto). Simplemente pase esta referencia al método SendInvitationAsync del objeto de sesión. Todos los participantes de una sesión tienen una referencia a la sesión remota (consulte la sección siguiente), por lo que cualquier participante puede enviar una invitación.
// "currentSession" is a reference to a RemoteSystemSession.
// "guestSystem" is a previously discovered RemoteSystem instance
currentSession.SendInvitationAsync(guestSystem);
Detección y unión a una sesión remota
El proceso de detección de sesiones remotas se controla mediante la clase RemoteSystemSessionWatcher y es similar a la detección de sistemas remotos individuales.
public void DiscoverSessions() {
// create a watcher for remote system sessions
RemoteSystemSessionWatcher sessionWatcher = RemoteSystemSession.CreateWatcher();
// register a handler for the "added" event
sessionWatcher.Added += async (sender, args) => {
// get a reference to the info about the discovered session
RemoteSystemSessionInfo sessionInfo = args.SessionInfo;
// Optionally update the UI with the sessionInfo.DisplayName and
// sessionInfo.ControllerDisplayName strings.
// Save a reference to this RemoteSystemSessionInfo to use when the
// user selects this session from the UI
//...
};
// Begin watching
sessionWatcher.Start();
}
Cuando se obtiene una instancia remoteSystemSessionInfo , se puede usar para emitir una solicitud de unión al dispositivo que controla la sesión correspondiente. Una solicitud de combinación aceptada devolverá de forma asincrónica un objeto RemoteSystemSessionJoinResult que contiene una referencia a la sesión unida.
public async void JoinSession(RemoteSystemSessionInfo sessionInfo) {
// issue a join request and wait for result.
RemoteSystemSessionJoinResult joinResult = await sessionInfo.JoinAsync();
if (joinResult.Status == RemoteSystemSessionJoinStatus.Success) {
// Join request was approved
// RemoteSystemSession instance "currentSession" was declared at class level.
// Assign the value obtained from the join result.
currentSession = joinResult.Session;
// note connection and register to handle disconnection event
bool isConnected = true;
currentSession.Disconnected += async (sender, args) => {
isConnected = false;
// update the UI with args.Reason value
};
if (isConnected) {
// optionally use the session here (see next section)
//...
}
} else {
// Join was unsuccessful.
// Update the UI, using joinResult.Status value to show cause of failure.
}
}
Un dispositivo se puede unir a varias sesiones al mismo tiempo. Por este motivo, puede ser conveniente separar la funcionalidad de unión de la interacción real con cada sesión. Siempre que se mantenga una referencia a la instancia remoteSystemSession en la aplicación, se puede intentar la comunicación a través de esa sesión.
Compartir mensajes y datos a través de una sesión remota
Recepción de mensajes
Puede intercambiar mensajes y datos con otros dispositivos participantes en la sesión mediante una instancia remoteSystemSessionMessageChannel , que representa un único canal de comunicación para toda la sesión. Tan pronto como se inicializa, comienza a escuchar los mensajes entrantes.
Nota:
Los mensajes se deben serializar y deserializar desde matrices de bytes al enviar y recibir. Esta funcionalidad se incluye en los ejemplos siguientes, pero se puede implementar por separado para mejorar la modularidad del código. Consulte la aplicación de ejemplo) para obtener un ejemplo de esto.
public async void StartReceivingMessages() {
// Initialize. The channel name must be known by all participant devices
// that will communicate over it.
RemoteSystemSessionMessageChannel messageChannel = new RemoteSystemSessionMessageChannel(currentSession,
"Everyone in Bob's Minecraft game",
RemoteSystemSessionMessageChannelReliability.Reliable);
// write the handler for incoming messages on this channel
messageChannel.ValueSetReceived += async (sender, args) => {
// Update UI: a message was received from the participant args.Sender
// Deserialize the message
// (this app must know what key to use and what object type the value is expected to be)
ValueSet receivedMessage = args.Message;
object rawData = receivedMessage["appKey"]);
object value = new ExpectedType(); // this must be whatever type is expected
using (var stream = new MemoryStream((byte[])rawData)) {
value = new DataContractJsonSerializer(value.GetType()).ReadObject(stream);
}
// do something with the "value" object
//...
};
}
Envío de mensajes
Cuando se establece el canal, enviar un mensaje a todos los participantes de la sesión es sencillo.
public async void SendMessageToAllParticipantsAsync(RemoteSystemSessionMessageChannel messageChannel, object value){
// define a ValueSet message to send
ValueSet message = new ValueSet();
// serialize the "value" object to send
using (var stream = new MemoryStream()){
new DataContractJsonSerializer(value.GetType()).WriteObject(stream, value);
byte[] rawData = stream.ToArray();
message["appKey"] = rawData;
}
// Send message to all participants. Ordering is not guaranteed.
await messageChannel.BroadcastValueSetAsync(message);
}
Para enviar un mensaje solo a determinados participantes, primero debe iniciar un proceso de detección para adquirir referencias a los sistemas remotos que participan en la sesión. Esto es similar al proceso de detección de sistemas remotos fuera de una sesión. Use una instancia remoteSystemSessionParticipantWatcher para buscar los dispositivos participantes de una sesión.
public void WatchForParticipants() {
// "currentSession" is a reference to a RemoteSystemSession.
RemoteSystemSessionParticipantWatcher watcher = currentSession.CreateParticipantWatcher();
watcher.Added += (sender, participant) => {
// save a reference to "participant"
// optionally update UI
};
watcher.Removed += (sender, participant) => {
// remove reference to "participant"
// optionally update UI
};
watcher.EnumerationCompleted += (sender, args) => {
// Apps can delay data model render up until this point if they wish.
};
// Begin watching for session participants
watcher.Start();
}
Cuando se obtiene una lista de referencias a los participantes de la sesión, puede enviar un mensaje a cualquier conjunto de ellos.
Para enviar un mensaje a un solo participante (idealmente seleccionado en pantalla por el usuario), simplemente pase la referencia a un método como el siguiente.
public async void SendMessageToParticipantAsync(RemoteSystemSessionMessageChannel messageChannel, RemoteSystemSessionParticipant participant, object value) {
// define a ValueSet message to send
ValueSet message = new ValueSet();
// serialize the "value" object to send
using (var stream = new MemoryStream()){
new DataContractJsonSerializer(value.GetType()).WriteObject(stream, value);
byte[] rawData = stream.ToArray();
message["appKey"] = rawData;
}
// Send message to the participant
await messageChannel.SendValueSetAsync(message,participant);
}
Para enviar un mensaje a varios participantes (idealmente seleccionados en pantalla por el usuario), agréguelos a un objeto de lista y pase la lista a un método como el siguiente.
public async void SendMessageToListAsync(RemoteSystemSessionMessageChannel messageChannel, IReadOnlyList<RemoteSystemSessionParticipant> myTeam, object value){
// define a ValueSet message to send
ValueSet message = new ValueSet();
// serialize the "value" object to send
using (var stream = new MemoryStream()){
new DataContractJsonSerializer(value.GetType()).WriteObject(stream, value);
byte[] rawData = stream.ToArray();
message["appKey"] = rawData;
}
// Send message to specific participants. Ordering is not guaranteed.
await messageChannel.SendValueSetToParticipantsAsync(message, myTeam);
}