Xamarin Bluetooth LE: Scan for devices Android Edition

Posted on Posted in Uncategorized

For iOS see Xamarin Bluetooth LE: Scan for devices iOS Edition

I was working through a Xamarin Forms PCL app recently and had to implement GATT communications on UWP, Android and iOS applications.

Here’s some steps and code you need for the first part of that task: Scan for devices on Android

    1. Make sure you have permissions set up. You need BluetoothAdmin and Bluetooth
      required-permissions
    2. Drop a listview in your axml file and derive the activity from ListActivity. You will have to change the id attribute of the ListView to android:id=”@android:id/list”
    3. I just created a new Android SingleView project for demonstration
          [Activity(Label = "AndroidGATT", MainLauncher = true, Icon = "@drawable/icon")]
          public class MainActivity : ListActivity
          {
              private BluetoothEnumerationService _bluetoothEnumerationService;
              protected override void OnCreate(Bundle bundle)
              {
                  base.OnCreate(bundle);
      
                  // Set our view from the "main" layout resource
                  SetContentView(Resource.Layout.Main);
      
                  // Get our button from the layout resource,
                  // and attach an event to it
                  var button = FindViewById<Button>(Resource.Id.MyButton);
      
                  _bluetoothEnumerationService = new BluetoothEnumerationService();
                  
                  button.Click += async delegate
                  {
                      ListAdapter = new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, new[] {"Searching..."});
                      var devices = await _bluetoothEnumerationService.GetDevicesAsync();
                      ListAdapter = new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, devices.Select(x => x.Name).ToList());
                  };
              }
          }
      

      Note that MainActivity is derived from ListActivity instead of Activity

    4. Now you can implement the scanner service
      public class BluetoothEnumerationService
          {
              private readonly BluetoothAdapter _bluetoothAdapter;
              private readonly ScanCallback _androidScanCallback;
              private readonly Dictionary<string, BluetoothDevice> _devices = new Dictionary<string, BluetoothDevice>();
      
              public BluetoothEnumerationService()
              {
                  var bluetoothManager = (BluetoothManager) Application.Context.GetSystemService(Context.BluetoothService);
                  _androidScanCallback = new MyAndroidScanCallback(_devices);
                  _bluetoothAdapter = bluetoothManager.Adapter;
              }
      
              public async Task<IEnumerable<BluetoothDevice>> GetDevicesAsync()
              {
                  if (!_bluetoothAdapter.IsEnabled)
                      return _devices.Values;
      
                  _bluetoothAdapter.BluetoothLeScanner.StartScan(_androidScanCallback);
                  await Task.Delay(200);
                  _bluetoothAdapter.BluetoothLeScanner.StopScan(_androidScanCallback);
                  return _devices.Values;
              }
          }
      
          public class MyAndroidScanCallback : ScanCallback
          {
              private readonly Dictionary<string, BluetoothDevice> _bluetoothDevices;
      
              public MyAndroidScanCallback(Dictionary<string, BluetoothDevice> devices)
              {
                  _bluetoothDevices = devices;
              }
      
              public override void OnScanResult(ScanCallbackType callbackType, ScanResult result)
              {
                  base.OnScanResult(callbackType, result);
                  _bluetoothDevices[result.Device.Address] = result.Device;
              }
          }
      

      First get hold of the Android adapter in lines 9-11 and create your custom AndroidScanCallback. In the callback I want to add an item to the devices dictionary when they are discovered. Since I’ll get tons of hits on each one, I used the dictionary to make sure that I only have one device per Bluetooth Address.

Line 19 in the BluetoothEnumerationService class is where you can add some filtering and scanner settings. For simplicity, this scanner is going to find all the Bluetooth LE devices that are advertising.
Line 20 is a short delay while the scanner works. I don’t know what the optimal value is. In this scenario, I’m assuming that the device is already on and broadcasting because the scan only lasts 200ms.

Android BLE enumeration

Leave a Reply

Your email address will not be published. Required fields are marked *