Skip to content
Introducing AI Conversations: Natural Language Interaction for Your Apps! Learn More

BluetoothLE Releases

Feature
L2CapChannelExtensions.SendFile(...) — new file-transfer helper on top of an open L2CapChannel with HTTP-transfer-style progress metrics (bytes-per-second, percent-complete, estimated time remaining). Overloads accept either a file path (length auto-detected) or an arbitrary Stream with an optional totalBytes. Progress callbacks fire ~every 2s plus a final 100% emission on completion. The new Shiny.BluetoothLE.TransferProgress record mirrors Shiny.Net.Http.TransferProgress so consumers have an identical mental model across HTTP and L2CAP transfers. Lives in Shiny.BluetoothLE.Common, shared with the hosting library.
Feature
L2CAP CoC central-role support shipped via the optional ICanL2Cap capability on IPeripheral. Call peripheral.OpenL2CapChannel(psm, secure) (or the safe TryOpenL2CapChannel(...) extension on the base IPeripheral) to open a streaming channel to a peripheral that has published a PSM. Supported on iOS, Mac Catalyst, macOS (CoreBluetooth CBPeripheral.OpenL2CapChannel), Android API 29+ (BluetoothDevice.CreateL2capChannel / CreateInsecureL2capChannel), and Linux (BlueZ — raw AF_BLUETOOTH / BTPROTO_L2CAP / SOCK_SEQPACKET socket; LE dynamic PSMs ≥ 0x80 do not need CAP_NET_RAW). On Apple platforms the secure flag is ignored — security is determined by how the peripheral published the channel. On Linux the flag toggles BT_SECURITY_LOW/MEDIUM via setsockopt(SOL_BLUETOOTH, BT_SECURITY).
Enhancement
The public L2CapChannel record moved into Shiny.BluetoothLE.Common (namespace Shiny.BluetoothLE) so both central and hosting libraries share one type. The record now implements IDisposable with an optional OnDispose hook for closing streams and disposing sockets.
Fix Android
Shiny.BluetoothLE.Extensions.ListenForData(BluetoothSocket) now reads from socket.InputStream (was incorrectly reading OutputStream) and emits a right-sized copy of each chunk instead of the full 8 KB buffer. The observable now completes on EOF and surfaces read errors via OnError.
Fix iOS
Shiny.BluetoothLE.Extensions.ListenForData(NSInputStream) now drains all bytes available per HasBytesAvailable event, emits a right-sized copy per read (was leaking the full 8 KB shared buffer to every subscriber), and completes on NSStreamEvent.EndEncountered.
Feature
macOS support added via CoreBluetooth (central role) - Shiny.BluetoothLE
Feature
Linux support added via BlueZ / D-Bus (central role) - new Shiny.BluetoothLE.Linux package
Feature
Blazor WebAssembly (Web) support added via the browser Web Bluetooth API - new Shiny.BluetoothLE.Blazor package. Central role only; scans require a user gesture, HTTPS, and a Chromium-based browser
Fix Windows
Fix BLE state cleanup after disconnect and reconnect - properly releases GATT resources and disposes stale peripherals
Fix Android
Fix the classic “status 133 after a few reconnects” trap — Connect() now closes any prior BluetoothGatt before opening a new client, so reconnect loops no longer leak GATT clients into Android’s per-app limit.
Fix Android
Connection state and connection-failure observables are now replay-safe (BehaviorSubject / time-windowed ReplaySubject), so subscribers that hook up immediately after calling Connect() no longer miss the resulting state change or failure.
Fix Android
OnConnectionStateChange now dispatches subscriber notifications off the single-threaded GATT binder callback thread, removing a class of deadlocks where awaiting subscribers blocked further BLE callbacks.
Fix Android
Notifier teardown re-resolves the characteristic against the current BluetoothGatt instead of a captured (possibly closed) reference, preventing spurious status 133 errors on the next operation after a disconnect/reconnect cycle.
Fix Android
Starting a scan no longer evicts peripherals that are currently in the Connecting state.
Fix iOS
IBleManager.GetKnownPeripheral(uuid) now calls CoreBluetooth’s RetrievePeripheralsWithIdentifiers, so callers can reconnect to a previously-paired device by UUID after a process restart without first running a scan.
Fix iOS
IBleManager.GetConnectedPeripherals() now seeds from RetrieveConnectedPeripherals so devices connected by other apps or restored sessions are visible.
Fix iOS
Auto-reconnect now issues CancelPeripheralConnection before each retry (iOS otherwise holds the previous pending connection slot) and additionally retries on FailedToConnectPeripheral, fixing cold-start failures that previously never retried because no Disconnected event was emitted.
Fix Windows
Service and characteristic lookups on the hot path now use BluetoothCacheMode.Uncached, so a reconnect always re-discovers fresh GattDeviceService / GattCharacteristic handles instead of silently operating on dead, OS-cached ones.
Fix Windows
Peripheral connections now acquire a GattSession with MaintainConnection = true, so the OS keeps the LE link up across idle periods and automatically re-establishes it when a device returns in range — eliminating “the connection dropped while idle” symptoms.
Fix Windows
IPeripheral references now survive a disconnect/reconnect cycle. Previously the manager replaced the wrapper instance on every reconnect, leaving any caller-held reference dead with “Device is disposed” errors. The wrapper now refreshes its underlying BluetoothLEDevice in place.
Fix Windows
A transient ConnectionStatus = Disconnected dip immediately after a successful service discovery no longer cancels the connect attempt — the connect now succeeds, and a real subsequent disconnect is handled by the normal ConnectionStatusChanged path.
Feature
Windows support added (No Background Support at this time)
Enhancement
ManagedScanResult is now passed with the full advertisement data in case user needs access to native internals
Enhancement Android
Improved manufacturer data parsing in ad data
Fix Android
BLE Delegate now reports proper status changes for enabled
Fix
ManagedScan now uses thread safe BindingList
Fix Android
BLE scan now disables legacy scanning for new android versions
Fix
More thread safetying for ManagedScan
Fix Android
Ensure peripheral cleanup matches iOS
Fix Android
BLE Delegate was not responding with Available when adapter was reenabled
Fix Android
Disable legacy scanner on newer Android versions
Fix Android
ManagedScanResult now has a property for the raw advertisement data
Fix Android
Additional thread safety on managed scan events
Fix Android
IBleDelegate now reports adapter state properly
Fix Android
BleDelegate does not fire for disconnected event on Android
Fix Android
Unsubscribing from a connection may be temporarily unstable if sub/unsub is performed rapidly
Fix Android
Reduce logging severity for characteristic events
Fix iOS
IsScanning flag was not being set
Fix
Characteristic extension (GetAllCharacteristics) was only returning characteristics from last service
Fix
Characteristic async extension signature fixes
Enhancement
BLE manager now allows you to check current permissions without requesting
Enhancement Android
RequestAccess(bool connect) now allows you to additionally request access to GATT connections (defaults to true). This allows Shiny to use Android API 31 properly. It will always ask for scan permissions.
BREAKING Android
Adapter control is no longer support through the Shiny API, but you do have raw access to the native adapter if needed
BREAKING
Managed scan now require you to set scan configuration values in Start instead of the constructor & property setters
BREAKING
The API has been simplified and no longer requires you to maintain (and refresh) instances of services/characteristics/descriptors
BREAKING
Managed peripheral is now gone. This functionality is now built into the main API.
BREAKING Enhancement Android
Android MTU requests are moved to the IPeripheral.Connect(AndroidConnectionConfig)