Flutter如何扫描局域网设备 获取IP、MAC地址及设备类型信息
局域网设备列表功能完整实现路线
整个功能分三个核心环节实现,不需要依赖额外重型SDK,各环节逻辑解耦方便调试:
1. 存活IP采集
你目前用的lan_scanner已经可以覆盖这部分需求,核心逻辑是遍历当前网段的所有IP,通过ICMP ping或者常用端口探测筛选出在线设备。
- 扫描前不要硬编码网段,先获取本机IP地址,比如本机IP是
192.168.1.12,就自动生成192.168.1.1-192.168.1.254的扫描范围,适配不同的局域网网段配置。 - 扫描并发数建议控制在10-15,过高会触发系统网络限制,也可能影响局域网内其他设备的网络使用。
2. IP对应MAC地址获取
这部分没有通用跨平台库可以直接用,基于ARP协议实现即可,同网段下准确率接近100%:
- 移动端(Android/iOS):主动给存活IP发送ARP请求,或者直接读取系统本地的ARP缓存表,解析出IP和MAC的映射关系。注意Android需要声明
ACCESS_WIFI_STATE权限,iOS 14及以上版本需要申请本地网络权限,否则ARP请求会被系统拦截。 - 桌面端(Windows/macOS/Linux):直接调用系统自带的ARP查询命令,用正则匹配返回结果里的IP、MAC字段即可,不需要额外构造网络包。
注意:跨三层交换机、跨VLAN的设备无法通过ARP拿到MAC地址,普通家用路由器下的局域网不存在这个问题。
3. 设备类型识别
这部分用「OUI粗筛 + mDNS精细识别」的组合方案,识别准确率最高:
- OUI粗筛:MAC地址的前3个字节是厂商统一分配的OUI标识,提前维护一份公开的OUI和设备类型的映射表,比如打印厂商的OUI对应打印机、手机厂商的OUI对应移动设备、网卡厂商的OUI对应PC,先给每个设备打初始标签。
- mDNS精细识别:你调研的multicast_dns库就是用来做这部分的,大部分手机、PC、智能硬件、打印机默认都会开启mDNS服务广播自身信息:
- 启动mDNS客户端后,先发送
_services._dns-sd._udp.local的指针查询,拿到局域网内所有广播的服务类型 - 针对每个服务类型,进一步查询对应的SRV记录和A记录,拿到设备的IP、端口、设备名信息
- 根据服务类型判断设备类别:
- 返回
_ipp._tcp/_printer._tcp服务的是打印机 - 返回
_airplay._tcp服务的是苹果系智能设备 - 返回
_smb._tcp服务的大概率是PC或者NAS设备 - 返回各厂商自定义IoT服务(比如米家、HomeKit相关服务)的对应智能硬件
- 启动mDNS客户端后,先发送
multicast_dns基础调用示例
import 'package:multicast_dns/multicast_dns.dart'; // 存储mDNS查询结果的结构体 class LanDeviceInfo { final String ip; final String deviceName; final String serviceType; final int port; LanDeviceInfo({required this.ip, required this.deviceName, required this.serviceType, required this.port}); } Future<List<LanDeviceInfo>> queryMDnsDevices() async { final client = MDnsClient(); final List<LanDeviceInfo> res = []; // 启动mDNS客户端,绑定5353端口 await client.start(); try { // 遍历所有广播的服务 await for (final ptrRecord in client.lookup<PtrResourceRecord>( ResourceRecordQuery.serverPointer('_services._dns-sd._udp.local'))) { // 查询对应服务下的具体设备 await for (final srvRecord in client.lookup<SrvResourceRecord>( ResourceRecordQuery.service(ptrRecord.domainName))) { // 查询设备对应的IP地址 await for (final ipRecord in client.lookup<IPAddressResourceRecord>( ResourceRecordQuery.addressIPv4(srvRecord.target))) { res.add(LanDeviceInfo( ip: ipRecord.address.address, deviceName: srvRecord.target, serviceType: ptrRecord.domainName, port: srvRecord.port, )); } } } } finally { client.stop(); } return res; }
注意事项
- 没有方案能做到100%的设备类型识别率:部分用户会手动关闭设备的mDNS服务,这类设备只能通过OUI做粗粒度分类,可以在列表里提供手动修改设备类型的入口。
- 权限适配:Android 10、iOS 14及以上版本必须在应用启动时申请本地网络权限,否则所有局域网扫描、ARP请求、mDNS查询都会被系统静默拦截,不会返回任何结果。
- 扫描逻辑建议放在后台异步执行,不要阻塞主线程,扫描过程中可以实时把发现的设备追加到列表,不需要等全部扫描完成再展示。
内容的提问来源于stack exchange,提问作者jimmy
相关产品推荐
相关产品推荐

