Language: JavaScript and HTML | VB/C#/C++ and XAML

Quickstart: Connecting apps using tapping or browsing (Windows Runtime apps using C#/VB/C++ and XAML)

Applies to Windows and Windows Phone

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

  1. 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.
  2. 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);
}


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();
}


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
Guidelines for proximity
Testing and troubleshooting proximity in apps
Windows.Networking.Proximity namespace
Samples
Proximity sample

 

 

Show:
© 2014 Microsoft. All rights reserved.