fourb_mdns 0.1.0 copy "fourb_mdns: ^0.1.0" to clipboard
fourb_mdns: ^0.1.0 copied to clipboard

Let people pick a server off the local network from inside your Flutter app, and remember which one they chose. Scans mDNS/Bonjour natively — no server.

fourb_mdns #

Let people pick a server off the local network from inside your Flutter app, and remember which one they chose.

Unlike a browser, a Flutter app can speak mDNS itself — so there is no server to run. The package queries multicast DNS directly via multicast_dns.

The companion package for React apps is 4b-react-mdns; the two share the same storage keys and record shape.

Quick start #

dependencies:
  fourb_mdns: ^0.1.0

Wrap your app once:

import 'package:fourb_mdns/fourb_mdns.dart';

void main() => runApp(
      MdnsScope(
        httpOnly: true,
        child: MaterialApp(home: HomePage()),
      ),
    );

A Scan network button floats bottom-right. Tap it, pick a server, done.

Add the platform permissions below first — without them the scan returns nothing, silently.

Reading the pick #

Anywhere below the scope:

final mdns = MdnsScope.of(context);

if (mdns.address == null) {
  return TextButton(
    onPressed: () => showMdnsPicker(context),
    child: const Text('Choose a server'),
  );
}
return Text('Server at ${mdns.address}');

Outside the widget tree — in an API client with no BuildContext:

final address = await MdnsStore.savedAddress(); // "192.168.0.224:3000"
final base = Uri.parse('http://$address');

Stored in SharedPreferences under the same keys the React package uses:

Key
4b_mDNS_ip the plain ip:port string
4b_mDNS_selection the full record as JSON

Platform setup #

mDNS needs explicit permission on Apple platforms, and multicast on Android. Skip these and the scan just finds nothing — there is no error dialog.

iOS #

ios/Runner/Info.plist:

<key>NSLocalNetworkUsageDescription</key>
<string>Finds servers on your network so you can pick one.</string>
<key>NSBonjourServices</key>
<array>
  <string>_services._dns-sd._udp</string>
  <string>_http._tcp</string>
  <string>_https._tcp</string>
</array>

NSBonjourServices is an allow-list: iOS only returns types you declare. _services._dns-sd._udp is what enumerates the rest, so keep it and add any other type you care about.

macOS #

Both macos/Runner/DebugProfile.entitlements and Release.entitlements:

<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>

macOS 15+ also wants the same NSLocalNetworkUsageDescription and NSBonjourServices keys in macos/Runner/Info.plist.

Android #

android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>

Flutter Web #

Not supported — browsers can't speak mDNS. Use 4b-react-mdns, which runs discovery in Node and serves it over HTTP.

MdnsScope #

Parameter Default
child Your app
httpOnly false Show only _http._tcp / _https._tcp
filterToggle false when httpOnly is set Show the HTTP-only switch in the picker
launcher true Show the built-in floating button
launcherLabel Scan network Its text
alignment Alignment.bottomRight Where it sits
scanOnStart true Sweep once on mount
timeout 6s How long each query phase listens
onSelect Called when the pick changes

Passing httpOnly hides the picker's own switch: the app has decided, so a control that contradicts it only confuses. Pass filterToggle: true to bring it back.

MdnsScope.of(context) #

Returns the [MdnsController] and rebuilds the caller when the scan or the pick changes. Use MdnsScope.read(context) in callbacks that only need to act.

selection      // MdnsService?  the pick
address, ip, url
services       // filtered + sorted
allServices    // everything found
webServerCount // how many are _http/_https
isScanning, isRestored, error
scan({fresh}), select(service), clear()
httpOnly       // get/set

isRestored tells "nothing selected" apart from "still reading storage", so you can avoid flashing an empty state on launch.

Your own button #

MdnsScope(
  launcher: false,
  child: MaterialApp(home: HomePage()),
)
IconButton(
  icon: const Icon(Icons.wifi_find),
  onPressed: () => showMdnsPicker(context),
)

showMdnsPicker returns the chosen MdnsService, or null if dismissed.

Using the scanner directly #

No widgets involved — useful for a CLI or a background refresh:

final scanner = MdnsScanner(timeout: const Duration(seconds: 4));
scanner.stream.listen((services) => print('${services.length} so far'));
await scanner.scan();
scanner.dispose();

MdnsService gives you name, type, protocol, host, port, addresses, txt, plus derived ip (IPv4 first, then IPv6, then the .local host), address (ip:port, IPv6 bracketed), url, kind and isWebServer.

How the scan works #

multicast_dns only answers questions you ask, so a wildcard browse is five steps:

  1. PTR on _services._dns-sd._udp.local — which types are in use
  2. PTR on each type — instances of it
  3. SRV on each instance — host and port
  4. A / AAAA on the host — addresses
  5. TXT on the instance — metadata

Types resolve concurrently, and results stream out as they arrive rather than after the whole sweep, so the list fills in progressively. mDNS has no "done" signal, so every phase is bounded by timeout.

Example #

cd example
flutter run -d macos

Or check discovery without a UI at all:

dart run tool/live_scan.dart --http-only
4 service(s) (http only, of 54 total)

  mDNS: advertising "streaming-server" at Mac.local:3000 (_http._tcp.local)
        ip=192.168.0.224  address=192.168.0.224:3000  url=http://192.168.0.224:3000

License #

MIT

1
likes
0
points
279
downloads

Publisher

unverified uploader

Weekly Downloads

Let people pick a server off the local network from inside your Flutter app, and remember which one they chose. Scans mDNS/Bonjour natively — no server.

Repository
View/report issues

Topics

#mdns #bonjour #discovery #networking

License

unknown (license)

Dependencies

flutter, meta, multicast_dns, shared_preferences

More

Packages that depend on fourb_mdns