无法让RemoteSystem在UWP App中运行

时间:2018-04-06 09:34:19

标签: c# uwp

我正在尝试通过使设备可被发现以及从不同的远程系统/设备加入远程会话,将Project Rome功能实现到我的UWP应用程序中。

项目罗马概述可以在这里找到:Project Rome

我想在广义上实现的目标在这里描述:Connect devices through remote sessions

我已按照代码下载了GitHub上提供的Quiz示例应用程序:Remote System session - Quiz game App

我的代码如下。我使用简化代码来使基本功能正常工作:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Windows.System.RemoteSystems;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace App3
{
    public sealed partial class MainPage : Page, INotifyPropertyChanged
    {
        private RemoteSystemSessionWatcher m_sessionWatcher;
        private RemoteSystemSessionController m_sessionController;

        private string _statusText;
        public string StatusText
        {
            get => _statusText;
            set => SetProperty(ref _statusText, value);
        }

        public MainPage()
        {
            this.InitializeComponent();

            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".
                StatusText = $"The system is not authorized to connect to cross-user devices!";
            }
            else
            {
                StatusText = $"Initialisation OK!";
            }
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            if (m_sessionController != null)
            {
                m_sessionController.JoinRequested -= RemoteSystemSessionController_JoinRequested;
                m_sessionController = null;
            }

            if (m_sessionWatcher != null)
            {
                m_sessionWatcher.Stop();
                m_sessionWatcher.Added -= RemoteSystemSessionWatcher_RemoteSessionAdded;
                m_sessionWatcher.Removed -= RemoteSystemSessionWatcher_RemoteSessionRemoved;
                m_sessionWatcher = null;
            }
        }

        private async void CreateSession_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            StatusText = "";

            if (string.IsNullOrWhiteSpace(SessionNameBox.Text))
            {
                StatusText = $"Provide a Session name first!";
                return;
            }

            await StartNewSharedExperience(SessionNameBox.Text);
        }

        private async void JoinSession_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            SessionNameBox.Text = "";
            await DiscoverSessions();
        }

        public async Task StartNewSharedExperience(string sessionName)
        {
            RemoteSystemAccessStatus accessStatus = await RemoteSystem.RequestAccessAsync();

            // Checking that remote system access is allowed - ensure capability in the project manifest is set
            if (accessStatus != RemoteSystemAccessStatus.Allowed)
            {
                StatusText = $"Create Session: Access is denied, ensure the 'bluetooth' and 'remoteSystem' capabilities are set.";
                return;
            }

            m_sessionController = new RemoteSystemSessionController(sessionName);

            // register the following code to handle the JoinRequested event
            m_sessionController.JoinRequested += RemoteSystemSessionController_JoinRequested;

            // create and start the session
            RemoteSystemSessionCreationResult createResult = await m_sessionController.CreateSessionAsync();

            // handle the creation result
            if (createResult.Status == RemoteSystemSessionCreationStatus.Success)
            {
                // creation was successful
                RemoteSystemSession currentSession = createResult.Session;

                // optionally subscribe to the disconnection event
                currentSession.Disconnected += async (sender, args) => {
                    // update the UI, using args.Reason
                    // ...
                    StatusText = $"Session disconnected. Reason: {args.Reason.ToString()}";
                };

                // Use session ...
                StatusText = $"Session '{sessionName}' created successfully.";
            }
            else if (createResult.Status == RemoteSystemSessionCreationStatus.SessionLimitsExceeded)
            {
                // creation failed. Optionally update UI to indicate that there are too many sessions in progress
                StatusText = $"Too many Sessions!";
            }
            else
            {
                // creation failed for an unknown reason. Optionally update UI
                StatusText = $"Creation failed with unknown reason!";
            }
        }

        // Discovery of existing sessions
        public async Task DiscoverSessions()
        {
            try
            {
                RemoteSystemAccessStatus status = await RemoteSystem.RequestAccessAsync();

                // Checking that remote system access is allowed - ensure capability in the project manifest is set
                if (status != RemoteSystemAccessStatus.Allowed)
                {
                    StatusText = $"Discover Session: Access is denied, ensure the 'bluetooth' and 'remoteSystem' capabilities are set.";
                    return;
                }

                //  Create watcher to observe for added, updated, or removed sessions
                m_sessionWatcher = RemoteSystemSession.CreateWatcher();
                m_sessionWatcher.Added += RemoteSystemSessionWatcher_RemoteSessionAdded;
                m_sessionWatcher.Removed += RemoteSystemSessionWatcher_RemoteSessionRemoved;
                m_sessionWatcher.Start();
                StatusText = $"Session discovery started.";
            }
            catch (Win32Exception ex)
            {
                StatusText = $"Session discovery failed. Exception occurred: {ex.Message}";
            }
        }

        private void RemoteSystemSessionController_JoinRequested(RemoteSystemSessionController sender, RemoteSystemSessionJoinRequestedEventArgs args)
        {
            // Get the deferral
            var deferral = args.GetDeferral();

            // display the participant (args.JoinRequest.Participant) on UI, giving the
            // user an opportunity to respond
            // ...
            StatusText = $"Session join requested by: {args.JoinRequest.Participant.RemoteSystem.DisplayName}";

            // If the user chooses "accept", accept this remote system as a participant
            args.JoinRequest.Accept();
            deferral.Complete();
        }

        private void RemoteSystemSessionWatcher_RemoteSessionAdded(RemoteSystemSessionWatcher sender, RemoteSystemSessionAddedEventArgs args)
        {
            StatusText = $"Discovered Session {args.SessionInfo.DisplayName}:{args.SessionInfo.ControllerDisplayName}.";
        }

        private void RemoteSystemSessionWatcher_RemoteSessionRemoved(RemoteSystemSessionWatcher sender, RemoteSystemSessionRemovedEventArgs args)
        {
            StatusText = $"Session {args.SessionInfo.DisplayName}:{args.SessionInfo.ControllerDisplayName} was ended by host.";
        }

        public bool SetProperty<T>(ref T field, T value, [CallerMemberName]string propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(field, value))
            {
                return false;
            }

            field = value;
            OnPropertyChanged(propertyName);

            return true;
        }

        public void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

我没有更改App.xml.cs文件。只有一个(主)页面。

我的XAML如下:

    <Page
    x:Class="App3.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App3"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,100,0,0">
            <TextBlock Text="Status:" FontSize="18" Foreground="Black" Margin="20,0,0,0"/>
            <TextBlock x:Name="StatusTextUI" FontSize="16" Foreground="Black" Text="{x:Bind StatusText, Mode=OneWay}" Margin="10,0,0,0"
                       VerticalAlignment="Center"/>
        </StackPanel>

        <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,40,0,0">
            <TextBlock Text="Session Name:" FontSize="18" Foreground="Black" HorizontalAlignment="Left" Margin="20,0,0,0" />
            <TextBox x:Name="SessionNameBox" Width="740" Margin="10,0,0,0"/>
            <Button x:Name="CreateSessionButton" HorizontalAlignment="Center" Content="Create Session" Margin="20,0,0,0"
                    Click="CreateSession_Click" />
        </StackPanel>

        <StackPanel Grid.Row="2" Orientation="Horizontal" Margin="0,40,0,0">
            <TextBlock Text="Session Discovered:" FontSize="18" Foreground="Black" HorizontalAlignment="Left" Margin="20,0,0,0" />
            <TextBlock x:Name="SessionFound" Width="700" Margin="10,0,0,0"/>
            <Button x:Name="JoinSessionButton" HorizontalAlignment="Center" Content="Join Session" Margin="20,0,0,0"
                    Click="JoinSession_Click"/>
        </StackPanel>
    </Grid>
</Page>

该应用程序正在使用最新的库,请参阅下面的参考资料截图:

Visual Studio 2017 NuGet Package Manager details

我的清单代码是:

    <?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" IgnorableNamespaces="uap mp uap3">
  <Identity Name="7b15365b-4ve6-4c19-a0c6-0b47g8733b52" Publisher="CN=ANOtherCompany" Version="1.0.0.0" />
  <mp:PhoneIdentity PhoneProductId="7b15365b-4ve6-4c19-a0c6-0b47g8733b52" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
  <Properties>
    <DisplayName>App3</DisplayName>
    <PublisherDisplayName>ANOtherCompany</PublisherDisplayName>
    <Logo>Assets\StoreLogo.png</Logo>
  </Properties>
  <Dependencies>
    <TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.16299.15" MaxVersionTested="10.0.16299.15" />
  </Dependencies>
  <Resources>
    <Resource Language="x-generate" />
  </Resources>
  <Applications>
    <Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="App3.App">
      <uap:VisualElements DisplayName="App3" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="App3" BackgroundColor="transparent">
        <uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png">
        </uap:DefaultTile>
        <uap:SplashScreen Image="Assets\SplashScreen.png" />
      </uap:VisualElements>
    </Application>
  </Applications>
  <Capabilities>
    <Capability Name="internetClientServer" />
    <Capability Name="internetClient" />
    <Capability Name="privateNetworkClientServer" />
    <uap3:Capability Name="remoteSystem" />
    <DeviceCapability Name="bluetooth" />
  </Capabilities>
</Package>

我已在2台不同的Windows 10 Surface设备上部署了我的应用程序,但我无法发现在另一台设备上创建的会话。测验应用程序在两个设备上都按预期运行。但我想要更简单的东西。会话发现时的断点在测验应用程序中被点击,但在我的应用程序中没有。 &#39;功能&#39;我的清单中的部分与测验应用程序相同。上面列出的基本代码或多或少来自上面提供的链接中的官方示例。所以他们应该工作,但我不知道我做错了什么。

我尽量提供尽可能多的信息,但请不要犹豫,询问您是否需要更多信息。

非常感谢任何协助/指导。

1 个答案:

答案 0 :(得分:1)

对于有类似问题且想要答案的人:

我试图在同一个UWP应用程序中托管远程会话并发现其他会话,以促进App-to-App消息传递。对于主机 - 客户端会话,测验应用程序示例工作正常(请参阅我的问题中提供的链接)。但是,对于多对多会话托管,发现和向单个参与者发送消息,很难实现(至少对我来说)。换句话说,我的应用程序主持远程会话并加入其他人。

这是我对流程的理解以及我如何解决它:

  1. 创建远程会话
  2. 发现远程会话
  3. 为其创建消息频道
  4. 观看远程会话参与者(RemoteSystemSessionParticipantWatcher)
  5. 然后将消息发送给相应消息通道上的参与者(在步骤3中创建)。
  6. 当设备创建消息通道时,它还会将自己添加为参与者。因此,我保存对此(主持人)参与者的引用(在步骤4中),然后在需要时将消息发送给它。

    问题的关键是保存对远程会话消息通道及其特定参与者的引用 - 然后将消息发送到该通道。我发现,一开始理解起来有点复杂。文档可用,但遗憾的是不是我想要的场景。尽管如此,我最终到了那里。对不起,不能发布代码,因为它现在非常大,但我希望感兴趣的读者会发现上面的工作逻辑是有用的。