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

Device Monitoring

Shiny.Core includes two small monitors: IConnectivity for network reachability and IBattery for power state. Shiny’s modules use them to decide when to run. Jobs, for example, use them to honour RequiredInternetAccess and BatteryNotLow. You can inject them in your own code too.

Neither monitor is registered by default:

services.AddConnectivity();
services.AddBattery();

Both use TryAdd, so they are safe to call even if a module already registered them. On Linux, the methods come from Shiny.Core.Linux, and on Blazor WebAssembly from Shiny.Core.Blazor. The call is the same everywhere.

public interface IConnectivity
{
event EventHandler? Changed;
ConnectionTypes ConnectionTypes { get; } // [Flags] None, Unknown, Bluetooth, Wired, Wifi, Cellular
NetworkAccess Access { get; } // Unknown, None, Local, ConstrainedInternet, Internet
}
public class SyncService(Shiny.Net.IConnectivity connectivity) : IDisposable
{
public void Start() => connectivity.Changed += this.OnChanged;
void OnChanged(object? sender, EventArgs e)
{
if (connectivity.IsInternetAvailable())
_ = this.FlushOutbox();
}
public void Dispose() => connectivity.Changed -= this.OnChanged;
}

IsInternetAvailable(allowConstrained: true) returns true for Internet, and also for ConstrainedInternet (a captive portal or low-data mode) unless you pass false. Check ConnectionTypes.HasFlag(ConnectionTypes.Wifi) if you want to hold large transfers until the device is on Wi-Fi.

public interface IBattery
{
event EventHandler? Changed;
BatteryState Status { get; } // Unknown, None, Charging, Full, NotCharging, Discharging
double Level { get; } // 0.0 – 1.0
}

IsPluggedIn() returns true for Charging, Full and None. None means no battery was found, which means the device is on mains power.

Changed has no payload. Read Access / ConnectionTypes or Status / Level inside the handler. On most platforms the native listener only starts when the first handler subscribes and stops when the last one unsubscribes, so remember to unsubscribe, for example in Dispose or when a page is left. The properties always return a fresh reading, whether or not anything is subscribed.

Platform Connectivity Battery
Android ConnectivityManager.NetworkCallback ACTION_BATTERY_CHANGED broadcast
iOS / Mac Catalyst NWPathMonitor UIDevice battery notifications
tvOS NWPathMonitor None. An Apple TV is mains powered and UIDevice has no battery API there, so it always reports Full / 1.0 and Changed never fires
macOS (AppKit) NWPathMonitor IOKit power sources (IOPSNotificationCreateRunLoopSource)
Windows NetworkInformation.NetworkStatusChanged Battery.AggregateBattery
Linux (Shiny.Core.Linux) System.Net.NetworkInformation (netlink change events) sysfs /sys/class/power_supply/BAT*, polled every 5 seconds while subscribed. Reports None / 1.0 on machines without a battery
Blazor WASM (Shiny.Core.Blazor) navigator.onLine + Network Information API Battery Status API (navigator.getBattery)

On Linux, Access reports Internet whenever a non-loopback interface is up. It does not check whether the internet is actually reachable.

The browser implementations load a JavaScript module before they can report anything, and a module import cannot be awaited from a synchronous property. So both monitors start themselves the first time you read a property or subscribe to Changed, and report Unknown (with a Level of 1.0) until that finishes. A Changed event follows once the browser reports one, so a page that subscribes in OnInitialized updates by itself.

When you want the very first read to be accurate, await the start explicitly after building the host:

var host = builder.Build();
await host.Services.UseShinyCore(); // starts whichever monitors were registered
await host.RunAsync();

Browser support varies, and the monitors say so rather than guessing. Access uses navigator.onLine, which works everywhere. Connection type and battery come from the Network Information and Battery Status APIs, which only Chromium-based browsers implement. On Firefox and Safari, ConnectionTypes stays Unknown and Status stays Unknown with a Level of 1.0.