Flutter使用udp包在iOS14下本地网络广播报errno=9错误
错误产生原因
- iOS 14及以上系统新增本地网络权限限制,应用未提前申请对应权限时,系统会主动拦截本地网络广播请求,直接关闭已绑定的UDP socket,导致后续操作引用无效的文件描述符,触发
OS Error: Bad file descriptor, errno = 9报错。 - 现有代码未显式开启UDP socket的广播标识,iOS系统默认禁止普通UDP socket发送广播数据包,会直接触发socket回收关闭。
- 部分版本的第三方udp包iOS端实现存在时序缺陷,bind操作完成后未正确持有socket句柄,短时间内连续调用listen和send方法时可能出现句柄提前释放的问题。
解决方案
步骤1:配置iOS端权限
打开iOS项目下的ios/Runner/Info.plist文件,添加两项权限配置:
- 添加本地网络使用说明:key为
NSLocalNetworkUsageDescription,value填写业务相关的权限提示文案,例如「需要访问本地网络以发现同网段设备」 - 添加广播服务声明:key为
NSBonjourServices,类型为数组,添加一个值为_udp._local的item
步骤2:调整UDP逻辑代码
显式开启socket广播属性,调整调用时序避免异步问题,修改后的参考代码如下:
var endPoint = Endpoint.broadcast(port: Port(6000)); var udpFuture = UDP.bind(Endpoint.any(port: Port(6000))); udpFuture.then((udp) async { // 显式开启socket广播权限,适配iOS系统限制 udp.socket.broadcastEnabled = true; // 初始化监听 udp.listen((datagram) { handleMessage(datagram.data); }); // 增加短延时规避iOS端socket初始化时序问题 await Future.delayed(const Duration(milliseconds: 100)); udp.send(bytesToSend, endPoint); });
备选方案
如果第三方udp包仍存在兼容问题,可直接使用Dart标准库dart:io中的RawDatagramSocket实现UDP广播,原生实现对iOS14+系统的适配稳定性更高。
内容的提问来源于stack exchange,提问作者Roy Solberg
相关产品推荐
相关产品推荐

