透過遠端工作階段連接裝置

遠端工作階段功能可讓應用程式透過工作階段連線到其他裝置,無論是用於明確應用程式傳訊,還是系統管理資料的代理交換,例如 Windows Holographic 裝置之間用於全像共用的 SpatialEntityStore

遠端工作階段可由任何 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".
}

若要變更此設定,使用者必須開啟 [設定] 應用程式。 在 [系統>共用體驗>跨裝置共用] 功能表中,有一個下拉式方塊,使用者可以指定其系統可以共用的裝置。

shared experiences settings page

包含必要的命名空間

若要使用本指南中的所有程式碼片段,您需要類別檔案中的下列 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);   
}