Connettere i dispositivi tramite sessioni remoteConnect devices through remote sessions

La funzionalità sessioni remote consente a un'app di connettersi ad altri dispositivi tramite una sessione, per la messaggistica esplicita dell'app o per lo scambio negoziato di dati gestiti dal sistema, ad esempio SpatialEntityStore per la condivisione olografica tra i dispositivi Windows olografici.The Remote Sessions feature allows an app to connect to other devices through a session, either for explicit app messaging or for brokered exchange of system-managed data, such as the SpatialEntityStore for holographic sharing between Windows Holographic devices.

Le sessioni remote possono essere create da qualsiasi dispositivo Windows e qualsiasi dispositivo Windows può richiedere l'aggiunta (anche se le sessioni possono avere visibilità di solo invito), inclusi i dispositivi connessi da altri utenti.Remote sessions can be created by any Windows device, and any Windows device can request to join (although sessions can have invite-only visibility), including devices signed in by other users. Questa guida fornisce il codice di esempio di base per tutti gli scenari principali che usano le sessioni remote.This guide provides basic sample code for all of the major scenarios that make use of remote sessions. Questo codice può essere incorporato in un progetto di app esistente e modificato in base alle esigenze.This code can be incorporated into an existing app project and modified as necessary. Per un'implementazione end-to-end, vedere l' app di esempio quiz game.For an end-to-end implementation, see the Quiz Game sample app).

Installazione preliminarePreliminary setup

Aggiungere la funzionalità RemoteSystemAdd the remoteSystem capability

Se vuoi che la tua app avvii un'app su un dispositivo remoto, devi aggiungere la funzionalità remoteSystem al manifesto del pacchetto dell'app.In order for your app to launch an app on a remote device, you must add the remoteSystem capability to your app package manifest. È possibile usare la finestra di progettazione del manifesto del pacchetto per aggiungerla selezionando sistema remoto nella scheda funzionalità oppure è possibile aggiungere manualmente la riga seguente al file Package. appxmanifest del progetto.You can use the package manifest designer to add it by selecting Remote System on the Capabilities tab, or you can manually add the following line to your project's Package.appxmanifest file.

<Capabilities>
   <uap3:Capability Name="remoteSystem"/>
</Capabilities>

Abilitare l'individuazione tra utenti sul dispositivoEnable cross-user discovering on the device

Le sessioni remote sono rivolte alla connessione di più utenti diversi, quindi i dispositivi necessari devono disporre di una condivisione tra utenti abilitata.Remote Sessions is geared toward connecting multiple different users, so the devices involved will need to have Cross-User Sharing enabled. Si tratta di un'impostazione di sistema su cui è possibile eseguire query con un metodo statico nella classe RemoteSystem :This is a system setting that can be queried with a static method in the RemoteSystem class:

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

Per modificare questa impostazione, l'utente deve aprire l'app Impostazioni .To change this setting, the user must open the Settings app. Nel System > menu condivisione delleesperienze condivisedi sistema > tra i dispositivi è presente una casella di riepilogo a discesa in cui l'utente può specificare i dispositivi con cui il sistema può condividere.In the System > Shared experiences > Share across devices menu, there is a drop-down box where the user can specify which devices their system can share with.

pagina Impostazioni esperienze condivise

Includi gli spazi dei nomi necessariInclude the necessary namespaces

Per utilizzare tutti i frammenti di codice in questa guida, è necessario disporre delle using istruzioni seguenti nei file di classe.In order to use all of the code snippets in this guide, you will need the following using statements in your class file(s).

using System.Runtime.Serialization.Json;
using Windows.Foundation.Collections;
using Windows.System.RemoteSystems;

Creare una sessione remotaCreate a remote session

Per creare un'istanza di sessione remota, è necessario iniziare con un oggetto RemoteSystemSessionController .To create a remote session instance, you must start with a RemoteSystemSessionController object. Usare il Framework seguente per creare una nuova sessione e gestire le richieste di join da altri dispositivi.Use the following framework to create a new session and handle join requests from other devices.

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
    }
}

Eseguire solo l'invito di una sessione remotaMake a remote session invite-only

Se si vuole impedire che la sessione remota sia individuabile pubblicamente, è possibile renderla solo di invito.If you wish to keep your remote session from being publicly discoverable, you can make it invite-only. Solo i dispositivi che ricevono un invito saranno in grado di inviare richieste di join.Only the devices that receive an invitation will be able to send join requests.

La procedura è essenzialmente identica a quella descritta in precedenza, ma quando si costruisce l'istanza di RemoteSystemSessionController , viene passato un oggetto RemoteSystemSessionOptions configurato.The procedure is mostly the same as above, but when constructing the RemoteSystemSessionController instance, you will pass in a configured RemoteSystemSessionOptions object.

// 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);

//...

Per inviare un invito, è necessario disporre di un riferimento al sistema remoto ricevente (acquisito tramite l'individuazione normale del sistema remoto).To send an invitation, you must have a reference to the receiving remote system (acquired through normal remote system discovery). È sufficiente passare questo riferimento al metodo SendInvitationAsync dell'oggetto Session.Simply pass this reference into the session object's SendInvitationAsync method. Tutti i partecipanti a una sessione hanno un riferimento alla sessione remota (vedere la sezione successiva), quindi qualsiasi partecipante può inviare un invito.All of the participants in a session have a reference to the remote session (see next section), so any participant can send an invitation.

// "currentSession" is a reference to a RemoteSystemSession.
// "guestSystem" is a previously discovered RemoteSystem instance
currentSession.SendInvitationAsync(guestSystem); 

Individuare e partecipare a una sessione remotaDiscover and join a remote session

Il processo di individuazione delle sessioni remote viene gestito dalla classe RemoteSystemSessionWatcher ed è simile all'individuazione dei singoli sistemi remoti.The process of discovering remote sessions is handled by the RemoteSystemSessionWatcher class and is similar to discovering individual remote systems.

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();
}

Quando viene ottenuta, un'istanza di RemoteSystemSessionInfo può essere usata per emettere una richiesta di join al dispositivo che controlla la sessione corrispondente.When a RemoteSystemSessionInfo instance is obtained, it can be used to issue a join request to the device that controls the corresponding session. Una richiesta di join accettata restituirà in modo asincrono un oggetto RemoteSystemSessionJoinResult che contiene un riferimento alla sessione unita in join.An accepted join request will asynchronously return a RemoteSystemSessionJoinResult object that contains a reference to the joined session.

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 può essere unito in join a più sessioni nello stesso momento.A device can be joined to multiple sessions at the same time. Per questo motivo, potrebbe essere utile separare la funzionalità di join dall'interazione effettiva con ogni sessione.For this reason, it may be desirable to separate the joining functionality from the actual interaction with each session. Fino a quando un riferimento all'istanza di RemoteSystemSession viene mantenuto nell'app, è possibile tentare la comunicazione su tale sessione.As long as a reference to the RemoteSystemSession instance is maintained in the app, communication can be attempted over that session.

Condividere messaggi e dati tramite una sessione remotaShare messages and data through a remote session

Ricevere messaggiReceive messages

È possibile scambiare messaggi e dati con altri dispositivi del partecipante nella sessione usando un'istanza di RemoteSystemSessionMessageChannel , che rappresenta un singolo canale di comunicazione a livello di sessione.You can exchange messages and data with other participant devices in the session by using a RemoteSystemSessionMessageChannel instance, which represents a single session-wide communication channel. Non appena viene inizializzato, inizia ad ascoltare i messaggi in arrivo.As soon as it's initialized, it begins listening for incoming messages.

Nota

I messaggi devono essere serializzati e deserializzati da matrici di byte durante l'invio e la ricezione.Messages must be serialized and deserialized from byte arrays upon sending and receiving. Questa funzionalità è inclusa negli esempi seguenti, ma può essere implementata separatamente per migliorare la modularità del codice.This functionality is included in the following examples, but it can be implemented separately for better code modularity. Vedere l' app di esempio) per un esempio.See the sample app) for an example of this.

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
        //...
    };
}

Inviare messaggiSend messages

Quando il canale viene stabilito, l'invio di un messaggio a tutti i partecipanti della sessione è semplice.When the channel is established, sending a message to all of the session participants is straightforward.

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);
}

Per inviare un messaggio solo a determinati partecipanti, è necessario innanzitutto avviare un processo di individuazione per acquisire i riferimenti ai sistemi remoti che partecipano alla sessione.In order to send a message to only certain participant(s), you must first initiate a discovery process to acquire references to the remote systems participating in the session. Questa operazione è simile al processo di individuazione di sistemi remoti all'esterno di una sessione.This is similar to the process of discovering remote systems outside of a session. Usare un'istanza di RemoteSystemSessionParticipantWatcher per trovare i dispositivi del partecipante di una sessione.Use a RemoteSystemSessionParticipantWatcher instance to find a session's participant devices.

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();
}

Quando si ottiene un elenco di riferimenti ai partecipanti della sessione, è possibile inviare un messaggio a qualsiasi set di essi.When a list of references to session participants is obtained you can send a message to any set of them.

Per inviare un messaggio a un singolo partecipante (idealmente selezionato sullo schermo dall'utente), è sufficiente passare il riferimento in un metodo come il seguente.To send a message to a single participant (ideally selected on-screen by the user), simply pass the reference into a method like the following.

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);
}

Per inviare un messaggio a più partecipanti (idealmente selezionati dall'utente), aggiungerli a un oggetto elenco e passare l'elenco a un metodo come il seguente.To send a message to multiple participants (ideally selected on-screen by the user), add them to a list object and pass the list into a method like the following.

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);   
}