flutter_local_device_discovery
Discover, resolve, classify, and monitor devices and services on the local network from Flutter. Version 2.0 brings native SSDP & WS-Discovery engines, native Linux D-Bus Avahi desktop support, network topology graph mapping, native Wi-Fi connection metadata, native ICMP pinging, permission querying, expanded 500+ OUI manufacturer resolution, and specialized smart home decoders (Matter, HomeKit HAP, Google Cast, AirPlay, Spotify Connect, Sonos, MQTT, Home Assistant, IPP).
Features
- Native Android NSD, Apple Network framework, Windows DNS-SD, and Linux D-Bus Avahi service discovery
- Native SSDP and WS-Discovery multicast engines on Android, iOS, macOS, Windows, and Linux
- Network topology graph builder (
buildTopology()) with automatic gateway detection and hop-count analysis - Native Wi-Fi & network metadata inspection (
getNetworkInfo()) for SSID, BSSID, RSSI, band, channel, speed, and gateway - Native ICMP reachability probing (
probeIcmp()) - Discovery permission checking and requesting (
checkPermissions()) - Offline IEEE OUI manufacturer resolution for 500+ vendor prefixes
- Smart home & IoT protocol decoders (Matter/Thread, HomeKit HAP, Google Cast, AirPlay, Spotify, Sonos, MQTT, Home Assistant, IPP)
- Modular
DiscoveryProtocolAdapterAPI for integrating custom discovery engines - Multicast health diagnostics to detect router multicast drops / IGMP snooping
- Secure, bounded UPnP device-description retrieval with anti-SSRF protections
- Cross-protocol deduplication by UDN, hostname, address, and service identity
- Full JSON serialization (
toJson()/fromJson()) across all models
Platform support
| Platform | Minimum | Discovery support |
|---|---|---|
| Android | API 21 | Native NSD, native SSDP/UPnP, native WS-Discovery, Wi-Fi info, gateway detection, ARP cache |
| iOS | 13.0 | Network framework, native SSDP/UPnP, native WS-Discovery, Wi-Fi info, gateway detection |
| macOS | 10.15 | Network framework, native SSDP/UPnP, native WS-Discovery, CoreWLAN Wi-Fi info, gateway detection |
| Windows | Flutter-supported versions | Native DNS-SD/mDNS, native SSDP/UPnP, native WS-Discovery, WLAN API info, gateway detection |
| Linux | Flutter-supported versions | Native D-Bus Avahi mDNS/DNS-SD, native SSDP/WS-Discovery, NetworkManager info, /proc/net/route gateway |
| Web | — | API compiles and reports unsupported; browsers cannot open the required multicast sockets |
The package requires Dart 3.5 or later and Flutter 3.24 or later.
Installation
Add the package to your application:
dependencies:
flutter_local_device_discovery: ^2.0.0
Then run flutter pub get.
Snapshot discovery
discover starts a bounded session, waits for the configured duration, returns its normalized snapshot, and releases the session resources.
import 'package:flutter_local_device_discovery/flutter_local_device_discovery.dart';
final discovery = FlutterLocalDeviceDiscovery();
final snapshot = await discovery.discover(
const LocalDiscoveryRequest(
duration: Duration(seconds: 8),
protocols: {
LocalDiscoveryProtocol.mdns,
LocalDiscoveryProtocol.dnsSd,
LocalDiscoveryProtocol.ssdp,
LocalDiscoveryProtocol.upnp,
},
serviceTypes: {
'_http._tcp',
'_ipp._tcp',
'_googlecast._tcp',
},
ssdpSearchTargets: {'ssdp:all'},
fetchUpnpDescriptions: true,
),
);
for (final device in snapshot.devices) {
print('${device.displayName}: ${device.addresses}');
}
UPnP metadata retrieval is opt-in. Set fetchUpnpDescriptions to true and include either ssdp or upnp in protocols.
Continuous discovery
Keep the event subscription and session, then cancel and stop both when the owning component is disposed.
final session = await discovery.start(
const LocalDiscoveryRequest(
mode: LocalDiscoveryMode.continuous,
protocols: {
LocalDiscoveryProtocol.mdns,
LocalDiscoveryProtocol.dnsSd,
LocalDiscoveryProtocol.ssdp,
},
serviceTypes: {'_http._tcp'},
ssdpSearchTargets: {'ssdp:all'},
),
);
final subscription = session.events.listen((event) {
switch (event) {
case LocalDeviceAdded(:final device):
print('Added: ${device.displayName}');
case LocalDeviceUpdated(:final device):
print('Updated: ${device.displayName}');
case LocalDeviceRemoved(:final device):
print('Removed: ${device.displayName}');
case LocalDiscoveryWarning(:final message):
print('Warning: $message');
case LocalDiscoveryFailure(:final error):
print('Failure: $error');
case _:
break;
}
});
// When discovery is no longer needed:
await subscription.cancel();
await session.stop();
Sessions also support pause(), resume(), and snapshot().
Capabilities and readiness
Check support before presenting protocol-specific controls, then check whether a concrete request can start:
final capabilities = await discovery.getCapabilities();
print(capabilities.supportedProtocols);
final request = const LocalDiscoveryRequest(
protocols: {LocalDiscoveryProtocol.ssdp},
ssdpSearchTargets: {'ssdp:all'},
);
final readiness = await discovery.checkReadiness(request);
if (!readiness.canStart) {
print('Requirements: ${readiness.requirements}');
}
Classification evidence and UPnP identity
Classification is an inference from observable service and device metadata. Applications can inspect the supporting evidence instead of treating a classification as authoritative.
for (final device in snapshot.devices) {
print('Type: ${device.type}');
print('UPnP UDN: ${device.identity.upnpUdn}');
for (final evidence in device.capabilityEvidence) {
print('${evidence.capability}: ${evidence.source}');
}
}
Platform configuration
Android
The Android implementation declares these permissions and they are merged into the consuming application manifest:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
iOS
Add a purpose string and every Bonjour service type your application browses to ios/Runner/Info.plist:
<key>NSLocalNetworkUsageDescription</key>
<string>This app discovers devices and services available on your local network.</string>
<key>NSBonjourServices</key>
<array>
<string>_http._tcp</string>
<string>_ipp._tcp</string>
</array>
Only declare service types the application actually uses.
macOS
Add the same NSLocalNetworkUsageDescription and NSBonjourServices entries to macos/Runner/Info.plist. Sandboxed applications also need client and server networking in both debug/profile and release entitlements:
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
Enabling Local Network Access (macOS & iOS)
If you encounter Network.NWError error -65555 - NoAuth or no devices appear, verify that Local Network permissions are enabled:
On macOS:
- Open System Settings ( > System Settings).
- Click Privacy & Security in the sidebar.
- Scroll down and click Local Network.
- Find
device_discovery(orRunner/ your terminal or IDE if running in debug mode) and toggle the switch to ON (Enabled). - Re-open or re-run the app.
On iOS:
- Open the Settings app on the iPhone/iPad.
- Scroll down to
Device Discovery(or Privacy & Security > Local Network). - Ensure the Local Network switch is turned ON.
Windows
Windows Firewall or enterprise policy can filter multicast UDP. Test on the intended network profile; the plugin does not create firewall exceptions.
UPnP metadata security
UPnP descriptions are untrusted network input. The default MetadataSecurityPolicy:
- permits private and link-local targets only
- blocks public and loopback targets
- validates and pins resolved connection addresses
- validates every redirect target
- limits redirects, response size, request time, and XML depth
- rejects XML document types and entity declarations
Relax allowExternalAddresses or allowLoopbackAddresses only when the application explicitly trusts those targets.
Important behavior
- Discovery is not authentication, pairing, or a guaranteed network inventory.
- Guest Wi-Fi, client isolation, VPNs, firewalls, and enterprise multicast policy can hide devices.
- A missing response does not prove that a device is offline.
- Service and device metadata can be malformed or intentionally deceptive.
- Neighbor-table inspection, reachability probing, and safe port probing are fully implemented and supported in v1.0.0.
Example
The included example application is a v0.2 review console with protocol controls, live device/service events, UPnP metadata, capability evidence, readiness, and diagnostics.
Additional documentation
License
MIT. See LICENSE.
Libraries
- flutter_local_device_discovery
- Local-network device and service discovery for Flutter.
- testing