Skip to content
Shiny Controls v1.0 - The Ultra Control Suite for .NET MAUI & BlazorO...M...G!

Wi-Fi Releases

Feature
New Shiny.Net.Wifi package — cross-platform Wi-Fi for Android, iOS, Mac Catalyst, macOS and Windows, with Shiny.Net.Wifi.Linux covering Linux through NetworkManager. Register services.AddWifi() and inject IWifiManager to scan for access points, join and leave networks, manage the networks the device has saved, read the current network, and power the radio. Backed by WifiManager + ConnectivityManager on Android, NEHotspotConfiguration + CaptiveNetwork on iOS/Mac Catalyst, CoreWLAN on macOS, the WiFiAdapter WinRT API on Windows, and NetworkManager over D-Bus on Linux.
Feature
IWifiManager.Capabilities publishes a WifiCapabilities flags value describing what the current platform can actually do, and anything unavailable throws WifiNotSupportedException naming the specific limit. Wi-Fi is the most unevenly exposed capability across these platforms — iOS has no scanning API, neither phone OS will show an app the networks the user saved, only three platforms can raise a hotspot — and the API states that rather than returning empty results that are indistinguishable from a quiet neighbourhood.
Feature
Scan(...) returns one WifiNetwork per BSSID — SSID, WifiSecurity (Open/WEP/WPA/WPA2/WPA3/Enterprise/OWE), signal in both dBm and a 0-100 percentage, frequency, and derived Band and Channel. Results are strongest-first. Networks in a WPA2/WPA3 or OWE transition mode report the stronger scheme, so a caller never sees a network as weaker than it is.
Feature
Connect(new WifiConnectionRequest(ssid) { Passphrase = ... }) joins a network and returns only once an address has been assigned, not merely on association — a result with no IP on it is not useful to the caller. Disconnect() leaves. WifiConnectionException carries the reason a join failed: wrong passphrase, out of range, user declined the system prompt, or DHCP timeout.
Feature
Known networks — GetKnownNetworks() lists what the device has saved as KnownWifiNetwork (an opaque platform-issued Id, plus SSID, security, hidden flag and AddedByThisApp), Forget(id) deletes one, and Connect(id) rejoins one without the passphrase being handed over again. The three sit behind the KnownNetworks, ForgetNetwork and ConnectKnownNetwork capability flags. Id is the platform’s own handle — a NetworkManager connection UUID on Linux, a numeric network id on Android below API 29, the SSID everywhere else — so round-trip it rather than parsing it.
Feature
What counts as “known” is scoped differently per platform and the API says which rather than papering over it: iOS, Mac Catalyst and Android disclose only the entries your own app created, while Windows, macOS and Linux hand back every profile on the machine. Neither phone OS will show an app the networks the user saved themselves, so AddedByThisApp exists to tell the two cases apart and a “manage all my Wi-Fi networks” screen is a desktop-only idea.
FeatureiOS
Saved networks on iOS and Mac Catalyst map onto NEHotspotConfigurationManagergetConfiguredSSIDs for the listing and removeConfiguration(forSSID:) for Forget. Only names come back; a stored configuration carries no security type or hidden flag. Connect(id) is not available: a configuration is a standing instruction iOS acts on when the network is in range, and there is no call to force the join.
FeatureAndroid
Remember = true now does something on Android 11+. The specifier join is still what gets the device onto the network, but a WifiNetworkSuggestion is registered alongside it so the OS can rejoin later — which is also what makes the network visible to GetKnownNetworks(). The suggestion only takes effect once the user approves the notification Android raises, and a failure to register one never fails the join. Below API 29 the legacy WifiConfiguration list is used instead, and its numeric network id is a real handle, so Connect(id) works there.
FeatureWindows
Saved profiles are outside WinRT entirely — WiFiAdapter cannot list, delete or join one — so GetKnownNetworks(), Forget() and Connect(id) P/Invoke wlanapi.dll directly (WlanGetProfileList, WlanGetProfile, WlanDeleteProfile, WlanConnect) rather than shelling out to netsh and parsing localised console output. Security and the hidden flag are read out of each profile’s XML; one that cannot be parsed is still reported, as unknown.
Feature
macOS lists the machine’s preferred-network list from CWConfiguration.networkProfiles and rejoins from the login keychain, so your app never sees the passphrase. Forget() there means committing a whole CWConfiguration, which macOS gates behind an SFAuthorization a normal app cannot raise — it throws WifiPermissionException explaining that. Linux reads, activates and deletes NetworkManager’s saved connections directly, with deletion gated on the polkit action org.freedesktop.NetworkManager.settings.modify.system.
Feature
IWifiManager.CurrentNetwork reports the joined network as a WifiNetworkInfo — SSID, BSSID, security, signal and frequency alongside every IP address, DNS resolver, gateway and subnet mask, with IPv4Address/IPv6Address shortcuts. The Changed event fires with the new WifiNetworkInfo? (null when the device drops off Wi-Fi) and is de-duplicated: the native watchers behind it all fire several times per real change. WifiNetworkInfo compares its address lists by value rather than by reference, so snapshots can be diffed directly.
Feature
New IWifiHotspot (services.AddWifiHotspot()) raises an access point. Start(...) returns an IHotspotSession carrying the SSID and passphrase actually in use; disposing it brings the access point down. GetClients() lists joined devices with MAC address, IP and host name.
FeatureAndroid
The Android hotspot is a local-only hotspot — clients reach the device but get no route to the internet, because real tethering sits behind the signature permission TETHER_PRIVILEGED. The OS also generates the SSID and passphrase and offers no supported way to choose them (SoftApConfiguration.Builder exposes only the channel to non-system apps), so read them back off IHotspotSession.Info and show them to the user. GetClients() throws — Android has never exposed a client list and blocked the /proc/net ARP table apps read instead in Android 10.
FeatureWindows
Windows hotspot support goes through NetworkOperatorTetheringManager — real tethering that shares the machine’s current internet connection, honours the SSID, passphrase and band you supply, and can enumerate connected clients. Starting one with the machine offline fails, since there is no connection to share.
Feature
Linux hotspot support runs NetworkManager AP mode with ipv4.method=shared for DHCP and NAT, honours the full HotspotConfiguration, and lists clients from the kernel neighbour table filtered to the hotspot interface.
FeatureiOS
iOS and Mac Catalyst support joining, leaving and reading the current network, and nothing else. There is no scanning API — the only one that lists nearby networks lives inside a NEHotspotHelper, an entitlement Apple grants case by case — no hotspot API and no radio toggle. Requires the Hotspot Configuration and Access WiFi Information App ID capabilities plus NSLocationWhenInUseUsageDescription; without the location grant iOS 13+ returns a placeholder SSID rather than failing, which is why RequestAccess() asks for it.
FeatureAndroid
Android needs ACCESS_WIFI_STATE, CHANGE_WIFI_STATE and ACCESS_FINE_LOCATION, plus NEARBY_WIFI_DEVICES from API 33. Joining uses a WifiNetworkSpecifier from API 29 (a system dialog, and the join itself is never persisted) and falls back to the legacy WifiConfiguration path below it. The radio toggle drops out of Capabilities from API 29, where setWifiEnabled was revoked for third-party apps.
Feature
macOS is backed by CoreWLAN and supports the full station API — scanning, associating, disassociating and powering the interface. Needs NSLocationWhenInUseUsageDescription, since macOS 14 gates scan results and the SSID on location the way iOS does. Windows needs the wiFiControl and radios capabilities; Linux gates the mutating calls behind the polkit actions org.freedesktop.NetworkManager.network-control and …enable-disable-wifi.
Enhancement
A scan that comes back empty because a permission was refused throws WifiPermissionException naming what is missing, rather than looking like an empty neighbourhood — Android returns an empty list instead of an error in that case. Android’s <unknown ssid> placeholder and the all-zero BSSID it substitutes without location permission are reported as null rather than passed through as literal strings.
Chore
The plain .NET target of the base package is a deliberate stub rather than a fallback: CurrentNetwork still reports the IP, DNS, gateway and mask of the wireless interface and Changed still fires off NetworkChange, because that comes from the managed network stack — but every Wi-Fi-specific call throws, pointing at Shiny.Net.Wifi.Linux where relevant. Capabilities reports None.