December 2014

Volume 29 Number 12

Universal Apps : Equip Your Apps with OBEX

Uday Gupta

During the last decade, Bluetooth has become a widely used technology for short-range wireless communication between devices such as mobile phones, personal computers and headsets. The Bluetooth Special Interest Group (BTSIG) is the industry body that defines the standards for wireless services in Bluetooth Profile specifications.

One such profile is the Object Push Profile (OPP), which is used to send files from one device to another. The Object Exchange Protocol (OBEX) is part of the foundation of the OPP. OBEX is also used in profiles other than OPP, as it’s a generic protocol for transferring objects between devices.

For developers looking to use OBEX within their apps, I’ve developed a set of APIs over the Windows Runtime (WinRT) Bluetooth APIs that provide OBEX from within the app. These APIs come as a library package for universal apps, which means Windows Store apps and Windows Phone Silverlight apps can leverage the same set of APIs.

OBEX and OPP

First, it’s important to understand what OBEX and OPP are and how they work. OPP lets a Bluetooth device send a file or object to another OPP-capable Bluetooth device. The intended use for OBEX was file sharing via infrared channels. The BTSIG chose to reuse this protocol for file sharing over Bluetooth. Aside from the underlying transport medium, OBEX-over-infrared and OBEX-over-Bluetooth are similar.

OBEX is based on a client-server model in which the recipient Bluetooth device is running an OBEX server that listens for and accepts client connections. The client Bluetooth device connects to the server Bluetooth device as a stream channel over Bluetooth. The authentication requirements to allow the connection and object transfer depend on the service or application using OBEX. For example, OPP can allow an unauthenticated connection in order to streamline the process of quickly exchanging business cards. Other services using OBEX may only allow authenticated connections.

Files are shared using three types of packets. These packets are known as first PUT, intermediate PUT and last PUT. The first PUT packet marks the file transfer initialization and the last PUT packet marks its completion. The multiple intermediate PUT packets contain the bulk of the data. After the server receives each PUT packet, it returns an acknowledgement packet to the client.

In a typical scenario, OBEX packets are sent as follows:

  1. The OBEX client connects to the recipient device by sending a connect packet. This packet specifies the maximum packet size the client can receive.
  2. After receiving a response from the server indicating the connection has been accepted, the OBEX client sends the first PUT packet. This contains the metadata describing the object, including the file name and size. (While the OBEX protocol allows for this first PUT packet to also include object data, the implementation of OBEX in the library I’ve developed doesn’t send any of that data in the first PUT packet.)
  3. After receiving acknowledgement the server has the first PUT packet, the OBEX client sends the multiple PUT packets that contain object data. The length of these packets is limited by the maximum packet size the server can receive, set by the server’s response to the connect packet sent in step one.
  4. The last PUT packet contains the last PUT constant and the final chunk of object data.
  5. Once the file sharing is complete, the OBEX client sends a disconnect packet and closes the Bluetooth connection. The OBEX protocol allows repetition of steps two through three to send multiple objects on the same connection.

At any point, the OBEX client can abort the sharing process by sending an ABORT packet. The sharing is immediately canceled. In the library I’ve written, the OBEX protocol implementation details are hidden and you’ll only see high-level APIs.

The OBEX Library

The Bluetooth OBEX client library for Windows Store apps is designed as a portable library targeting: Windows Store apps and Windows Phone Silverlight 8.1 apps. It contains three DLLs that make the library a runtime for the OBEX client. Each DLL is designed to handle a specific task: Bluetooth.Core.Service, Bluetooth.Core.Sockets and Bluetooth.Services.Obex.

Bluetooth Core Service The file Bluetooth.Core.Service.dll contains the Bluetooth.Core.Service namespace. This library is designed to search for and count nearby Bluetooth devices paired with the client device (see Figure 1). Currently, it’s restricted to a one-time count of paired devices. Future versions will contain a watcher to keep looking for additional Bluetooth devices.

Figure 1 Methods and Associated Events from BluetoothService

Method (with Parameters) Associated Events
[static] GetDefault No associated event
SearchForPairedDevicesAsync

Success - SearchForDevicesSucceeded

Failure - SearchForPairedDevicesFailed

The core Bluetooth service is represented by a static class called BluetoothService, shown in Figure 2. This class has an API to asynchronously count devices.

Figure 2 BluetoothService Counting Paired Devices

BluetoothService btService = BluetoothService.GetDefault();
btService.SearchForPairedDevicesFailed 
  += btService_SearchForPairedDevicesFailed;
btService.SearchForPairedDevicesSucceeded 
  += btService_SearchForPairedDevicesSucceeded;
await btService.SearchForPairedDevicesAsync();
void btService_SearchForPairedDevicesSucceeded(object sender,
  SearchForPairedDevicesSucceededEventArgs e)
{
  // Get list of paired devices from e.PairedDevices collection
}
void btService_SearchForPairedDevicesFailed(object sender,
  SearchForPairedDevicesFailedEventArgs e)
{
  // Get the failure reason from e.FailureReason enumeration
}

Bluetooth Core Sockets The file Bluetooth.Core.Sockets.dll contains the Bluetooth.Core.Sockets namespace and is designed to support stream-based socket operations over a Bluetooth connection. The socket functionality is exposed via the BluetoothSockets class (see Figure 3). This is neither a TCP nor UDP socket. All communication with the recipient device takes place through BluetoothSockets.

Figure 3 Methods and Associated Events from BluetoothSockets

Method (with Parameters) Associated Events

Constructor(Bluetooth.Core.Services.BluetoothDevice)

Constructor(Bluetooth.Core.Services.BluetoothDevice, System.UInt32)

Constructor(Bluetooth.Core.Services.BluetoothDevice, System.String)

Constructor(Bluetooth.Core.Services.BluetoothDevice, System.UInt32, System.String)

No associated event
PrepareSocketAsync

Success – SocketConnected

Failure – ErrorOccured

SendDataAsync(System.Byte[])

SendDataAsync(System.String)

No associated Event
CloseSocket SocketClosed
No associated method DataReceived

Bluetooth Services Obex The Bluetooth.Services.Obex.dll file contains the Bluetooth.Services.Obex namespace. This is the core implementation of OBEX, exposed through a class named ObexService. This class provides the abstracted view of the Bluetooth OPP specification. It exposes the method that helps connect, send and disconnect from the recipient Bluetooth device. Figure 4 lists the APIs and associated events this class exposes, and Figure 5 demonstrates the usage.

Figure 4 Methods and Associated Events from ObexService

Method (with Parameters) Associated Events
[static] GetDefaultForBluetoothDevice(Bluetooth.Core.Services.BluetoothDevice) No associated event
ConnectAsync

Success – DeviceConnected

Failure – ConnectionFailed

SendFileAsync(Windows.Storage.IStorageFile)

Success:

ServiceConnected

DataTransferProgressed

DataTransferSucceeded

Disconnecting

Disconnected

Failure:

ConnectionFailed

DataTransferFailed

AbortAsync Aborted

Figure 5 Obex Service Usage

protected async override void OnNavigatedTo(Windows.UI.Xaml.Navigation.NavigationEventArgs e)
{
  base.OnNavigatedTo(e);
  ObexService obexService = ObexService.GetDefaultForBluetoothDevice(null);
  obexService.DeviceConnected += obexService_DeviceConnected;
  obexService.ServiceConnected += obexService_ServiceConnected;
  obexService.ConnectionFailed += obexService_ConnectionFailed;
  obexService.DataTransferProgressed += obexService_DataTransferProgressed;
  obexService.DataTransferSucceeded += obexService_DataTransferSucceeded;
  obexService.DataTransferFailed += obexService_DataTransferFailed;
  obexService.Disconnecting += obexService_Disconnecting;
  obexService.Disconnected += obexService_Disconnected;
  obexService.Aborted += obexService_Aborted;
  await obexService.ConnectAsync();
}
async void obexService_DeviceConnected(object sender, EventArgs e)
{
  // Device is connected, now send file
  await (sender as ObexService).SendFileAsync(fileToSend);
}
void obexService_ServiceConnected(object sender, EventArgs e)
{
  // Device connected to Obex Service on target device
}
void obexService_ConnectionFailed(object sender, 
  ConnectionFailedEventArgs e)
{
  // Connection to service failed
}
void obexService_DataTransferProgressed(object sender, 
  DataTransferProgressedEventArgs e)
{
  // Get data transfer progress from DataTransferProgressedEventArgs
}
void obexService_DataTransferSucceeded(object sender, EventArgs e)
{
  // Data transfer succeeded
}
void obexService_DataTransferFailed(object sender, DataTransferFailedEventArgs e)
{
  // Data transfer failed, get the reason from DataTransferFailedEventArgs
}
void obexService_Disconnecting(object sender, EventArgs e)
{
  // Device is disconnecting from service
  }
void obexService_Disconnected(object sender, EventArgs e)
{
  // Device is now disconnected from targeted device and service
}
void obexService_Aborted(object sender, EventArgs e)
{
  // Data transfer operation is aborted
}

A typical usage scenario for using these libraries is something like this:

  • Using APIs in Blue-­tooth.Core.Service, count all the paired OPP-capable Bluetooth devices. OPP-capability check is already implemented.
  • Get the instance of BluetoothDevice with which you want to share files.
  • Get an instance of ObexService for the recipient Bluetooth device by passing the instance of BluetoothDevice to factory method. The ObexService class will internally create an instance of BluetoothSocket, over which the ObexService will share the file.
  • Once file sharing is complete, the ObexService is disconnected automatically.

Get Started

Because my library is targeted toward Windows Store apps and Windows Phone 8.1 apps, I’ll start with a universal app. These are a great way of developing apps for all Windows devices. To learn more about universal apps, visit bit.ly/1h3AQeu. To start with universal apps, I’ll use Visual Studio 2013 and create a new universal apps project under the Store Apps node (see Figure 6). I used Visual C#, but you can also use Visual Basic and Visual C++.

Blank Universal App to Create a New Project
Figure 6 Blank Universal App to Create a New Project

Before I start programming for a Bluetooth OBEX client app, I’ll update the package.appx­manifest file for both projects (apps for Windows 8.1 and Windows Phone 8.1):

<Capabilities>
  <m2:DeviceCapability Name="bluetooth.rfcomm">
    <m2:Device Id="any">
      <m2:Function Type="name:obexObjectPush"/>
    </m2:Device>
  </m2:DeviceCapability>
</Capabilities>

To apply this update, I open package.appx­­manifest as a code file by choosing View Code in the context menu in Solution Explorer. I’ll place this snippet where <Application> tag ends. That code snippet is required to provide device-level capability to use the Bluetooth radio frequency communication (RFCOMM) service with this app. I also specified all services and device types compatible with this device.

For my scenario, I need obexObjectPush support from the device that’s compatible with any OPP-capable device. For more information on Supported profiles on Windows 8.1 and Windows Phone 8.1, visit bit.ly/1pG6rYO. If that capability isn’t mentioned, then device enumeration will fail with CapabilityNotDefined enum constant.

Before I start coding, I’ll add the reference to the three library files mentioned earlier so I can use the OBEX implementation within those libraries. I need to a add reference to these libraries for both projects separately. If the reference isn’t added, the project won’t be able to use any features.

I’ll follow these coding patterns and practices:

  • Implement UX design for Windows Store 8.1 app in Windows project.
  • Implement UX design for Windows Phone 8.1 apps in Windows Phone project.
  • Implement common feature in Shared project.
  • Perform platform-specific implementation in Shared project using platform-specific compiler constants. For Windows 8.1, I’ll use WINDOWS_APP. For Windows Phone 8.1, I’ll use WINDOWS_PHONE_APP. These compiler constants are already defined as part of the project.

Download the sample code to get hands-on experience with these libraries, along with the coding practices you should follow for developing universal apps. Figure 7 shows the sample project’s Solution Explorer window with the file structure and patterns.

Solution Explorer of BluetoothDemo App
Figure 7 Solution Explorer of BluetoothDemo App

Enumerating Paired Devices

Before I can share files with a paired device, I need to see the list of paired devices and select a target. I’ll get the handle to the instance of Bluetooth.Core.Services.BluetoothService, which represents the core Bluetooth service provided by my device. I acquire this instance using the GetDefault static factory method, because there’s only one Bluetooth service available per device.

For enumeration, I’ll make a call to the SearchForPairedDevicesAsync method. This method will start enumerating devices paired with my device. For Windows Store 8.1 apps, I need to allow the use of a paired device to get the enumerated devices. If I block the use, that paired device won’t be enumerated.

If that API succeeds, it will raise the SearchForPairedDevicesSucceeded event and fetch the collection of paired devices from its event argument. Otherwise, the SearchForPairedDevicesFailed event will be raised, with failure enum constant available in its event argument. Figure 8 shows the code for enumerating devices.

Figure 8 Enumerating Paired Devices

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
  base.OnNavigatedTo(e);
  await EnumerateDevicesAsync();
}
public async Task EnumerateDevicesAsync()
{
  BluetoothService btService = BluetoothService.GetDefault();
  btService.SearchForPairedDevicesFailed +=
    btService_SearchForPairedDevicesFailed;
  btService.SearchForPairedDevicesSucceeded +=
    btService_SearchForPairedDevicesSucceeded;
  await btService.SearchForPairedDevicesAsync();
}
void btService_SearchForPairedDevicesSucceeded(object sender,
  SearchForPairedDevicesSucceededEventArgs e)
{
  (sender as BluetoothService).SearchForPairedDevicesFailed -=
    btService_SearchForPairedDevicesFailed;
  (sender as BluetoothService).SearchForPairedDevicesSucceeded -=
    btService_SearchForPairedDevicesSucceeded;
  this.cvBtDevices.Source = e.PairedDevices;
}
void btService_SearchForPairedDevicesFailed(object sender,
  SearchForPairedDevicesFailedEventArgs e)
{
  (sender as BluetoothService).SearchForPairedDevicesFailed -=
    btService_SearchForPairedDevicesFailed;
  (sender as BluetoothService).SearchForPairedDevicesSucceeded -=
    btService_SearchForPairedDevicesSucceeded;
  txtblkErrorBtDevices.Text = e.FailureReason.ToString();
}

I’ve also provided the scan button in BottomAppBar for Windows 8.1 and ApplicationBar for Windows Phone 8.1. That way an app user can rescan for devices when a new paired device has arrived.

When enumerating devices on Windows Phone 8.1, it will enumerate all OBEX-capable devices, regardless of their physical presence and whether the Bluetooth radio is switched on. However, when enumerating devices on Windows 8.1, it will only list those devices physically present near the Windows 8.1 device and with their Bluetooth radio switched on.

Once I enumerate the paired devices, I can select a device to share the files. Each device is represented as an object of the Bluetooth.Core.Services.BluetoothDevice class. The object contains connection details and the display name of the paired device. The Bluetooth.Services.Obex.ObexService will use the connection details internally to create an instance of Bluetooth.Core.Sock­ets.BluetoothSocket and connect to the paired device.

Using ObexService

Once I get the instance of the Bluetooth.Core.Services.BluetoothDevice object that represents my targeted device for sharing files, I can use Bluetooth.Services.Obex.ObexService for sharing files using OPP. I also need the list of files so I can queue them for sharing. In the code sample, I’ve only provided a handful of files. Otherwise, I could use Windows.Storage.Pickers.FileOpenPicker (see bit.ly/1qtiLeh) or custom logic from my Windows.Storage.ApplicationData.Current.LocalFolder (see bit.ly/1qtiSGI) to select multiple files.

As of now, I can only share one file per connection. When sharing is complete, the connection to the targeted device is closed. If I need to send multiple files, I need to get the handle to Blue­tooth.Services.Obex.ObexService instance multiple times. I can acquire this instance using the static factory method GetDefaultForBluetoothDevice(Bluetooth.Core.Services.BluetoothDevice). This method returns the single instance of Bluetooth.Services.Obex.ObexService that represents the Obex service on the device.

To represent the file to share, I’ll use the FileItemToShare class. This contains the name, path and size of the file, and the instance of Windows.Storage.IStorageFile (see bit.ly/1qMcZlB) representing the file instance on the disk. I’ll queue all the files I have to share in terms of data structure objects. When sharing multiple files, the first file in the list is the one currently being shared. It’s removed from the list when sharing is complete. Figure 9 shows how to hook up ObexService and its events for sharing files.

Figure 9 Hooking ObexService and Its Events

ObexService obexService = null;
BluetoothDevice BtDevice = null;
ObservableCollection<FileItemToShare> filesToShare = null;
async override void OnNavigatedTo(NavigationEventArgs e)
{
  base.OnNavigatedTo(e);
  if (e.Parameter == null || !(e.Parameter is BluetoothDevice))
  {
    MessageDialog messageBox = new MessageDialog(
      "Invalid navigation detected. Moving to Main Page", "Bluetooth Hub");
    messageBox.Commands.Add(new UICommand("OK", (uiCommand) =>
    {
      this.Frame.Navigate(typeof(MainPage));
    }));
    await messageBox.ShowAsync();
    return;
  }
  BtDevice = e.Parameter as BluetoothDevice;
  filesToShare = GetFilesFromLocalStorage();
  this.cvFileItems.Source = filesToShare;
  obexService = ObexService.GetDefaultForBluetoothDevice(BtDevice);
  obexService.Aborted += obexService_Aborted;
  obexService.ConnectionFailed += obexService_ConnectionFailed;
  obexService.DataTransferFailed += obexService_DataTransferFailed;
  obexService.DataTransferProgressed += obexService_DataTransferProgressed;
  obexService.DataTransferSucceeded += obexService_DataTransferSucceeded;
  obexService.DeviceConnected += obexService_DeviceConnected;
  obexService.Disconnected += obexService_Disconnected;
  obexService.Disconnecting += obexService_Disconnecting;
  obexService.ServiceConnected += obexService_ServiceConnected;
  await obexService.ConnectAsync();
}

When I call the ConnectAsync method, the ObexService object gets the connection properties from BluetoothDevice object, which was passed in the factory method. It attempts to create a connection with the targeted BluetoothDevice over Bluetooth channel. When that’s successful, it raises the DeviceConnected event. Figure 10 shows the DeviceConnected event handler of ObexService.

Figure 10 DeviceConnected Event Handler Method

async void obexService_DeviceConnected(object sender, EventArgs e)
{
  await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
  {
    System.Diagnostics.Debug.WriteLine("device connected");
    if (filesToShare.Count > 0)
    {
      filesToShare.ShareStatus = FileShareStatus.Connecting;
      await obexService.SendFileAsync(filesToShare[0].FileToShare);
    }
    ...
  });
}

As soon as the device is connected to the targeted device, I’ll start sharing the file at index 0 from the list of files. The file is shared by calling SendFileAsync(Windows.Storage.IStorageFile) and passing the file object represented by IStorageFile from object of type FileToShare data structure. When this method is called, the ObexService attempts to connect to the OBEX Server running on the targeted device. If the connection is successful, it will raise the ServiceConnected event. Otherwise, it will raise ConnectionFailed event. This code shows the ServiceConnected event handler:

async void obexService_ServiceConnected(object sender, EventArgs e)
{
  await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
  {
    System.Diagnostics.Debug.WriteLine("service connected");
    filesToShare[0].ShareStatus = FileShareStatus.Sharing;
  });
}

Figure 11 shows the ConnectionFailed event handler of ObexService.

Figure 11 ConnectionFailed Event Handler Method

async void obexService_ConnectionFailed(object sender, 
  ConnectionFailedEventArgs e)
{
  await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
  {
    System.Diagnostics.Debug.WriteLine("connection failed");
    filesToShare[0].ShareStatus = FileShareStatus.Error;
    filesToShare[0].Progress = 0;
    FileItemToShare currentItem = filesToShare[0];
    filesToShare.RemoveAt(0);
    filesToShare.Add(currentItem);
  });
}

When my device connects to the OBEX server of the targeted device, the file sharing process begins. The progress of files shared can be determined from the DataTransferProgressed event. The following code shows the DataTransferProgressed method:

async void obexService_DataTransferProgressed(object sender,
  DataTransferProgressedEventArgs e)
{
  await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
  {
    System.Diagnostics.Debug.WriteLine("Bytes {0}, Percentage {1}",
      e.TransferInBytes, e.TransferInPercentage);
    filesToShare[0].Progress = e.TransferInBytes;
  });
}

Once file sharing is complete, that raises the DataTransfer­Succeeded event. If file sharing is unsuccessful, it raises the DataTransferFailedEvent. The following code shows DataTransfer­Succeeded event handler:

async void obexService_DataTransferSucceeded(object sender, EventArgs e)
{
  await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
  {
    System.Diagnostics.Debug.WriteLine("data transfer succeeded");
    filesToShare.RemoveAt(0);
  });
}

In the event of a file sharing error, it will raise a DataTransferFailed event. The event handler is shown in the following code:

async void obexService_DataTransferFailed(object sender,
  DataTransferFailedEventArgs e)
{
  await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
  {
    System.Diagnostics.Debug.WriteLine("Data transfer failed {0}",
      e.ExceptionObject.ToString());
    filesToShare[0].ShareStatus = FileShareStatus.Error;
    filesToShare[0].Progress = 0;
    FileItemToShare fileToShare = this.filesToShare[0];
    filesToShare.RemoveAt(0);
    this.filesToShare.Add(fileToShare);
  });
}

When the data transfer is finished, the shared file is removed from the list and the ObexService is disconnected. When the ObexService is disconnecting, it raises the Disconnecting event. And, when the connection is disconnected properly, then the Disconnected event is raised. The Disconnecting event handler is shown here:

void obexService_Disconnecting(object sender, EventArgs e)
{
  System.Diagnostics.Debug.WriteLine("disconnecting");
}

Once the connection is successfully disconnected, the code in Figure 12 handles raising the Disconnected event.

Figure 12 Disconnected Event Handler Method

async void obexService_Disconnected(object sender, EventArgs e)
{
  await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
  {
    System.Diagnostics.Debug.WriteLine("disconnected");
    obexService.Aborted -= obexService_Aborted;
    obexService.ConnectionFailed -= obexService_ConnectionFailed;
    obexService.DataTransferFailed -= obexService_DataTransferFailed;
    obexService.DataTransferProgressed -= 
      obexService_DataTransferProgressed;
    obexService.DataTransferSucceeded -= 
      obexService_DataTransferSucceeded;
    obexService.DeviceConnected -= obexService_DeviceConnected;
    obexService.Disconnected -= obexService_Disconnected;
    obexService.Disconnecting -= obexService_Disconnecting;
    obexService.ServiceConnected -= obexService_ServiceConnected;
    obexService = null;
    if (filesToShare.Count.Equals(0))
    {
      ...
      MessageDialog messageBox =
        new MessageDialog("All files are shared successfully",
        "Bluetooth DemoApp");
      messageBox.Commands.Add(new UICommand("OK", (uiCommand) =>
      {
        this.Frame.Navigate(typeof(MainPage));
      }));
      await messageBox.ShowAsync();
    }
    else
    {
      obexService = ObexService.GetDefaultForBluetoothDevice(BtDevice);
      obexService.Aborted += obexService_Aborted;
      obexService.ConnectionFailed += obexService_ConnectionFailed;
      obexService.DataTransferFailed += obexService_DataTransferFailed;
      obexService.DataTransferProgressed += 
        obexService_DataTransferProgressed;
      obexService.DataTransferSucceeded += 
        obexService_DataTransferSucceeded;
      obexService.DeviceConnected += obexService_DeviceConnected;
      obexService.Disconnected += obexService_Disconnected;
      obexService.Disconnecting += obexService_Disconnecting;
      obexService.ServiceConnected += obexService_ServiceConnected;
      await obexService.ConnectAsync();
    }
  });
}

When the Disconnected event is raised, remove all handlers and clear out the ObexService instance. During data transfer, conditions may arise that require you to abort current transfer. To abort a current transfer, call AbortAsync. The Aborted event is raised with the following code and then the connection to the targeted device is ended:

async void obexService_Aborted(object sender, EventArgs e)
{
  await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
  {
    System.Diagnostics.Debug.WriteLine("Aborted");
    if (!filesToShare.Count.Equals(0))
    {
      filesToShare.RemoveAt(0);
    }
  });
}

Wrapping Up

The demo app is now complete. The concept of universal apps can really help you in writing a single piece of code for multiple Windows platforms and form-factors, thereby reducing the overall development effort.

I’ve used these libraries in a number of Windows Store and Windows Phone apps. Search for Code Create (a free Windows Phone App) or OBEX (Universal App) and get a glimpse of how these APIs work in conjunction with the app. These libraries are available to download from the NuGet repository. Simply search for “Bluetooth OBEX for Store Apps” on the NuGet online dialog, straight from the Visual Studio Solution and import these libraries as a reference to the projects.


Uday Gupta is a senior engineer-product development at Symphony Teleca Corp. Pvt Ltd. in India. He has experience in many .NET technologies, especially Windows Presentation Foundation, Silverlight, Windows Phone and Windows 8.x.

Thanks to the following Microsoft technical experts for reviewing this article: Jeff Kelley and Guruprasad Subbarayan