我正在尝试通过使设备可被发现以及从不同的远程系统/设备加入远程会话,将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;我的清单中的部分与测验应用程序相同。上面列出的基本代码或多或少来自上面提供的链接中的官方示例。所以他们应该工作,但我不知道我做错了什么。
我尽量提供尽可能多的信息,但请不要犹豫,询问您是否需要更多信息。
非常感谢任何协助/指导。
答案 0 :(得分:1)
对于有类似问题且想要答案的人:
我试图在同一个UWP应用程序中托管远程会话并发现其他会话,以促进App-to-App消息传递。对于主机 - 客户端会话,测验应用程序示例工作正常(请参阅我的问题中提供的链接)。但是,对于多对多会话托管,发现和向单个参与者发送消息,很难实现(至少对我来说)。换句话说,我的应用程序主持远程会话并加入其他人。
这是我对流程的理解以及我如何解决它:
当设备创建消息通道时,它还会将自己添加为参与者。因此,我保存对此(主持人)参与者的引用(在步骤4中),然后在需要时将消息发送给它。
问题的关键是保存对远程会话消息通道及其特定参与者的引用 - 然后将消息发送到该通道。我发现,一开始理解起来有点复杂。文档可用,但遗憾的是不是我想要的场景。尽管如此,我最终到了那里。对不起,不能发布代码,因为它现在非常大,但我希望感兴趣的读者会发现上面的工作逻辑是有用的。