{"id":14968294,"url":"https://github.com/dotnet-bluetooth-le/dotnet-bluetooth-le","last_synced_at":"2025-05-13T18:09:29.618Z","repository":{"id":1640819,"uuid":"42249040","full_name":"dotnet-bluetooth-le/dotnet-bluetooth-le","owner":"dotnet-bluetooth-le","description":"Bluetooth LE plugin for Xamarin/MAUI, supporting Android, iOS, Mac, Windows","archived":false,"fork":false,"pushed_at":"2025-03-30T10:42:52.000Z","size":10211,"stargazers_count":886,"open_issues_count":287,"forks_count":324,"subscribers_count":57,"default_branch":"master","last_synced_at":"2025-04-25T15:48:32.072Z","etag":null,"topics":["ble","bluetooth","iot","maui","mvvmcross-plugin","xamarin","xamarin-android","xamarin-forms","xamarin-ios"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dotnet-bluetooth-le.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"janusw"}},"created_at":"2015-09-10T14:20:09.000Z","updated_at":"2025-04-20T09:03:50.000Z","dependencies_parsed_at":"2024-01-17T23:58:22.878Z","dependency_job_id":"ce55201c-fda0-4d11-9bad-88dc8fb3248b","html_url":"https://github.com/dotnet-bluetooth-le/dotnet-bluetooth-le","commit_stats":{"total_commits":902,"total_committers":69,"mean_commits":"13.072463768115941","dds":0.7228381374722839,"last_synced_commit":"c9261fc147a65553092df2c5b52c4542035c5dca"},"previous_names":["xabre/xamarin-bluetooth-le"],"tags_count":54,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotnet-bluetooth-le%2Fdotnet-bluetooth-le","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotnet-bluetooth-le%2Fdotnet-bluetooth-le/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotnet-bluetooth-le%2Fdotnet-bluetooth-le/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotnet-bluetooth-le%2Fdotnet-bluetooth-le/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dotnet-bluetooth-le","download_url":"https://codeload.github.com/dotnet-bluetooth-le/dotnet-bluetooth-le/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254000851,"owners_count":21997441,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ble","bluetooth","iot","maui","mvvmcross-plugin","xamarin","xamarin-android","xamarin-forms","xamarin-ios"],"created_at":"2024-09-24T13:39:40.222Z","updated_at":"2025-05-13T18:09:29.596Z","avatar_url":"https://github.com/dotnet-bluetooth-le.png","language":"C#","funding_links":["https://github.com/sponsors/janusw"],"categories":["Components"],"sub_categories":[],"readme":"# \u003cimg src=\"icon_small.png\" width=\"71\" height=\"71\"/\u003e Bluetooth LE plugin for Xamarin \u0026 MAUI\n\nBuild status: [![Build status](https://github.com/dotnet-bluetooth-le/dotnet-bluetooth-le/actions/workflows/dotnet.yml/badge.svg)](https://github.com/dotnet-bluetooth-le/dotnet-bluetooth-le/actions/workflows/dotnet.yml?branch=master)\n\n[Xamarin](https://github.com/xamarin), [MAUI](https://github.com/dotnet/maui) and [MvvMCross](https://github.com/MvvmCross) plugin for accessing the bluetooth functionality. The plugin is loosely based on the BLE implementation of [Monkey Robotics](https://github.com/xamarin/Monkey.Robotics).\n\n**Important Note:** With the term *\"vanilla\"* we mean the non-MvvmCross version, i.e. the pure Xamarin or MAUI plugin. You **can** use it without MvvmCross, if you download the vanilla package.\n\n## Support \u0026 Limitations\n\n[Release Notes](doc/changelog.md)\n\n| Platform        | Version           | Limitations |\n| --------------- | ----------------- | ----------- |\n| Xamarin.Android | 4.3               |             |\n| Xamarin.iOS     | 7.0               |             |\n| Xamarin.Mac     | 10.9 (Mavericks)  | \u003e= 2.1.0    |\n| Xamarin.UWP     | 1709 - 10.0.16299 | \u003e= 2.2.0    |\n| MAUI (Android, iOS, Mac, WinUI) |   | \u003e= 3.0.0    |\n\n## Nuget Packages\n\n| package              | stable    | beta      | downloads |\n| ---------------------|:---------:|:---------:|:---------:|\n| Plugin.BLE           | [![NuGet](https://img.shields.io/nuget/v/Plugin.BLE.svg?style=flat)](https://www.nuget.org/packages/Plugin.BLE) | [![NuGet Beta](https://img.shields.io/nuget/vpre/Plugin.BLE.svg?style=flat)](https://www.nuget.org/packages/Plugin.BLE) | [![Downloads](https://img.shields.io/nuget/dt/Plugin.BLE.svg)](https://www.nuget.org/packages/Plugin.BLE)\n| MvvmCross.Plugin.BLE | [![NuGet MvvMCross](https://img.shields.io/nuget/v/MvvmCross.Plugin.BLE.svg?style=flat)](https://www.nuget.org/packages/MvvmCross.Plugin.BLE) | [![NuGet MvvMCross Beta](https://img.shields.io/nuget/vpre/MvvmCross.Plugin.BLE.svg?style=flat)](https://www.nuget.org/packages/MvvmCross.Plugin.BLE) | [![Downloads](https://img.shields.io/nuget/dt/MvvmCross.Plugin.BLE.svg)](https://www.nuget.org/packages/MvvmCross.Plugin.BLE)\n\n## Installation\n\n**Vanilla**\n\n```\n// stable\nInstall-Package Plugin.BLE\n// or pre-release\nInstall-Package Plugin.BLE -Pre\n```\n\n**MvvmCross**\n\n```\nInstall-Package MvvmCross.Plugin.BLE\n// or\nInstall-Package MvvmCross.Plugin.BLE -Pre\n```\n\n## Permissions\n\n### Android\n\nAdd these permissions to AndroidManifest.xml. For Marshmallow and above, please follow [Requesting Runtime Permissions in Android Marshmallow](https://devblogs.microsoft.com/xamarin/requesting-runtime-permissions-in-android-marshmallow/) and don't forget to prompt the user for the location permission.\n\n```xml\n\u003cuses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" /\u003e\n\u003cuses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" /\u003e\n\u003cuses-permission android:name=\"android.permission.BLUETOOTH\" /\u003e\n\u003cuses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" /\u003e\n```\n\nAndroid 12 and above may require one or more of the following additional runtime permissions, depending on which features of the library you are using (see [the android Bluetooth permissions documentation](https://developer.android.com/guide/topics/connectivity/bluetooth/permissions))\n```xml\n\u003cuses-permission android:name=\"android.permission.BLUETOOTH_SCAN\" /\u003e\n\u003cuses-permission android:name=\"android.permission.BLUETOOTH_CONNECT\" /\u003e\n\u003cuses-permission android:name=\"android.permission.BLUETOOTH_ADVERTISE\" /\u003e\n```\n\nAdd this line to your manifest if you want to declare that your app is available to BLE-capable devices **only**:\n```xml\n\u003cuses-feature android:name=\"android.hardware.bluetooth_le\" android:required=\"true\"/\u003e\n````\n\n### iOS\n\nOn iOS you must add the following keys to your `Info.plist`\n\n```xml\n\u003ckey\u003eUIBackgroundModes\u003c/key\u003e\n\u003carray\u003e\n    \u003c!--for connecting to devices (client)--\u003e\n    \u003cstring\u003ebluetooth-central\u003c/string\u003e\n    \u003c!--for server configurations if needed--\u003e\n    \u003cstring\u003ebluetooth-peripheral\u003c/string\u003e\n\u003c/array\u003e\n\n\u003c!--Description of the Bluetooth request message (required on iOS 10, deprecated)--\u003e\n\u003ckey\u003eNSBluetoothPeripheralUsageDescription\u003c/key\u003e\n\u003cstring\u003eYOUR CUSTOM MESSAGE\u003c/string\u003e\n\n\u003c!--Description of the Bluetooth request message (required on iOS 13)--\u003e\n\u003ckey\u003eNSBluetoothAlwaysUsageDescription\u003c/key\u003e\n\u003cstring\u003eYOUR CUSTOM MESSAGE\u003c/string\u003e\n````\n\n### MacOS\n\nOn MacOS (version 11 and above) you must add the following keys to your `Info.plist`:\n\n```xml\n\u003c!--Description of the Bluetooth request message--\u003e\n\u003ckey\u003eNSBluetoothAlwaysUsageDescription\u003c/key\u003e\n\u003cstring\u003eYOUR CUSTOM MESSAGE\u003c/string\u003e\n````\n\n### UWP\n\nAdd this line to the Package Manifest (.appxmanifest):\n\n```xml\n\u003cDeviceCapability Name=\"bluetooth\" /\u003e\n```\n\n## Sample app\n\nWe provide a sample Xamarin.Forms app, that is a basic bluetooth LE scanner. With this app, it's possible to\n\n- check the BLE status\n- discover devices\n- connect/disconnect\n- discover the services\n- discover the characteristics\n- see characteristic details\n- read/write and register for notifications of a characteristic\n\nHave a look at the code and use it as starting point to learn about the plugin and play around with it.\n\n## Usage  \n\n**Vanilla**\n\n```csharp\nvar ble = CrossBluetoothLE.Current;\nvar adapter = CrossBluetoothLE.Current.Adapter;\n```\n\n**MvvmCross**\n\nThe MvvmCross plugin registers `IBluetoothLE` and  `IAdapter` as lazy initialized singletons. You can resolve/inject them as any other MvvmCross service. You don't have to resolve/inject both. It depends on your use case.\n\n```csharp\nvar ble = Mvx.Resolve\u003cIBluetoothLE\u003e();\nvar adapter = Mvx.Resolve\u003cIAdapter\u003e();\n```\nor\n```csharp\nMyViewModel(IBluetoothLE ble, IAdapter adapter)\n{\n    this.ble = ble;\n    this.adapter = adapter;\n}\n```\n\nPlease make sure you have this code in your LinkerPleaseLink.cs file\n\n```csharp\npublic void Include(MvvmCross.Plugins.BLE.Plugin plugin)\n{\n    plugin.Load();\n}\n```\n\n### IBluetoothLE\n#### Get the bluetooth status\n```csharp\nvar state = ble.State;\n```\nYou can also listen for State changes. So you can react if the user turns on/off bluetooth on your smartphone.\n```csharp\nble.StateChanged += (s, e) =\u003e\n{\n    Debug.WriteLine($\"The bluetooth state changed to {e.NewState}\");\n};\n```\n\n\n### IAdapter\n#### Scan for devices\n```csharp\nadapter.DeviceDiscovered += (s,a) =\u003e deviceList.Add(a.Device);\nawait adapter.StartScanningForDevicesAsync();\n```\n\n#### Scan Filtering\n```csharp\nvar scanFilterOptions = new ScanFilterOptions();\nscanFilterOptions.ServiceUuids = new [] {guid1, guid2, etc}; // cross platform filter\nscanFilterOptions.ManufacturerDataFilters = new [] { new ManufacturerDataFilter(1), new ManufacturerDataFilter(2) }; // android only filter\nscanFilterOptions.DeviceAddresses = new [] {\"80:6F:B0:43:8D:3B\",\"80:6F:B0:25:C3:15\",etc}; // android only filter\nawait adapter.StartScanningForDevicesAsync(scanFilterOptions);\n```\n\n##### ScanTimeout\nSet `adapter.ScanTimeout` to specify the maximum duration of the scan.\n\n##### ScanMode\nSet `adapter.ScanMode` to specify scan mode. It must be set **before** calling `StartScanningForDevicesAsync()`. Changing it while scanning, will not affect the current scan.\n\n#### Connect to device\n`ConnectToDeviceAsync` returns a Task that finishes if the device has been connected successful. Otherwise a `DeviceConnectionException` gets thrown.\n\n```csharp\ntry\n{\n    await _adapter.ConnectToDeviceAsync(device);\n}\ncatch(DeviceConnectionException e)\n{\n    // ... could not connect to device\n}\n```\n\n#### Connect to known Device\n`ConnectToKnownDeviceAsync` can connect to a device with a given GUID. This means that if the device GUID is known, no scan is necessary to connect to a device. This can be very useful for a fast background reconnect.\nAlways use a cancellation token with this method.\n- On **iOS** it will attempt to connect indefinitely, even if out of range, so the only way to cancel it is with the token.\n- On **Android** this will throw a GATT ERROR in a couple of seconds if the device is out of range.\n\n```csharp\ntry\n{\n    await _adapter.ConnectToKnownDeviceAsync(guid, cancellationToken);\n}\ncatch(DeviceConnectionException e)\n{\n    // ... could not connect to device\n}\n```\n\n#### Get services\n```csharp\nvar services = await connectedDevice.GetServicesAsync();\n```\nor get a specific service:\n```csharp\nvar service = await connectedDevice.GetServiceAsync(Guid.Parse(\"ffe0ecd2-3d16-4f8d-90de-e89e7fc396a5\"));\n```\n\n#### Get characteristics\n```csharp\nvar characteristics = await service.GetCharacteristicsAsync();\n```\nor get a specific characteristic:\n```csharp\nvar characteristic = await service.GetCharacteristicAsync(Guid.Parse(\"d8de624e-140f-4a22-8594-e2216b84a5f2\"));\n```\n\n#### Read characteristic\n```csharp\nvar bytes = await characteristic.ReadAsync();\n```\n\n#### Write characteristic\n```csharp\nawait characteristic.WriteAsync(bytes);\n```\n\n#### Characteristic notifications\n```csharp\ncharacteristic.ValueUpdated += (o, args) =\u003e\n{\n    var bytes = args.Characteristic.Value;\n};\n\nawait characteristic.StartUpdatesAsync();\n\n```\n\n#### Get descriptors\n```csharp\nvar descriptors = await characteristic.GetDescriptorsAsync();\n```\n\n#### Read descriptor\n```csharp\nvar bytes = await descriptor.ReadAsync();\n```\n\n#### Write descriptor\n```csharp\nawait descriptor.WriteAsync(bytes);\n```\n\n#### Get System Devices\n\nReturns all BLE devices connected or bonded (only Android) to the system. In order to use the device in the app you have to first call ConnectAsync.\n- For iOS the implementation uses get [retrieveConnectedPeripherals(services)](https://developer.apple.com/reference/corebluetooth/cbcentralmanager/1518924-retrieveconnectedperipherals)\n- For Android this function merges the functionality of the following API calls:\n    - [getConnectedDevices](https://developer.android.com/reference/android/bluetooth/BluetoothManager.html#getConnectedDevices(int))\n    - [getBondedDevices()](https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getBondedDevices())\n\n\n```csharp\n\nvar systemDevices = adapter.GetSystemConnectedOrPairedDevices();\n\nforeach(var device in systemDevices)\n{\n    await _adapter.ConnectToDeviceAsync(device);\n}\n\n```\n## Caution! Important remarks / API limitations\n\nThe BLE API implementation (especially on **Android**) has the following limitations:\n\n- *Characteristic/Descriptor Write*: make sure you call characteristic.**WriteAsync**(...) from the **main thread**, failing to do so will most probably result in a GattWriteError.\n- *Sequential calls*: **Always** wait for the previous BLE command to finish before invoking the next. The Android API needs its calls to be serial, otherwise calls that do not wait for the previous ones will fail with some type of GattError. A more explicit example: if you call this in your view lifecycle (onAppearing etc) all these methods return **void** and 100% don't guarantee that any await bleCommand() called here will be truly awaited by other lifecycle methods.\n- *Scan with services filter*: On **specifically Android 4.3** the *scan services filter does not work* (due to the underlying android implementation). For android 4.3 you will have to use a workaround and scan without a filter and then manually filter by using the advertisement data (which contains the published service GUIDs).\n\n## Best practice\n\n### API\n- Surround Async API calls in try-catch blocks. Most BLE calls can/will throw an exception in certain cases, this is especially true for Android. We will try to update the xml doc to reflect this.\n```csharp\n    try\n    {\n        await _adapter.ConnectToDeviceAsync(device);\n    }\n    catch(DeviceConnectionException ex)\n    {\n        //specific\n    }\n    catch(Exception ex)\n    {\n        //generic\n    }\n```\n\n- **Avoid caching of Characteristic or Service instances between connection sessions**. This includes saving a reference to them in your class between connection sessions etc. After a device has been disconnected all Service \u0026 Characteristic instances become **invalid**. Always **use GetServiceAsync and GetCharacteristicAsync to get a valid instance**.\n\n### General BLE iOS, Android\n\n- Scanning: Avoid performing BLE device operations like Connect, Read, Write etc while scanning for devices. Scanning is battery-intensive.\n    - Try to stop scanning before performing device operations (connect/read/write/etc).\n    - Try to stop scanning as soon as you find the desired device.\n    - Never scan on a loop, and set a time limit on your scan.\n\n## How to build the nuget package\n\n1) Build\n\n    Open a console, change to the folder \"dotnet-bluetooth-le/.build\" and run `cake`.\n\n2) pack the nuget\n\n    `nuget pack ../Source/Plugin.BLE/Plugin.BLE.csproj`\n\n    `nuget pack ../Source/MvvmCross.Plugins.BLE/MvvmCross.Plugins.BLE.csproj`\n\n\n\n## Extended topics\n\n- [How to set custom trace method?](doc/howto_custom_trace.md)\n- [Characteristic Properties](doc/characteristics.md)\n- [Scan Mode Mapping](doc/scanmode_mapping.md)\n- [iOS state restoration (basic support)](doc/ios_state_restoration.md)\n\n\n## Useful Links\n\n- [Bluetooth Core Specification v4.2 (2014)](https://www.bluetooth.com/specifications/specs/core-specification-4-2/)\n- [Bluetooth Core Specification v5.4 (2023)](https://www.bluetooth.com/specifications/specs/core-specification-5-4/)\n- [Android Bluetooth LE guideline](https://developer.android.com/guide/topics/connectivity/bluetooth-le.html)\n- [iOS CoreBluetooth Best Practices](https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/BestPracticesForInteractingWithARemotePeripheralDevice/BestPracticesForInteractingWithARemotePeripheralDevice.html)\n- [iOS CoreBluetooth Background Modes](https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html#//apple_ref/doc/uid/TP40013257-CH7-SW7)\n- [Monkey Robotics](https://github.com/xamarin/Monkey.Robotics)\n\n## How to contribute\n\nWe usually do our development work on a branch with the name of the milestone. So please base your pull requests on the currently open development branch.\n\n## Licence\n\n[Apache 2.0](https://github.com/dotnet-bluetooth-le/dotnet-bluetooth-le/blob/master/LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdotnet-bluetooth-le%2Fdotnet-bluetooth-le","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdotnet-bluetooth-le%2Fdotnet-bluetooth-le","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdotnet-bluetooth-le%2Fdotnet-bluetooth-le/lists"}