Forum Libraries, Components, and Plugins
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

Why doesn't Xamarin have Bluetooth BLE support?

I was quite surprised when I started digging into getting a Bluetooth BLE device connected to my Xamarin/iOS application to find myself looking at a bunch of fairly uninspiring nuget packages. Bluetooth is standard and common, and I would have expected Xamarin to have at least some basic support by now, perhaps in Xamarin.Essentials.

The nuget packages I found all seemed to be either old or to carry way too much baggage. To go through a couple of examples:

The promising Plugin.BluetoothLE has a big message saying that it is migrating into the Shiny framework. Throughout my whole project, I have made a big effort to avoid frameworks that force you to do things a certain way and I don't really want to start now.

XamarinBluetoothLE also looked promising but I can't get any of it to build and so far am struggling to figure out the best way of getting it into my project without unwanted dependencies across my projects.

I guess it will be too late for me but is Xamarin planning any Bluetooth support? Or can anyone recommend a lightweight Bluetooth library?

Any advice would be very welcome.

Kind wishes - Patrick

Best Answers

  • EasyGoingPatEasyGoingPat GBMember ✭✭✭
    Accepted Answer

    In answer to my own question above, I have worked out how to do this. This may not be the best method but does what is required.

    The following code uses nuget package https://github.com/xabre/xamarin-bluetooth-le to search for nearby BluetoothLE heart-rate devices. Note that the code is nowhere near complete; it just shows the main steps. And it is important always to do something with exceptions with Bluetooth because you will get some.

    // These are the main entry points to the API.
    Plugin.BLE.Abstractions.Contracts.IBluetoothLE BLE;
    Plugin.BLE.Abstractions.Contracts.IAdapter BLEAdapter;
    
    // These event handlers need to be attached.
    BLE.StateChanged += BLE_OnStateChanged;
    BLEAdapter.ScanTimeoutElapsed += BLEAdapter_ScanTimeoutElapsed;
    BLEAdapter.DeviceDiscovered += BLEAdapter_OnDeviceDiscovered;
    BLEAdapter.DeviceDisconnected += BLEAdapter_OnDeviceDisconnected;
    BLEAdapter.DeviceConnectionLost += BLEAdapter_OnDeviceConnectionLost;
    
    // My own simple class to hold records detailing discovered devices.
    class BLEDeviceRecord
    {
        public BLEDeviceRecord( IDevice device )
        {
            Device = device;
        }
    
        public IDevice Device { get; private set; }
        public Guid UniqueId => Device.Id;
        public bool IsConnected => Device.State == DeviceState.Connected;
        public int Rssi => Device.Rssi;
        public string Name => Device.Name;
    }
    
    // A collection of the discovered devices.
    ObservableCollection<BLEDeviceRecord> BluetoothDevices { get; private set; } = new ObservableCollection<BLEDeviceRecord>();
    
    // Start the scan; results come via the event handlers.
    void BuildListOfBluetoothDevices()
    {
        BluetoothDevices.Clear();
        CancellationTokenSource cts = new CancellationTokenSource();
        BLEAdapter.ScanMode = ScanMode.LowLatency;
        await BLEAdapter.StartScanningForDevicesAsync( cts.Token );
    }
    
    // Once you have devices in the above collection, look for the heart-rate ones like this.
    void SearchForHeartRateCharacteristic()
    {
        // Obtain this from the Bluetooth GATT Specifications: 
        const int HeartRateUuid = 0x2A37;
    
        Guid heartRateMeasurementGuid = HeartRateUuid.UuidFromPartial();
        foreach( IService service in services )
        {
            var characteristics = await service.GetCharacteristicsAsync();
            foreach( ICharacteristic characteristic in characteristics )
            {
                if( characteristic.Id == heartRateGuid )
                {
                    // The current IService contains an ICharacteristic that is a heart-rate measurement.                                                   
                }
            }
        }
    }
    
    

    The Bluetooth GATT Specifications can be found here: [https://bluetooth.com/specifications/gatt/characteristics/]( GATT
    Characteristics)

    This could easily be generalised to search for any other Characteristic in the Bluetooth Specification.

    Hope it helps someone.

Answers

  • EasyGoingPatEasyGoingPat GBMember ✭✭✭

    @LeonLu Yes, xamarin-bluetooth-le does indeed look like an excellent choice. It's a shame they chose to tangle their example code with MvvmCross, a framework I am not using, but otherwise I am making good progress with it so far.

    You have saved me a lot of time messing about trying to understand the other packages I had found, so thank you for the suggestion!

    • Patrick
  • EasyGoingPatEasyGoingPat GBMember ✭✭✭

    @LeonLu

    I'm doing okay with the xamarin-bluetooth-le package that you recommended but I seem to have hit a chicken-or-egg situation. I am wanting to get a connected heart-rate service. I can get a specific Service using its GUID by calling...

    var service = await connectedDevice.GetServiceAsync(Guid.Parse("ffe0ecd2-3d16-4f8d-90de-e89e7fc396a5"));

    Or I can get all services by calling...

    var services = await connectedDevice.GetServicesAsync();

    I can then follow exactly the same pattern for characteristics - either get all Characteristics or pick a specific one by using its GUID.

    In the example code for xamarin-bluetooth-le, there are classes for KnownServices and KnownCharacteristics. The problem is that these lists are private to their respective classes and only way to do a look-up is by passing the GUID.

    I'm obviously missing something but this seems like the wrong way round. What I need is some way to say something like this...

    var BluetoothAdapter.FindAllServicesThatContainCharacteristic( KnownCharacteristic.HeartRate );

    This is obviously not real code but hopefully you can see what I am getting at.

    How do I find out these mysterious GUIDs?

  • EasyGoingPatEasyGoingPat GBMember ✭✭✭
    Accepted Answer

    In answer to my own question above, I have worked out how to do this. This may not be the best method but does what is required.

    The following code uses nuget package https://github.com/xabre/xamarin-bluetooth-le to search for nearby BluetoothLE heart-rate devices. Note that the code is nowhere near complete; it just shows the main steps. And it is important always to do something with exceptions with Bluetooth because you will get some.

    // These are the main entry points to the API.
    Plugin.BLE.Abstractions.Contracts.IBluetoothLE BLE;
    Plugin.BLE.Abstractions.Contracts.IAdapter BLEAdapter;
    
    // These event handlers need to be attached.
    BLE.StateChanged += BLE_OnStateChanged;
    BLEAdapter.ScanTimeoutElapsed += BLEAdapter_ScanTimeoutElapsed;
    BLEAdapter.DeviceDiscovered += BLEAdapter_OnDeviceDiscovered;
    BLEAdapter.DeviceDisconnected += BLEAdapter_OnDeviceDisconnected;
    BLEAdapter.DeviceConnectionLost += BLEAdapter_OnDeviceConnectionLost;
    
    // My own simple class to hold records detailing discovered devices.
    class BLEDeviceRecord
    {
        public BLEDeviceRecord( IDevice device )
        {
            Device = device;
        }
    
        public IDevice Device { get; private set; }
        public Guid UniqueId => Device.Id;
        public bool IsConnected => Device.State == DeviceState.Connected;
        public int Rssi => Device.Rssi;
        public string Name => Device.Name;
    }
    
    // A collection of the discovered devices.
    ObservableCollection<BLEDeviceRecord> BluetoothDevices { get; private set; } = new ObservableCollection<BLEDeviceRecord>();
    
    // Start the scan; results come via the event handlers.
    void BuildListOfBluetoothDevices()
    {
        BluetoothDevices.Clear();
        CancellationTokenSource cts = new CancellationTokenSource();
        BLEAdapter.ScanMode = ScanMode.LowLatency;
        await BLEAdapter.StartScanningForDevicesAsync( cts.Token );
    }
    
    // Once you have devices in the above collection, look for the heart-rate ones like this.
    void SearchForHeartRateCharacteristic()
    {
        // Obtain this from the Bluetooth GATT Specifications: 
        const int HeartRateUuid = 0x2A37;
    
        Guid heartRateMeasurementGuid = HeartRateUuid.UuidFromPartial();
        foreach( IService service in services )
        {
            var characteristics = await service.GetCharacteristicsAsync();
            foreach( ICharacteristic characteristic in characteristics )
            {
                if( characteristic.Id == heartRateGuid )
                {
                    // The current IService contains an ICharacteristic that is a heart-rate measurement.                                                   
                }
            }
        }
    }
    
    

    The Bluetooth GATT Specifications can be found here: [https://bluetooth.com/specifications/gatt/characteristics/]( GATT
    Characteristics)

    This could easily be generalised to search for any other Characteristic in the Bluetooth Specification.

    Hope it helps someone.

Sign In or Register to comment.