Document DB v12 - Improved Interceptors with Soft Delete Integration, AI protections, & Admin UI with Aspire Integration!How!?
BluetoothLE Releases
5.2.4 - July 20, 2026
Section titled “5.2.4 - July 20, 2026”FixiOS
A disconnect that races an in-flight GATT operation no longer permanently deadlocks the BLE operation queue. CoreBluetooth delegate callbacks are the only thing that completes a queued operation, and a dead peripheral never fires them again — so an operation parked on one (most visibly a
WriteCharacteristic(withResponse: false) waiting on canSendWriteWithoutResponse flow control) held the operation lock forever, blocking every subsequent operation across all peripherals until the app was restarted. Every queued Apple operation — service/characteristic/descriptor discovery, reads, both write modes, and ReadRssi — now aborts with a BleException when the peripheral disconnects mid-operation, releasing the lock so reconnect and retry work normally. Applies to iOS, Mac Catalyst, and macOS.FixAndroid
The same disconnect-mid-operation deadlock is fixed on Android. Once the link drops, the
BluetoothGatt client is closed and its callbacks never fire again, so a parked read, write-with-response, descriptor read/write (including the CCCD write that re-arms notifications on reconnect), service discovery, or ReadRssi held the operation lock indefinitely. These now abort with a BleException on disconnect — including the explicit disconnect path, where Gatt.Close() suppresses the framework’s own state-change callback. Write-without-response was never affected on Android; it does not wait on flow control.5.1.0 - June 28, 2026
Section titled “5.1.0 - June 28, 2026”FixAndroid
NotifyCharacteristic no longer drops the first notification(s) for peripherals that stream data the instant the subscription is enabled. The notification listener is now wired up before the CCCD descriptor write turns the peripheral on (it was previously hooked only after the write was acknowledged, leaving a window where the earliest OnCharacteristicChanged callbacks were lost).FixiOS
NotifyCharacteristic now subscribes to characteristic updates before calling SetNotifyValue(true), closing the same notify-before-listen race on Apple platforms (iOS, Mac Catalyst, macOS).5.0.1 - June 27, 2026
Section titled “5.0.1 - June 27, 2026”FixAndroid
Scanning now discovers devices again. A previous change forced
setLegacy(false) alone on Android 8+, which on most chipsets suppresses the legacy advertisements that virtually all BLE peripherals send. Scans now report both legacy AND Bluetooth 5 extended advertisements automatically, by pairing setLegacy(false) with all-PHY scanning and only enabling it when the chipset reports IsLeExtendedAdvertisingSupported (otherwise falling back to a legacy scan). Force a legacy-only scan with new AndroidScanConfig(IncludeExtendedAdvertisements: false).FixAndroid
RequestAccess() no longer crash the app ~5 seconds after the OS permission dialog appears. The internal 5-second guard was incorrectly timing the user’s interaction with the dialog; it now only bounds the wait for an Activity to become available, so the user may take as long as they like to respond.5.0.0 - June 20, 2026
Section titled “5.0.0 - June 20, 2026”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.FixAndroid
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.FixiOS
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.BluetoothLEFeature
Linux support added via BlueZ / D-Bus (central role) - new
Shiny.BluetoothLE.Linux packageFeature
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 browserFixWindows
Fix BLE state cleanup after disconnect and reconnect - properly releases GATT resources and disposes stale peripherals
FixAndroid
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.FixAndroid
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.FixAndroid
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.FixAndroid
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.FixAndroid
Starting a scan no longer evicts peripherals that are currently in the
Connecting state.FixiOS
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.FixiOS
IBleManager.GetConnectedPeripherals() now seeds from RetrieveConnectedPeripherals so devices connected by other apps or restored sessions are visible.FixiOS
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.FixWindows
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.FixWindows
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.FixWindows
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.FixWindows
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.4.0.0 - March 26, 2026
Section titled “4.0.0 - March 26, 2026”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
EnhancementAndroid
Improved manufacturer data parsing in ad data
Fix
ManagedScan now uses thread safe BindingList
FixAndroid
BLE scan now disables legacy scanning for new android versions
FixAndroid
BLE Delegate was not responding with Available when adapter was reenabled
3.3.4 - April 22, 2024
Section titled “3.3.4 - April 22, 2024”FixAndroid
Disable legacy scanner on newer Android versions
FixAndroid
ManagedScanResult now has a property for the raw advertisement data
FixAndroid
Additional thread safety on managed scan events
3.3.0 - March 18, 2024
Section titled “3.3.0 - March 18, 2024”FixAndroid
IBleDelegate now reports adapter state properly
FixAndroid
Unsubscribing from a connection may be temporarily unstable if sub/unsub is performed rapidly
FixAndroid
Reduce logging severity for characteristic events
Fix
Characteristic extension (GetAllCharacteristics) was only returning characteristics from last service
3.2.0 - December 8, 2023
Section titled “3.2.0 - December 8, 2023”Enhancement
BLE manager now allows you to check current permissions without requesting
3.0.0 - September 5, 2023
Section titled “3.0.0 - September 5, 2023”EnhancementAndroid
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.
BREAKINGAndroid
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.
BREAKINGEnhancementAndroid
Android MTU requests are moved to the IPeripheral.Connect(AndroidConnectionConfig)


