リモート セッションでデバイスを接続するConnect devices through remote sessions

リモート セッション機能を使用すると、セッションを介してアプリを他のデバイスに接続できます。これは明示的なアプリ メッセージングや、ブローカーによるシステム管理データ (Windows Holographic デバイス間のホログラフィック共有に使用する SpatialEntityStore など) の交換を目的としています。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.

リモート セッションはどの Windows デバイスでも作成でき、(他のユーザーがサインインしているデバイスを含めて) どの Windows デバイスでも参加を要求できます (セッションによっては招待のみの可視性が適用されることがあります)。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. このガイドには、リモート セッションを利用するあらゆる主要なシナリオの基本的なサンプル コードを記載しています。This guide provides basic sample code for all of the major scenarios that make use of remote sessions. このコードは、既存のアプリ プロジェクトに組み込み、必要に応じて変更できます。This code can be incorporated into an existing app project and modified as necessary. エンド ツー エンド実装については、クイズ ゲームのサンプル アプリをご覧ください。For an end-to-end implementation, see the Quiz Game sample app).

準備段階のセットアップPreliminary setup

remoteSystem 機能を追加するAdd the remoteSystem capability

アプリでリモート デバイスのアプリを起動するには、remoteSystem 機能をアプリ パッケージ マニフェストに追加する必要があります。In order for your app to launch an app on a remote device, you must add the remoteSystem capability to your app package manifest. これには、マニフェスト デザイナーで [機能] タブの [リモート システム] を選んで追加するか、プロジェクトの Package.appxmanifest ファイルに以下のコードを手動で追加します。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>

デバイスでユーザー間の検出を有効にするEnable cross-user discovering on the device

リモート セッションには、複数の異なるユーザーどうしの接続を目的とした機能が備えられているため、各デバイスでユーザー間の共有を有効にしておく必要があります。Remote Sessions is geared toward connecting multiple different users, so the devices involved will need to have Cross-User Sharing enabled. このシステム設定は、次のように 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".
}

この設定を変更するには、ユーザーが設定アプリを開く必要があります。To change this setting, the user must open the Settings app. [システム] > [共有エクスペリエンス] > [デバイス間で共有します] メニューの順に移動すると、システムで共有可能なデバイスをユーザーが指定できるドロップダウン ボックスがあります。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.

[共有エクスペリエンス] 設定ページ

必要な名前空間を含めるInclude the necessary namespaces

このガイドに含まれているコード スニペットを使用するには、クラス ファイルに以下の using ステートメントを記述する必要があります。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;

リモート セッション作成するCreate a remote session

リモート セッション インスタンスを作成するには、 RemoteSystemSessionController オブジェクトから開始する必要があります。To create a remote session instance, you must start with a RemoteSystemSessionController object. 新しいセッションを作成し、他のデバイスからの参加要求を処理するには、以下のフレームワークを使用します。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
    }
}

リモート セッションを招待のみに設定するMake a remote session invite-only

リモート セッションを一般に公開しない場合は、招待のみに設定することができます。If you wish to keep your remote session from being publicly discoverable, you can make it invite-only. 招待を受け取ったデバイスのみが参加要求を送信できます。Only the devices that receive an invitation will be able to send join requests.

手順は上記とほとんど同じですが、 RemoteSystemSessionController インスタンスを作成する際には、構成済みの RemoteSystemSessionOptions オブジェクトを渡します。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);

//...

招待を送信するには、受信側のリモート システムへの参照 (通常のリモート システム検出を使用して取得) が必要です。To send an invitation, you must have a reference to the receiving remote system (acquired through normal remote system discovery). この参照をセッション オブジェクトの SendInvitationAsync メソッドに渡します。Simply pass this reference into the session object's SendInvitationAsync method. すべてのセッション参加者がリモート セッションへの参照にアクセスできるため (次のセクションをご覧ください)、どの参加者も招待を送信することができます。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); 

リモート セッションを検出して参加するDiscover and join a remote session

リモート セッションを検出するプロセスは、個々のリモート システムの検出に似ており、 RemoteSystemSessionWatcher クラスによって処理されます。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();
}

取得した RemoteSystemSessionInfo インスタンスは、対応するセッションを制御するデバイスへの参加要求を発行するために使用します。When a RemoteSystemSessionInfo instance is obtained, it can be used to issue a join request to the device that controls the corresponding session. 参加要求が受け入れられると、参加するセッションへの参照が含まれた RemoteSystemSessionJoinResult オブジェクトが返されます。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.
    }
}

同じデバイスが同時に複数のセッションに参加することもできます。A device can be joined to multiple sessions at the same time. このため、参加のための機能は、各セッションと実際のやり取りから分離する方が望ましい場合があります。For this reason, it may be desirable to separate the joining functionality from the actual interaction with each session. アプリ内で RemoteSystemSession インスタンスへの参照が維持されている限り、そのセッションでの通信を試行できます。As long as a reference to the RemoteSystemSession instance is maintained in the app, communication can be attempted over that session.

リモート セッションを介してメッセージとデータを共有するShare messages and data through a remote session

メッセージを受信するReceive messages

セッション内では、他の参加デバイスとメッセージやデータを交換できます。これには、セッション全体の単一通信チャネルを表す RemoteSystemSessionMessageChannel インスタンスを使用します。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. このインスタンスは、初期化されるとすぐに受信メッセージのリッスンを開始します。As soon as it's initialized, it begins listening for incoming messages.

注意

メッセージの送受信時には、バイト配列からのシリアル化および逆シリアル化を行う必要があります。Messages must be serialized and deserialized from byte arrays upon sending and receiving. 次の例にはこの機能が含まれていますが、コードのモジュール性を高めるために、別途実装することもできます。This functionality is included in the following examples, but it can be implemented separately for better code modularity. その例については、サンプル アプリをご覧ください。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
        //...
    };
}

メッセージを送信するSend messages

チャネルが確立されると、すべてのセッション参加者へのメッセージ送信は簡単です。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);
}

特定の参加者だけにメッセージを送信するには、まずセッションに参加しているリモート システムへの参照を取得する検出プロセスを開始する必要があります。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. これは、セッションの外部でリモート システムを検出するプロセスと似ています。This is similar to the process of discovering remote systems outside of a session. セッションに参加しているデバイスを検出するには、 RemoteSystemSessionParticipantWatcher インスタンスを使用します。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();
}

セッション参加者への参照の一覧を取得した場合は、参加者のすべてまたは一部にメッセージを送信できます。When a list of references to session participants is obtained you can send a message to any set of them.

単一参加者 (画面でのユーザーによる選択が望ましい) のみにメッセージを送信するには、次のようなメソッドに参照を渡します。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);
}

複数の参加者 (画面でのユーザーによる選択が望ましい) にメッセージを送信するには、対象をリスト オブジェクトに追加し、そのリストを次のようなメソッドに渡します。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);   
}