Quickstart: Connecting apps using tapping or browsing (XAML)
[This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation]
This topic walks you through the code you need to make your app capable of connecting to another instance of your app running on another device using Proximity.
Proximity is a great way for users on two devices to share your app experience and data. App users can initiate the shared app connection by tapping two devices together or by discovering a peer app within wireless range. When the connection has been established, a socket transfers data between the apps.
To initiate a connection between two instances of the app using a tap gesture, most devices must have NFC. On a PC, this connection channel can be made over Bluetooth, Wi-Fi Direct, or an infrastructure network. On Windows Phone, the connection can be established over Bluetooth or an infrastructure network. Wi-Fi Direct is not supported on Windows Phone. This means that tapping to connect works between a Windows Phone and a PC, but that communication is restricted to using either Bluetooth or an infrastructure network.
Using the Proximity browsing feature, a user on one device can discover your app running on nearby devices without tapping them together. When a user discovers a peer app on a nearby device, the user can request a connection to the peer app. On a PC, browsing uses Wi-Fi Direct. On a Windows Phone, browsing uses Bluetooth. Therefore, an app running on a PC cannot discover a peer app running on a phone by browsing, and vice versa.
The sample in this topic shows you how to use Proximity and the PeerFinder class to create a long-term socket connection with a peer app on another device.
For connections triggered by a tap, if the peer app is not running in the foreground on the target device, then Proximity invites the user to activate the app on the target device. If the peer app is not installed on the target device, then Proximity invites the user on the target device to install the app from the Store. For more details on activating apps using a tap gesture, see "Activating apps using Proximity" in Proximity and tapping.
Objective: Create a connection between two devices by using Proximity tapping or wireless browsing.
Prerequisites
Microsoft Visual Studio Express 2012 for Windows 8
Instructions
1. Create a new project and enable Proximity
- Open Visual Studio Express 2012 for Windows 8 and select New Project from the File menu. In the Visual C# or Visual Basic section, select Windows store and then select Blank app (XAML). Name the app ProximityConnect and click OK.
- Open the Package.appxmanifest file and select the Capabilities tab. Select the Proximity capability to enable Proximity. Close and save the manifest file.
2. Add XAML UI
Open the MainPage.xaml file and replace the default Grid element with the following XAML.
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Margin="20">
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="16" VerticalAlignment="Center" Margin="0,0,10,0">Display Name</TextBlock>
<TextBox x:Name="DisplayNameTextBox" Width="300"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button x:Name="AdvertiseForPeersButton" Content="Advertise For a Connection"
Click="AdvertiseForPeersButton_Click" />
<Button x:Name="AcceptConnectionButton" Content="Accept Connection"
Click="AcceptConnectionButton_Click" />
<Button x:Name="FindPeersButton" Content="Browse for Peers"
Click="FindPeersButton_Click" />
<Button x:Name="StopFindingPeersButton" Content="Stop Browsing for Peers"
Click="StopFindingPeersButton_Click" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBox x:Name="SendMessageTextBox" Width="300" Height="30" />
<Button x:Name="SendMessageButton" Content="Send Message"
Click="SendMessageButton_Click" />
</StackPanel>
<TextBlock x:Name="MessageBlock" Width="600" HorizontalAlignment="Left"/>
</StackPanel>
</Grid>
3. Add click event handlers
In this step, you add the code for the click events of the XAML buttons, and a method for writing to the UI thread. The code in the event handler for the AdvertiseForPeersButton button sets the peer name for the local device and starts the PeerFinder. If triggered connections are supported (tapping), the code identifies the event handler for the TriggeredConnectionStateChanged event. In the TriggeredConnectionStateChanged event handler, the code opens a stream socket to send text messages between the peer apps.
The code in the event handler for the FindPeersButton button calls the FindAllPeersAsync method to browse for devices within wireless range. When one or more peers is found, the sample calls the ConnectAsync method to connect to the first peer found. This is for sample purposes only. You should present the user with a list of possible peers to choose from, and then connect to the peer that the user chooses.
The code includes an event handler for the ConnectionRequested event that occurs when a peer opens a connection with you by calling the ConnectAsync method. You can click the Accept Connection button to accept the connection.
The code in the event handler for the StopFindingPeersButton button calls the stop method to stop advertising and browsing for peers whether within wireless range or from a tap gesture.
In the MainPage.xaml.cs or MainPage.xaml.vb file, replace the default OnNavigatedTo event handler in the MainPage class with the following code.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
DisplayNameTextBox.Text = Windows.Networking.Proximity.PeerFinder.DisplayName;
Windows.Networking.Proximity.PeerFinder.ConnectionRequested += ConnectionRequested;
// If activated from launch or from the background, create a peer connection.
var args = e.Parameter as Windows.ApplicationModel.Activation.LaunchActivatedEventArgs;
if (args != null && args.Kind == Windows.ApplicationModel.Activation.ActivationKind.Launch)
{
if (args.Arguments == "Windows.Networking.Proximity.PeerFinder:StreamSocket")
{
AdvertiseForPeersButton_Click(null, null);
}
}
}
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
if (_started)
{
// Detach the callback handler (there can only be one PeerConnectProgress handler).
Windows.Networking.Proximity.PeerFinder.TriggeredConnectionStateChanged -= TriggeredConnectionStateChanged;
// Detach the incoming connection request event handler.
Windows.Networking.Proximity.PeerFinder.ConnectionRequested -= ConnectionRequested;
Windows.Networking.Proximity.PeerFinder.Stop();
CloseSocket();
_started = false;
}
}
// Write a message to MessageBlock on the UI thread.
private Windows.UI.Core.CoreDispatcher messageDispatcher = Window.Current.CoreWindow.Dispatcher;
async private void WriteMessageText(string message, bool overwrite = false)
{
await messageDispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
() =>
{
if (overwrite)
MessageBlock.Text = message;
else
MessageBlock.Text += message;
});
}
bool _started = false;
// Click event handler for "Advertise" button.
private void AdvertiseForPeersButton_Click(object sender, RoutedEventArgs e)
{
if (_started)
{
WriteMessageText("You are already advertising for a connection.\n");
return;
}
Windows.Networking.Proximity.PeerFinder.DisplayName = DisplayNameTextBox.Text;
if ((Windows.Networking.Proximity.PeerFinder.SupportedDiscoveryTypes &
Windows.Networking.Proximity.PeerDiscoveryTypes.Triggered) ==
Windows.Networking.Proximity.PeerDiscoveryTypes.Triggered)
{
Windows.Networking.Proximity.PeerFinder.TriggeredConnectionStateChanged +=
TriggeredConnectionStateChanged;
WriteMessageText("You can tap to connect a peer device that is " +
"also advertising for a connection.\n");
}
else
{
WriteMessageText("Tap to connect is not supported.\n");
}
if ((Windows.Networking.Proximity.PeerFinder.SupportedDiscoveryTypes &
Windows.Networking.Proximity.PeerDiscoveryTypes.Browse) !=
Windows.Networking.Proximity.PeerDiscoveryTypes.Browse)
{
WriteMessageText("Peer discovery using Wi-Fi Direct is not supported.\n");
}
Windows.Networking.Proximity.PeerFinder.Start();
_started = true;
}
private void TriggeredConnectionStateChanged(
object sender,
Windows.Networking.Proximity.TriggeredConnectionStateChangedEventArgs e)
{
if (e.State == Windows.Networking.Proximity.TriggeredConnectState.PeerFound)
{
WriteMessageText("Peer found. You may now pull your devices out of proximity.\n");
}
if (e.State == Windows.Networking.Proximity.TriggeredConnectState.Completed)
{
WriteMessageText("Connected. You may now send a message.\n");
SendMessage(e.Socket);
}
}
// Click event handler for "Browse" button.
async private void FindPeersButton_Click(object sender, RoutedEventArgs e)
{
if ((Windows.Networking.Proximity.PeerFinder.SupportedDiscoveryTypes &
Windows.Networking.Proximity.PeerDiscoveryTypes.Browse) !=
Windows.Networking.Proximity.PeerDiscoveryTypes.Browse)
{
WriteMessageText("Peer discovery using Wi-Fi Direct is not supported.\n");
return;
}
try
{
var peerInfoCollection = await Windows.Networking.Proximity.PeerFinder.FindAllPeersAsync();
if (peerInfoCollection.Count > 0)
{
// Connect to first peer found - example only.
// In your app, provide the user with a list of available peers.
ConnectToPeer(peerInfoCollection[0]);
}
}
catch (Exception err)
{
WriteMessageText("Error finding peers: " + err.Message + "\n");
}
}
async private void ConnectToPeer(Windows.Networking.Proximity.PeerInformation peerInfo)
{
WriteMessageText("Peer found. Connecting to " + peerInfo.DisplayName + "\n");
try
{
Windows.Networking.Sockets.StreamSocket socket =
await Windows.Networking.Proximity.PeerFinder.ConnectAsync(peerInfo);
WriteMessageText("Connection successful. You may now send messages.\n");
SendMessage(socket);
}
catch (Exception err)
{
WriteMessageText("Connection failed: " + err.Message + "\n");
}
requestingPeer = null;
}
// Click event handler for "Stop" button.
private void StopFindingPeersButton_Click(object sender, RoutedEventArgs e)
{
_started = false;
Windows.Networking.Proximity.PeerFinder.Stop();
if (proximitySocket != null) { CloseSocket(); }
}
// Handle external connection requests.
Windows.Networking.Proximity.PeerInformation requestingPeer;
private void ConnectionRequested(object sender,
Windows.Networking.Proximity.ConnectionRequestedEventArgs e)
{
requestingPeer = e.PeerInformation;
WriteMessageText("Connection requested by " + requestingPeer.DisplayName + ". " +
"Click 'Accept Connection' to connect.");
}
private void AcceptConnectionButton_Click(object sender, RoutedEventArgs e)
{
if (requestingPeer == null)
{
WriteMessageText("No peer connection has been requested.");
return;
}
ConnectToPeer(requestingPeer);
}
Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
DisplayNameTextBox.Text = Windows.Networking.Proximity.PeerFinder.DisplayName
AddHandler Windows.Networking.Proximity.PeerFinder.ConnectionRequested, AddressOf ConnectionRequested
' If activated from launch or from the background, create a peer connection.
Dim args = TryCast(e.Parameter, Windows.ApplicationModel.Activation.LaunchActivatedEventArgs)
If args IsNot Nothing AndAlso args.Kind = Windows.ApplicationModel.Activation.ActivationKind.Launch Then
If args.Arguments = "Windows.Networking.Proximity.PeerFinder:StreamSocket" Then
AdvertiseForPeersButton_Click()
End If
End If
End Sub
Protected Overrides Sub OnNavigatingFrom(e As Navigation.NavigatingCancelEventArgs)
If _started Then
' Detach the callback handler (there can only be one PeerConnectProgress handler).
RemoveHandler Windows.Networking.Proximity.PeerFinder.TriggeredConnectionStateChanged, AddressOf TriggeredConnectionStateChanged
' Detach the incoming connection request event handler.
RemoveHandler Windows.Networking.Proximity.PeerFinder.ConnectionRequested, AddressOf ConnectionRequested
Windows.Networking.Proximity.PeerFinder.Stop()
CloseSocket()
_started = False
End If
End Sub
' Write a message to MessageBlock on the UI thread.
Private Async Sub WriteMessageText(message As String, Optional overwrite As Boolean = False)
Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
Sub()
If overwrite Then
MessageBlock.Text = message
Else
MessageBlock.Text &= message
End If
End Sub)
End Sub
Private _started As Boolean = False
' Click event handler for "Advertise" button.
Private Sub AdvertiseForPeersButton_Click()
If _started Then
WriteMessageText("You are already advertising for a connection." & vbCrLf)
Return
End If
Windows.Networking.Proximity.PeerFinder.DisplayName = DisplayNameTextBox.Text
If ((Windows.Networking.Proximity.PeerFinder.SupportedDiscoveryTypes And
Windows.Networking.Proximity.PeerDiscoveryTypes.Triggered) =
Windows.Networking.Proximity.PeerDiscoveryTypes.Triggered) Then
AddHandler Windows.Networking.Proximity.PeerFinder.TriggeredConnectionStateChanged,
AddressOf TriggeredConnectionStateChanged
WriteMessageText("You can tap to connect a peer device that is " &
"also advertising for a connection." & vbCrLf)
Else
WriteMessageText("Tap to connect is not supported." & vbCrLf)
End If
If (Windows.Networking.Proximity.PeerFinder.SupportedDiscoveryTypes And
Windows.Networking.Proximity.PeerDiscoveryTypes.Browse) <>
Windows.Networking.Proximity.PeerDiscoveryTypes.Browse Then
WriteMessageText("Peer discovery using Wifi-Direct is not supported." & vbCrLf)
End If
Windows.Networking.Proximity.PeerFinder.Start()
_started = True
End Sub
Private Sub TriggeredConnectionStateChanged(
sender As Object,
e As Windows.Networking.Proximity.TriggeredConnectionStateChangedEventArgs)
If e.State = Windows.Networking.Proximity.TriggeredConnectState.PeerFound Then
WriteMessageText("Peer found. You may now pull your devices out of proximity." & vbCrLf)
End If
If e.State = Windows.Networking.Proximity.TriggeredConnectState.Completed Then
WriteMessageText("Connected. You may now send a message." & vbCrLf)
SendMessage(e.Socket)
End If
End Sub
' Click event handler for "Browse" button.
Private Async Sub FindPeersButton_Click()
If (Windows.Networking.Proximity.PeerFinder.SupportedDiscoveryTypes And
Windows.Networking.Proximity.PeerDiscoveryTypes.Browse) <>
Windows.Networking.Proximity.PeerDiscoveryTypes.Browse Then
WriteMessageText("Peer discovery using Wifi-Direct is not supported." & vbCrLf)
Return
End If
Try
Dim peerInfoCollection = Await Windows.Networking.Proximity.PeerFinder.FindAllPeersAsync()
If peerInfoCollection.Count > 0 Then
' Connect to first peer found - example only.
' In your app, provide the user with a list of available peers.
ConnectToPeer(peerInfoCollection(0))
End If
Catch err As Exception
WriteMessageText("Error finding peers: " & err.Message & vbCrLf)
End Try
End Sub
Private Async Sub ConnectToPeer(peerInfo As Windows.Networking.Proximity.PeerInformation)
WriteMessageText("Peer found. Connecting to " & peerInfo.DisplayName & vbCrLf)
Try
Dim socket = Await Windows.Networking.Proximity.PeerFinder.ConnectAsync(peerInfo)
WriteMessageText("Connection successful. You may now send messages." & vbCrLf)
SendMessage(socket)
Catch err As Exception
WriteMessageText("Connection failed: " & err.Message & vbCrLf)
End Try
requestingPeer = Nothing
End Sub
' Click event handler for "Stop" button.
Private Sub StopFindingPeersButton_Click()
_started = False
Windows.Networking.Proximity.PeerFinder.Stop()
If proximitySocket IsNot Nothing Then CloseSocket()
End Sub
' Handle external connection requests.
Private requestingPeer As Windows.Networking.Proximity.PeerInformation
Private Sub ConnectionRequested(sender As Object,
e As Windows.Networking.Proximity.ConnectionRequestedEventArgs)
requestingPeer = e.PeerInformation
WriteMessageText("Connection requested by " & requestingPeer.DisplayName & ". " &
"Click 'Accept Connection' to connect.")
End Sub
Private Sub AcceptConnectionButton_Click()
If requestingPeer Is Nothing Then
WriteMessageText("No peer connection has been requested.")
Return
End If
ConnectToPeer(requestingPeer)
End Sub
4. Add the code to send and receive messages using the supplied StreamSocket
When a successful connection is made, the code passes the StreamSocket object that was created by the connection to the SendMessage function. The SendMessage function opens a network connection with the proximate device, which enables you to send messages back and forth. Be sure to always call the close method of the StreamSocket object when you are finished with it.
In the MainPage.xaml.cs or MainPage.xaml.vb file, add the following code after the SendMessageButton_Click method.
private void SendMessageButton_Click(object sender, RoutedEventArgs e)
{
if (proximitySocket != null)
{
SendMessageText();
}
else
{
WriteMessageText("You must enter proximity to send a message.\n");
}
}
Windows.Networking.Sockets.StreamSocket proximitySocket;
Windows.Storage.Streams.DataWriter dataWriter;
// Reference socket streams for writing and reading messages.
private void SendMessage(Windows.Networking.Sockets.StreamSocket socket)
{
// PeerFinder has not been started.
if (!_started)
{
CloseSocket();
return;
}
// Get the network socket from the proximity connection.
proximitySocket = socket;
// Create DataWriter for writing messages to peers.
dataWriter = new Windows.Storage.Streams.DataWriter(proximitySocket.OutputStream);
// Listen for messages from peers.
Windows.Storage.Streams.DataReader dataReader =
new Windows.Storage.Streams.DataReader(proximitySocket.InputStream);
StartReader(proximitySocket, dataReader);
}
// Send a message to the socket.
private async void SendMessageText()
{
string msg = SendMessageTextBox.Text;
if (msg.Length > 0)
{
var msgLength = dataWriter.MeasureString(msg);
dataWriter.WriteInt32(msg.Length);
dataWriter.WriteString(msg);
try
{
await dataWriter.StoreAsync();
WriteMessageText("Message sent: " + msg + "\n");
}
catch (Exception e)
{
WriteMessageText("Send error: " + e.Message + "\n");
CloseSocket();
}
}
}
// Read out and print the message received from the socket.
private async void StartReader(Windows.Networking.Sockets.StreamSocket socket,
Windows.Storage.Streams.DataReader reader)
{
try
{
uint bytesRead = await reader.LoadAsync(sizeof(uint));
if (bytesRead > 0)
{
uint strLength = (uint)reader.ReadUInt32();
bytesRead = await reader.LoadAsync(strLength);
if (bytesRead > 0)
{
String message = reader.ReadString(strLength);
WriteMessageText("Received message: " + message + "\n");
StartReader(socket, reader); // Start another reader
}
else
{
WriteMessageText("The peer app closed the socket\n");
reader.Dispose();
CloseSocket();
}
}
else
{
WriteMessageText("The peer app closed the socket\n");
reader.Dispose();
CloseSocket();
}
}
catch
{
WriteMessageText("The peer app closed the socket\n");
reader.Dispose();
CloseSocket();
}
}
private void CloseSocket()
{
if (proximitySocket != null)
{
proximitySocket.Dispose();
proximitySocket = null;
}
if (dataWriter != null)
{
dataWriter.Dispose();
dataWriter = null;
}
}
public void Dispose()
{
CloseSocket();
}
Private Sub SendMessageButton_Click()
If proximitySocket IsNot Nothing Then
SendMessageText()
Else
WriteMessageText("You must enter proximity to send a message." & vbCrLf)
End If
End Sub
Private proximitySocket As Windows.Networking.Sockets.StreamSocket
Private dataWriter As Windows.Storage.Streams.DataWriter
' Reference socket streams for writing and reading messages.
Private Sub SendMessage(socket As Windows.Networking.Sockets.StreamSocket)
' PeerFinder has not been started.
If Not _started Then
CloseSocket()
Return
End If
' Get the network socket from the proximity connection.
proximitySocket = socket
' Create DataWriter for writing messages to peers.
dataWriter = New Windows.Storage.Streams.DataWriter(proximitySocket.OutputStream)
' Listen for messages from peers.
Dim dataReader = New Windows.Storage.Streams.DataReader(proximitySocket.InputStream)
StartReader(proximitySocket, dataReader)
End Sub
' Send a message to the socket.
Private Async Sub SendMessageText()
Dim msg = SendMessageTextBox.Text
If msg.Length > 0 Then
Dim msgLength = dataWriter.MeasureString(msg)
dataWriter.WriteInt32(msg.Length)
dataWriter.WriteString(msg)
Try
Await dataWriter.StoreAsync()
WriteMessageText("Message sent: " & msg & vbCrLf)
Catch e As Exception
WriteMessageText("Send error: " & e.Message & vbCrLf)
CloseSocket()
End Try
End If
End Sub
' Read out and print the message received from the socket.
Private Async Sub StartReader(socket As Windows.Networking.Sockets.StreamSocket,
reader As Windows.Storage.Streams.DataReader)
Try
Dim bytesRead As UInteger = Await reader.LoadAsync(4)
If bytesRead > 0 Then
Dim strLength = CType(reader.ReadUInt32(), UInteger)
bytesRead = Await reader.LoadAsync(strLength)
If (bytesRead > 0) Then
Dim message = reader.ReadString(strLength)
WriteMessageText("Received message: " & message & vbCrLf)
StartReader(socket, reader) ' Start another reader
Else
WriteMessageText("The peer app closed the socket" & vbCrLf)
reader.Dispose()
CloseSocket()
End If
Else
WriteMessageText("The peer app closed the socket" & vbCrLf)
reader.Dispose()
CloseSocket()
End If
Catch
WriteMessageText("The peer app closed the socket" & vbCrLf)
reader.Dispose()
CloseSocket()
End Try
End Sub
Private Sub CloseSocket()
If proximitySocket IsNot Nothing Then
proximitySocket.Dispose()
proximitySocket = Nothing
End If
If dataWriter IsNot Nothing Then
dataWriter.Dispose()
dataWriter = Nothing
End If
End Sub
Public Sub Dispose()
CloseSocket()
End Sub
5. Add the code to activate the app on a peer from a tap
In the code that you added earlier to set up the connection methods and event handlers, you included code in the OnNavigatedTo event handler to complete a socket connection if the app is activated by a tap. In order for that code to function correctly, the launch event arguments must be passed to the main page when it is navigated to. This is done in the OnLaunched event handler, which runs when the app is activated.
Open the App.xaml.cs or App.xaml.vb file and replace the default OnLaunched method with the following.
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
if (Window.Current.Content == null)
{
var rootFrame = new Frame();
rootFrame.Navigate(typeof(MainPage), args);
Window.Current.Content = rootFrame;
}
else
{
var rootFrame = Window.Current.Content as Frame;
rootFrame.Navigate(typeof(MainPage), args);
}
// Ensure the current window is active
Window.Current.Activate();
}
6. Run the app
To see the app in action, run it on two devices that have Proximity enabled. Click the Advertise for a Connection button in both apps, and then tap the devices together. If you have two Windows devices with Wi-Fi Direct enabled on both devices, you can click the Browse for Peers button on one device to create the connection. If you have two phones and Bluetooth is enabled on both devices, you can also tap Browse for Peers on one phone to create the connection.
Important
This quickstart must be run on two devices. For scenarios that use a tap gesture, each device must have a Proximity device, such as a Near-Field Communication (NFC) radio, installed. For scenarios that use wireless browsing, you need two PCs with Wi-Fi Direct enabled, or two Windows Phones with Bluetooth enabled. If you don't have hardware that supports Proximity tapping, such as an NFC radio, you can use the Proximity driver sample that is part of the Windows Driver Kit (WDK) samples. You can use the sample driver to simulate a tap gesture over a network connection between two Windows devices. For information on how to download the WDK, see Windows Driver Kit (WDK). After you have installed the WDK and samples, you can find the Proximity driver sample in the src\nfp directory in the location where you installed the WDK samples. See the NetNfpProvider.html file in the src\nfp\net directory for instructions on building and running the simulator. After you start the simulator, it runs in the background while your Proximity app is running in the foreground. Your app must be in the foreground for the tap simulation to work.
Summary and next steps
In this tutorial, you created an app that uses a tap gesture or wireless browsing to connect devices.
You can also use tap gestures to publish and subscribe to messages. For an example, see Quickstart: Publishing and subscribing to messages using Tapping.
Related topics
Proximity and tapping overview
Quickstart: Publishing and subscribing to messages using tapping
Testing and troubleshooting Proximity in apps
Windows.Networking.Proximity namespace
Samples