{"id":37042431,"url":"https://github.com/nexussays/ble.net","last_synced_at":"2026-01-14T05:00:15.281Z","repository":{"id":65414401,"uuid":"46394015","full_name":"nexussays/ble.net","owner":"nexussays","description":"Cross-platform Bluetooth Low Energy (BLE) library for Android, iOS, and UWP","archived":false,"fork":false,"pushed_at":"2019-08-07T02:24:49.000Z","size":413,"stargazers_count":196,"open_issues_count":35,"forks_count":51,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-10-06T03:43:30.572Z","etag":null,"topics":["android","ble","bluetooth","bluetooth-le","bluetooth-low-energy","csharp","dotnet","dotnet-standard","ios","uwp","xamarin"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nexussays.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-11-18T03:57:31.000Z","updated_at":"2025-09-10T17:11:04.000Z","dependencies_parsed_at":"2023-01-22T10:15:24.707Z","dependency_job_id":null,"html_url":"https://github.com/nexussays/ble.net","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nexussays/ble.net","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nexussays%2Fble.net","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nexussays%2Fble.net/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nexussays%2Fble.net/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nexussays%2Fble.net/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nexussays","download_url":"https://codeload.github.com/nexussays/ble.net/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nexussays%2Fble.net/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28410054,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["android","ble","bluetooth","bluetooth-le","bluetooth-low-energy","csharp","dotnet","dotnet-standard","ios","uwp","xamarin"],"created_at":"2026-01-14T05:00:14.038Z","updated_at":"2026-01-14T05:00:15.269Z","avatar_url":"https://github.com/nexussays.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"http://public.nexussays.com/ble.net/logo_256x256.png\" width=\"128\" height=\"128\" /\u003e\n\n# [ble.net](https://www.fuget.org/packages/ble.net) ![Build status](https://img.shields.io/vso/build/nexussays/ebc6aafa-2931-41dc-b030-7f1eff5a28e5/7.svg?style=flat-square) [![NuGet](https://img.shields.io/nuget/vpre/ble.net.svg?style=flat-square)](https://www.nuget.org/packages/ble.net) [![MPLv2 License](https://img.shields.io/badge/license-MPLv2-blue.svg?style=flat-square)](https://www.mozilla.org/MPL/2.0/)\n\n`ble.net` is a cross-platform Bluetooth Low Energy (aka BLE, aka Bluetooth LE, aka Bluetooth Smart) library to enable simple development of BLE clients on Android, iOS, and UWP/Windows.\n\nIt provides a consistent API across all supported platforms and hides most of the problems and poor API decisions of the native BLE APIs.\n\n## Platform Support\n\n| Platform         |  Version  |\n| ---------------- | :-------: |\n| Xamarin.iOS      | iOS 8.3+  |\n| Xamarin.Android  | API 18+   |\n| Windows 10 (UWP) | 1709+     |\n\n\u003e Note: Currently UWP only supports listening for broadcasts/advertisements, not connecting to devices.\n\n## Quick example\n\nThis is a quick overview of the API and usage; continue reading below for setup instructions and more comprehensive examples.\n\n```csharp\nvar connection = await ble.FindAndConnectToDevice(\n      new ScanFilter().AddAdvertisedService( service ),\n      TimeSpan.FromSeconds( 30 )\n   );\nif(connection.IsSuccessful())\n{\n   try\n   {\n      var gattServer = connection.GattServer;\n      var read = gattServer.ReadCharacteristicValue( service, char1 );\n      await Task.WhenAll( new Task[]\n      {\n         gattServer.WriteCharacteristicValue(\n            service, char1, new Byte[]{/* bytes */}\n         ),\n         gattServer.WriteCharacteristicValue(\n            service, char2, new Byte[]{/* bytes */}\n         ),\n         gattServer.WriteCharacteristicValue(\n            service2, char3, new Byte[]{/* bytes */}\n         )\n      } );\n      // Even though we await \"read\" after awaiting the write calls, the read was\n      // dispatched first and so will have executed prior to the write calls\n      originalValue = await read;\n   }\n   catch(GattException ex)\n   {\n      Debug.WriteLine( ex.ToString() );\n   }\n   finally\n   {\n     // The device will stay connected until you call Disconnect or the connection is lost through some external means.\n     await connection.GattServer.Disconnect();\n   }\n}\n```\n\n## Getting Started\n\n### 1. Install NuGet packages\n\n#### In your shared library project\n\nInstall the `ble.net (API)` package.\n\n```shell\ndotnet add package ble.net\n```\n\n\u003e NOTE: BLE.net switched from targetting `portable-net45+win8` in version `1.1.1`, to `.netstandard1.4` in version `1.2.0`, to `.netstandard2.0` in `1.2.1` (where it will remain for the forseeable future). If you are having problems please [file an issue](https://github.com/nexussays/ble.net/issues/new)\n\n#### In your platform project(s)\n\nInstall the relevant platform package. (See table at the top of the readme for supported versions.)\n\n```shell\ndotnet add package ble.net-android\n```\n\n```shell\ndotnet add package ble.net-ios\n```\n\n```shell\ndotnet add package ble.net-uwp\n```\n\n### 2. Add relevant app permissions\n\n#### Android\n\n```csharp\n[assembly: UsesPermission( Manifest.Permission.Bluetooth )]\n[assembly: UsesPermission( Manifest.Permission.BluetoothAdmin )]\n```\n\n\u003e If you are having issues discovering devices when scanning, try adding coarse location permissions. Android has inconsistent behavior across devices and adding this permission sometimes helps.\n\u003e ```csharp\n\u003e [assembly: UsesPermission( Manifest.Permission.AccessCoarseLocation )]\n\u003e ```\n\u003e Note also that this is a [\"dangerous\" permission](https://developer.android.com/guide/topics/permissions/requesting.html#normal-dangerous) in API 23+, so if you are targeting Android 6.0 or higher you will need to request this permission from the user at runtime.\n\n#### iOS\n\nIf you are only using BLE in the foreground, when your app is active, you don't need to do any further setup for iOS.\n\nIf you need to use BLE in the background:\n1. Add [bluetooth-central](https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html#//apple_ref/doc/uid/TP40013257-CH7-SW6) to background modes\n2. Add a string value for key [NSBluetoothPeripheralUsageDescription](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW20). iOS will display this value in a permission dialog box that the user must approve.\n\n```xml\n\u003c!-- Info.plist --\u003e\n\u003ckey\u003eUIBackgroundModes\u003c/key\u003e\n\u003carray\u003e\n   \u003cstring\u003ebluetooth-central\u003c/string\u003e\n\u003c/array\u003e\n\u003ckey\u003eNSBluetoothPeripheralUsageDescription\u003c/key\u003e\n\u003cstring\u003e[MyAppNameHere] would like to use bluetooth.\u003c/string\u003e\n```\n\n#### UWP\n\n```xml\n\u003c!-- Package.appxmanifest --\u003e\n\u003cCapabilities\u003e\n   \u003cDeviceCapability Name=\"bluetooth\" /\u003e\n\u003c/Capabilities\u003e\n```\n\n### 3. Initialize `BluetoothLowEnergyAdapter` (Android-only)\n\n\u003e There is no initialization needed for iOS or UWP.\n\nIf you want `IBluetoothLowEnergyAdapter.DisableAdapter()` and `IBluetoothLowEnergyAdapter.EnableAdapter()` to work, then in your main `Activity` add:\n\n```csharp\nprotected override void OnCreate( Bundle bundle )\n{\n   // ...\n   BluetoothLowEnergyAdapter.Init( this );\n   // ...\n}\n```\n\nIf you want `IBluetoothLowEnergyAdapter.CurrentState.Subscribe()` to work, then in your calling `Activity` add:\n\n```csharp\nprotected sealed override void OnActivityResult( Int32 requestCode, Result resultCode, Intent data )\n{\n   BluetoothLowEnergyAdapter.OnActivityResult( requestCode, resultCode, data );\n}\n```\n\n### 4. Obtain a reference to `BluetoothLowEnergyAdapter`\n\nEach platform project has a static method `BluetoothLowEnergyAdapter.ObtainDefaultAdapter()` which you call from your platform project and provide to your application code using whatever strategy you prefer (dependency injection, manual reference passing, a singleton or service locator, etc).\n\nSee the sample Xamarin Forms app for real-life examples:\n\n* [Android Xamarin.Forms](src/ble.net.sampleapp-android/MyApplication.cs#L108) example\n* [iOS Xamarin.Forms](src/ble.net.sampleapp-ios/MyApplication.cs#L59) example\n* [UWP Xamarin.Forms](src/ble.net.sampleapp-uwp/MainPage.xaml.cs#L12) example\n\n## API\n\n\u003e See [sample Xamarin Forms app](/src/ble.net.sampleapp/) included in the repo for further examples of how to integrate BLE.net into an app.\n\nAll the examples presume you have obtained the `IBluetoothLowEnergyAdapter` as per the setup notes above, e.g.:\n\n```csharp\nIBluetoothLowEnergyAdapter ble = /* platform-provided adapter from BluetoothLowEnergyAdapter.ObtainDefaultAdapter()*/;\n```\n\n### Control the Bluetooth Adapter on the device\n\n#### Enable Bluetooth\n\n\u003e There are corresponding methods to disable the adapter.\n\n```csharp\nif(ble.AdapterCanBeEnabled \u0026\u0026 ble.CurrentState.IsDisabledOrDisabling()) {\n   await ble.EnableAdapter();\n}\n```\n\n#### See \u0026 Observe Adapter Status\n\n```csharp\nble.CurrentState.Value; // e.g.: EnabledDisabledState.Enabled\n// The adapter implements IObservable\u003cEnabledDisabledState\u003e so you can subscribe to its state\nble.CurrentState.Subscribe( state =\u003e Debug.WriteLine(\"New State: {0}\", state) );\n```\n\n### Scan for advertisements being broadcast by nearby BLE peripherals\n\n```csharp\nvar cts = new CancellationTokenSource(TimeSpan.FromSeconds( 30 ));\nawait ble.ScanForBroadcasts(\n   // providing ScanSettings is optional\n   new ScanSettings()\n   {\n      // Setting the scan mode is currently only applicable to Android and has no effect on other platforms.\n      // If not provided, defaults to ScanMode.Balanced\n      Mode = ScanMode.LowPower,\n\n      // Optional scan filter to ensure that the observer will only receive peripherals\n      // that pass the filter. If you want to scan for everything around, omit the filter.\n      Filter = new ScanFilter()\n      {\n         AdvertisedDeviceName = \"foobar\",\n         AdvertisedManufacturerCompanyId = 76,\n         // peripherals must advertise at-least-one of any GUIDs in this list\n         AdvertisedServiceIsInList = new List\u003cGuid\u003e(){ someGuid },\n      },\n\n      // ignore repeated advertisements from the same device during this scan\n      IgnoreRepeatBroadcasts = false\n   },\n   // Your IObserver\u003cIBlePeripheral\u003e or Action\u003cIBlePeripheral\u003e will be triggered for each discovered\n   // peripheral based on the provided scan settings and filter (if any).\n   ( IBlePeripheral peripheral ) =\u003e\n   {\n      // read the advertising data\n      var adv = peripheral.Advertisement;\n      Debug.WriteLine( adv.DeviceName );\n      Debug.WriteLine( adv.Services.Select( x =\u003e x.ToString() ).Join( \",\" ) );\n      Debug.WriteLine( adv.ManufacturerSpecificData.FirstOrDefault().CompanyName() );\n      Debug.WriteLine( adv.ServiceData );\n\n      // if we found what we needed, stop the scan manually\n      cts.Cancel();\n\n      // perhaps connect to the device (see next example)...\n   },\n   // Provide a CancellationToken to stop the scan, or use the overload that takes a TimeSpan.\n   // If you omit this argument, the scan will timeout after BluetoothLowEnergyUtils.DefaultScanTimeout\n   cts.Token\n);\n\n// scanning has stopped when code reached this point since the scan was awaited\n```\n\nYou can also create a `ScanFilter` using a fluent builder syntax if you prefer that:\n\n```csharp\nnew ScanFilter()\n      .SetAdvertisedDeviceName( \"foobar\" )\n      .SetAdvertisedManufacturerCompanyId( 76 )\n      .AddAdvertisedService( someGuid )\n```\n\n### Connect to a BLE device\n\nIf you have already scanned for and discovered a peripheral and you now want to connect to it:\n\n```csharp\nvar connection = await ble.ConnectToDevice(\n   // The IBlePeripheral to connect to\n   peripheral,\n   // TimeSpan or CancellationToken to stop the\n   // connection attempt.\n   // If you omit this argument, it will use\n   // BluetoothLowEnergyUtils.DefaultConnectionTimeout\n   TimeSpan.FromSeconds( 15 ),\n   // Optional IProgress\u003cConnectionProgress\u003e\n   progress =\u003e Debug.WriteLine(progress)\n);\n\nif(connection.IsSuccessful())\n{\n   var gattServer = connection.GattServer;\n   // ... do things with gattServer here... (see later examples...)\n}\nelse\n{\n   // Do something to inform user or otherwise handle unsuccessful connection.\n   Debug.WriteLine( \"Error connecting to device. result={0:g}\", connection.ConnectionResult );\n   // e.g., \"Error connecting to device. result=ConnectionAttemptCancelled\"\n}\n```\n\nBe sure to disconnect when you are done:\n\n```csharp\nawait gattServer.Disconnect();\n```\n\n#### Connect to a specific device without manually scanning\n\nIn use-cases where you are not scanning for advertisements but rather looking to connect to a specific, known, device:\n\n```csharp\nvar connection = await ble.FindAndConnectToDevice(\n   new ScanFilter()\n      .SetAdvertisedDeviceName( \"foo\" )\n      .SetAdvertisedManufacturerCompanyId( 0xffff )\n      .AddAdvertisedService( guid ),\n   TimeSpan.FromSeconds( 30 ) );\nif(connection.IsSuccessful())\n{\n   // ...\n}\n```\n\n### See \u0026 Observe server connection Status\n\n```csharp\nDebug.WriteLine(gattServer.State); // e.g. ConnectionState.Connected\n// the server implements IObservable\u003cConnectionState\u003e so you can subscribe to its state\ngattServer.Subscribe( state =\u003e\n{\n   if(state == ConnectionState.Disconnected)\n   {\n      Debug.WriteLine(\"Connection Lost\");\n   }\n} );\n```\n\n### Get and store descriptions for GATT GUIDs\n\nYou can provide information for the GUIDs representing services, characteristics, and descriptors with `KnownAttributes`.\n\n```csharp\nvar known = new KnownAttributes();\n\n// You can add descriptions for any desired\n// characteristics, services, and descriptors\nknown.AddService( myGuid1, \"Foo\" );\nknown.AddCharacteristic( myGuid2, \"Bar\" );\nknown.AddDescriptor( myGuid3, \"Baz\" );\n```\n\nThere are shortcuts to add all the attributes that have been adopted by the Bluetooth SIG.\n\n```csharp\nknown.AddAdoptedServices();\nknown.AddAdoptedCharacteristics();\nknown.AddAdoptedDescriptors();\n```\n\nYou can also create a new KnownAttributes with all the above adopted attributes already populated:\n\n```csharp\nknown = KnownAttributes.CreateWithAdoptedAttributes();\n```\n\nThen use it as a lookup as needed.\n\n```csharp\nknown.Get(guid);\nknown.GetDescriptionOrGuid(guid);\n```\n\n### Enumerate all services on the GATT Server\n\n```csharp\nforeach(var guid in await gattServer.ListAllServices())\n{\n   Debug.WriteLine( $\"service: {known.GetDescriptionOrGuid(guid)}\" );\n}\n```\n\n### Enumerate all characteristics of a service\n\n```csharp\nDebug.WriteLine( $\"service: {serviceGuid}\" );\nforeach(var guid in await gattServer.ListServiceCharacteristics( serviceGuid ))\n{\n   Debug.WriteLine( $\"characteristic: {known.GetDescriptionOrGuid(guid)}\" );\n}\n```\n\n### Read a characteristic\n\n```csharp\ntry\n{\n   var value = await gattServer.ReadCharacteristicValue( someServiceGuid, someCharacteristicGuid );\n}\ncatch(GattException ex)\n{\n   Debug.WriteLine( ex.ToString() );\n}\n```\n\n### Listen for notifications on a characteristic\n\n```csharp\nIDisposable notifyHandler;\n\ntry\n{\n   // Will also stop listening when gattServer\n   // is disconnected, so if that is acceptable,\n   // you don't need to store this disposable.\n   notifyHandler = gattServer.NotifyCharacteristicValue(\n      someServiceGuid,\n      someCharacteristicGuid,\n      // IObserver\u003cTuple\u003cGuid, Byte[]\u003e\u003e or IObserver\u003cByte[]\u003e or\n      // Action\u003cTuple\u003cGuid, Byte[]\u003e\u003e or Action\u003cByte[]\u003e\n      bytes =\u003e {/* do something with notification bytes */} );\n}\ncatch(GattException ex)\n{\n   Debug.WriteLine( ex.ToString() );\n}\n\n// ... later, once done listening for notifications ...\nnotifyHandler.Dispose();\n```\n\n### Write to a characteristic\n\n```csharp\ntry\n{\n   // The resulting value of the characteristic is returned. In nearly all cases this\n   // will be the same value that was provided to the write call (e.g. `byte[]{ 1, 2, 3 }`)\n   var value = await gattServer.WriteCharacteristicValue(\n      someServiceGuid,\n      someCharacteristicGuid,\n      new byte[]{ 1, 2, 3 } );\n}\ncatch(GattException ex)\n{\n   Debug.WriteLine( ex.ToString() );\n}\n```\n\n### Logging\n\nBLE.net uses a simple logging library internally. You can add a log \"sink\" to receive each log entry which you can then write to the console or a logging system of your choice.\n\n\u003e Also, each platform's static `BluetoothLowEnergyAdapter.ObtainAdapter()` method has an overload that takes an `ILog`. If no log is provided the default log (`SystemLog.Instance`) is used, but you could provide your own entire logging implementation if you really wanted to.\n\n#### Add a debug log sink on Android\n\n```csharp\nvar logId = Assembly.GetAssembly( GetType() ).GetName().Name;\n// ble.net will log to SystemLog.Instance unless provided a custom logger\nSystemLog.Instance.AddSink(\n   entry =\u003e\n   {\n      var message = entry.FormatAsString();\n      switch(entry.Severity)\n      {\n         case LogLevel.Error:\n            Log.Error( logId, message );\n            break;\n         case LogLevel.Warn:\n            Log.Warn( logId, message );\n            break;\n         case LogLevel.Info:\n            Log.Info( logId, message );\n            break;\n         case LogLevel.Trace:\n         default:\n            Log.Debug( logId, message );\n            break;\n      }\n   } );\n```\n\n#### Add a console log sink on iOS\n\n```csharp\n// ble.net will log to SystemLog.Instance unless provided a custom logger\nSystemLog.Instance.AddSink(\n   entry =\u003e\n   {\n      var message = entry.FormatAsString();\n      if(entry.Severity == LogLevel.Error)\n      {\n         Console.Error.WriteLine( message );\n      }\n      else\n      {\n         Console.Out.WriteLine( message );\n      }\n   } );\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnexussays%2Fble.net","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnexussays%2Fble.net","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnexussays%2Fble.net/lists"}