Skip to content
Shiny.NET
Shiny MAUI Shell v7 - App Links, App Shortcuts, & Navigation Interception!Shortcut me to it

Beacons

GitHub GitHub stars for shinyorg/shiny
Downloads NuGet downloads for Shiny.Beacons
Frameworks
.NET
.NET MAUI
Blazor
Operating Systems
Android
iOS
macOS
Windows
Linux

Shiny Beacons covers both beacon formats that matter — Apple’s iBeacon and Google’s Eddystone — across ranging (how far away is it?), background region monitoring (tell me when I arrive), and broadcasting (become a beacon).

Terminal window
dotnet add package Shiny.Beacons

The two formats travel through different parts of a BLE advertisement, and that single fact shapes everything else about this library:

  • iBeacon is manufacturer data under Apple’s company identifier 0x004C. CoreBluetooth strips it out of every scan result on iOS, Mac Catalyst and macOS. There is no scan configuration that brings it back. So on Apple platforms iBeacon goes through CoreLocation, and costs a location permission rather than a Bluetooth one. On every other platform Shiny reads the advertisement directly.
  • Eddystone is service data under UUID 0xFEAA, which CoreBluetooth passes through untouched. It behaves identically everywhere, Apple included.

If you have ever wondered why an iOS app cannot find an iBeacon with a plain BLE scan — that is why.

// Foreground ranging - "which beacons are near me and how far?"
services.AddBeaconRanging();
// Background region monitoring - "tell me when I enter or leave"
services.AddBeaconMonitoring<MyBeaconMonitorDelegate>();
// Eddystone frames - works on every platform
services.AddEddystoneScanning();
// Become a beacon
services.AddBeaconBroadcasting();

Each takes an optional BeaconRangingOptions. AddBeaconMonitoring also wires the default repository, so monitored regions survive a process restart.

On Linux, or any plain .NET host, register an IBleManager first (AddBluetoothLE() from Shiny.BluetoothLE.Linux). The beacon registrations throw a named error if none is present, rather than failing later with an unresolved dependency from inside a scan.

public class BeaconViewModel(IBeaconRangingManager ranging)
{
IDisposable? sub;
public async Task Start()
{
var access = await ranging.RequestAccess();
if (access != AccessState.Available)
return;
var region = new BeaconRegion("store-front", Guid.Parse("B9407F30-F5F8-466E-AFF9-25556B57FE6D"));
this.sub = ranging
.WhenBeaconRanged(region)
.Subscribe(beacon => Console.WriteLine(
$"{beacon.Major}/{beacon.Minor}: {beacon.Distance:N1}m ({beacon.Proximity})"
));
}
public void Stop() => this.sub?.Dispose();
}
Feature iOS / Mac Catalyst macOS Android Windows Linux Blazor WASM
iBeacon ranging CoreLocation CoreLocation BLE scan BLE scan BLE scan BLE scan
Region monitoring CLMonitor (18+) / CLLocationManager Not supported by the OS BLE scan + foreground service BLE scan BLE scan BLE scan
Eddystone BLE scan BLE scan BLE scan BLE scan BLE scan BLE scan
iBeacon broadcast Yes Yes Yes Yes Yes No
Eddystone broadcast No No Yes Yes Yes No

tvOS has no target. tvOS binds no CLBeacon type of any kind — CoreLocation there is GPS only — so iBeacon is impossible, and an Eddystone-only surface that threw for half its members was not worth shipping.

macOS monitoring registers successfully but reports AccessState.NotSupported and throws from StartMonitoring. That is deliberate: shared startup code runs unchanged, and you branch on CurrentStatus rather than on OperatingSystem.IsMacOS(). Ranging and Eddystone both work fine.

Blazor needs navigator.bluetooth.requestLEScan, which is Chromium-only and sits behind chrome://flags/#enable-experimental-web-platform-features. The chooser fallback carries no advertisement payload at all, so beacons are invisible through it.

claude plugin marketplace add shinyorg/skills
claude plugin install shiny@shiny

One plugin installs all 36 Shiny skills. Your agent loads only the skill relevant to what you're building, so there's no cost to having them all available.

copilot plugin marketplace add https://github.com/shinyorg/skills
copilot plugin install shiny@shiny

One plugin installs all 36 Shiny skills. Your agent loads only the skill relevant to what you're building, so there's no cost to having them all available.

View shiny-beacons Skill