Поделиться через


Подключение устройств с помощью удаленных сеансов

Функция удаленных сеансов позволяет приложению подключаться к другим устройствам через сеанс либо для явного обмена сообщениями приложений, либо для обмена данными, управляемыми системой, например SpatialEntityStore для голографического обмена между устройствами Windows Holographic.

Удаленные сеансы могут создаваться любым устройством Windows, и любое устройство Windows может запрашивать присоединение (хотя сеансы могут иметь видимость только для приглашения), включая устройства, вошедшего в систему другими пользователями. В этом руководстве представлен базовый пример кода для всех основных сценариев, использующих удаленные сеансы. Этот код можно включить в существующий проект приложения и изменить при необходимости. Сведения о комплексной реализации см. в примере приложения "Игра теста").

Предварительная настройка

Добавление возможности remoteSystem

Чтобы приложение запускалось на удаленном устройстве, необходимо добавить remoteSystem возможность в манифест пакета приложения. С помощью конструктора манифеста пакета его можно добавить, выбрав удаленную систему на вкладке "Возможности" или вручную добавьте следующую строку в файл Package.appxmanifest проекта.

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

Включение межпользовательского обнаружения на устройстве

Удаленные сеансы ориентированы на подключение нескольких разных пользователей, поэтому устройствам, участвующим в них, потребуется включить общий доступ между пользователями. Это системный параметр, который можно запрашивать статическим методом в классе 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".
}

Чтобы изменить этот параметр, пользователь должен открыть приложение "Параметры ". В меню "Общий доступ к системе>" между устройствами> есть раскрывающийся список, с которым пользователь может указать устройства, с которыми может предоставляться общий доступ.

Страница параметров общего интерфейса

Включение необходимых пространств имен

Чтобы использовать все фрагменты кода в этом руководстве, вам потребуются следующие using инструкции в файлах класса.

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

Создание удаленного сеанса

Чтобы создать экземпляр удаленного сеанса, необходимо начать с объекта RemoteSystemSessionController. Используйте следующую платформу для создания нового сеанса и обработки запросов на присоединение с других устройств.

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

Создание приглашения на удаленный сеанс только

Если вы хотите, чтобы удаленный сеанс был общедоступным для обнаружения, его можно сделать только приглашенным. Только устройства, получающие приглашение, смогут отправлять запросы на присоединение.

Процедура в основном аналогична приведенной выше, но при создании экземпляра RemoteSystemSessionController вы будете передавать настроенный объект RemoteSystemSessionOptions.

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

//...

Чтобы отправить приглашение, необходимо иметь ссылку на получение удаленной системы (полученную через обычное обнаружение удаленной системы). Просто передайте эту ссылку в метод SendInvitationAsync объекта сеанса. Все участники сеанса имеют ссылку на удаленный сеанс (см. следующий раздел), чтобы любой участник может отправить приглашение.

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

Обнаружение и присоединение удаленного сеанса

Процесс обнаружения удаленных сеансов обрабатывается классом RemoteSystemSessionWatcher и аналогичен обнаружению отдельных удаленных систем.

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

При получении экземпляра RemoteSystemSessionInfo его можно использовать для выдачи запроса на присоединение к устройству, которое управляет соответствующим сеансом. Запрос на присоединение будет асинхронно возвращать объект RemoteSystemSessionJoinResult , содержащий ссылку на присоединенный сеанс.

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

Устройство может быть присоединено к нескольким сеансам одновременно. По этой причине может потребоваться разделить функциональность присоединения от фактического взаимодействия с каждым сеансом. Если ссылка на экземпляр RemoteSystemSession сохраняется в приложении, обмен данными можно выполнить через этот сеанс.

Предоставление общего доступа к сообщениям и данным через удаленный сеанс

Получение сообщений

Вы можете обмениваться сообщениями и данными с другими устройствами-участниками в сеансе с помощью экземпляра RemoteSystemSessionMessageChannel , представляющего единый канал связи на уровне сеанса. Как только он инициализирован, он начинает прослушивать входящие сообщения.

Примечание.

Сообщения должны быть сериализованы и десериализированы из массивов байтов при отправке и получении. Эта функция включена в следующие примеры, но ее можно реализовать отдельно для повышения модульности кода. Пример этого см. в примере приложения.

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

Отправка сообщений

Когда канал установлен, отправка сообщения всем участникам сеанса проста.

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

Чтобы отправить сообщение только определенным участникам, необходимо сначала инициировать процесс обнаружения для получения ссылок на удаленные системы, участвующие в сеансе. Это похоже на процесс обнаружения удаленных систем за пределами сеанса. Используйте экземпляр RemoteSystemSessionParticipantWatcher для поиска устройств участников сеанса.

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

При получении списка ссылок на участников сеанса можно отправить сообщение любому набору.

Чтобы отправить сообщение одному участнику (идеально выбранному на экране пользователю), просто передайте ссылку в метод, как показано ниже.

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

Чтобы отправить сообщение нескольким участникам (идеально выбранным на экране пользователем), добавьте их в объект списка и передайте список в метод, как показано ниже.

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