Transferring data via Bluetooth

We can transfer data to another device directly without having to use the Internet or any network infrastructure outside another device. Bluetooth allows one device to directly communicate with another device.

How to do it...

We can set up our app to listen for Bluetooth devices that we can communicate with:

  1. As with normal Bluetooth access, we need to have the apropriate permissions, such as Bluetooth and BluetoothAdmin, before we can transmit data via Bluetooth:
    [assembly: UsesPermission(Manifest.Permission.Bluetooth)]
    [assembly: UsesPermission(Manifest.Permission.BluetoothAdmin)]
  2. Before we start the listener, we need to have a name that will be used to register it with the system:
    const string ServiceName = "XamarinCookbookBluetooth";
  3. Before two apps can communicate, they need to know about each other. This is achieved by providing a generated UUID that will be used by both devices:
    const string Uuid = "25c0d296-0e78-4849-b70b-86f01f415add";
  4. We start the listener with the ListenUsingRfcommWithServiceRecord() method on the Bluetooth adapter, passing the service registration name and the UUID for this app:
    BluetoothServerSocket serverSocket = null;
    BluetoothSocket serverClientSocket = null;
    try {
      serverSocket = bluetooth.ListenUsingRfcommWithServiceRecord(
          ServiceName, UUID.FromString(Uuid));
      while (serverClientSocket == null) {
        serverClientSocket = await serverSocket.AcceptAsync();
      }
    }
    catch (IOException ex) {
      // there was an error, such as no devices found
    }
  5. Once a device is found, we can stop the listener and get hold of the communication streams:
    if (serverClientSocket != null) {
      serverSocket.Close();
      var device = serverClientSocket.RemoteDevice;
      try {
        inputStream = socket.InputStream;
        outputStream = socket.OutputStream;
      }
      catch (IOException ex) {
        // handle errors
      }
    }

Setting up the app to connect to another device that is listening is much the same, except we request to connect to a specific device:

  1. First, we need to get hold of the device we wish to connect to:
    BluetoothDevice paired = bluetooth.BondedDevices.First();
  2. Before we try and connect, we must make sure to cancel any discovery, as this slows down the connection and we already have a device:
    bluetooth.CancelDiscovery();
  3. Then we request a connection, providing the specific UUID for the app we wish to talk to:
    BluetoothSocket clientSocket = null;
    clientSocket = paired.CreateRfcommSocketToServiceRecord(
      UUID.FromString(Uuid));
    await clientSocket.ConnectAsync();
  4. Once a device is connected, we can get hold of the communication streams, just like the server did:
    try {
      inputStream = clientSocket.InputStream;
      outputStream = clientSocket.OutputStream;
    }
    catch (IOException ex) {
      // handle errors
    }

On both the server listener and the client, we can transfer data back and forth using the two streams:

  1. We can start reading the data off the input stream:
    byte[] bytes = new byte[1024];
    while (true) {
      try {
        var size = await inputStream.ReadAsync(
          bytes, 0, bytes.Length);
        var stringRead = Encoding.UTF8.GetString(
          bytes, 0, size);
      }
      catch (IOException ex) {
        // handle errors
      }
    }
  2. To send data, we just write to the output stream:
    var stringToSend = "Hello World!";
    var bytes = Encoding.UTF8.GetBytes(stringToSend);
    try {
      await outputStream.WriteAsync(bytes, 0, bytes.Length);
    }
    catch (IOException ex) {
      // handle errors
    }

How it works...

In order to send data from one device to another, both devices need to have an open stream. One device will send data, and the other will listen for incoming data. Also, both devices need to use an UUID that represents the connection from the client. The server listens for an incoming connection with a particular UUID and then accepts it, if it is the expected one.

The UUID is app-specific in that it is controlled by the app. Some apps may randomly generate UUIDs each time, and others may have a hardcoded value. This UUID can be randomly generated by the app, or specified by some other source, such as a new UUID for each major app version.

Note

In order to connect two devices, both the server and the client need to use the same UUID while connecting.

More information on how Bluetooth actually transfers data can be found on the official Bluetooth website: http://www.bluetooth.com/Pages/How-It-Works.aspx.

The server, or the listener, starts listening for incoming connections via the ListenUsingRfcommWithServiceRecord() method on the Bluetooth adapter. This method returns a BluetoothServerSocket with which we try and accept an incoming connection using the AcceptAsync() method. As soon as an incoming client connection is accepted, the method returns a BluetoothSocket instance, which represents an open connection.

Once we have an open connection to the client, we can stop listening for more connections by invoking the Close() method on the BluetoothServerSocket instance. We can then query the open client connection for the device by using the RemoteDevice property as well as get the communication streams.

The connection has two streams, one for incoming data, from the InputStream property, and one for outgoing data, from the OutputStream property. Both are basic Stream types that support byte-based communication.

Tip

Before connecting to a server, the client should cancel any ongoing device discovery as it may negatively impact connection performance.

If we want to connect to a listening server, we first need a device to which we want to connect. Once we have the device, either after a discovery or from an existing pair, we invoke the CreateRfcommSocketToServiceRecord() method on the BluetoothDevice instance. This method returns a BluetoothSocket instance, which represents a connection to the server. In order to start communicating, we have to open the connection using the ConnectAsync() method.

Once the connection to the server is opened, we can obtain the two streams just as we did with the server. Again, the InputStream instance represents the incoming data channel and the OutputStream represents the outgoing data channel.

Tip

Reading from and writing to the Bluetooth streams involves only the usual .NET stream operations, either directly or through a serializer.

Reading data from the input stream is simply a matter of continuously reading the data out of the InputStream instance. To do this, we can invoke the ReadAsync() method, with a buffer, and wait for a response. As soon as enough data is read, either when the buffer is full or when there is no more to read, the method will return with the number of bytes read. We can then convert those bytes into a stream. We could also read the data using a Stream instance by passing the actual stream to a deserializer or any reader that accepts a Stream instance such as XDocument.Load().

Sending data to the other device is simply a matter of writing bytes to the OutputStream instance. We could write directly using the WriteAsync() method or we could use a serializer, such as XDocument.Save(), which accepts a Stream instance.

There's more...

Just as we can communicate via Bluetooth, we can communicate via NFC, which is a shorter range communication technology.

See also

  • The Accessing Bluetooth recipe
  • The Sending data via NFC recipe
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.55.14