Oppo Android14设备NSD Discovery无法工作的问题排查
NSD Discovery无法在Android14的Oppo设备上发现服务
我按照官方文档实现了NSD服务注册与发现逻辑,代码在Pixel(Android14)、华为(Android9)、传音Infinix(Android11)等设备上都能正常工作,但唯独Android14的Oppo设备无法发现任何服务。
实现代码
NsdDiscovery类
class NsdDiscovery(private val context: Context) { private var mHostAddress: InetAddress? = null private var mHostPort = 0 private lateinit var mNsdManager: NsdManager private var isDiscovering = false private var mRandom = 0 private val mDiscoveryListener = DiscoveryListener() fun updateConnectionListener(str: String, i: Int) { Log.d(TAG, "updateConnectionListener: $str $i") LocalBroadcastManager.getInstance(context).sendBroadcast( Intent(BroadcastActions.DEVICE_CONNECTED.toString()) .putExtra(Constants.IP_ADDRESS.name, str) .putExtra(Constants.PORT.name, i) ) } inner class DiscoveryListener : NsdManager.DiscoveryListener { override fun onDiscoveryStarted(serviceType: String?) { Log.d(TAG, "onDiscoveryStarted: ") serviceType?.let { Log.d(TAG, "onDiscoveryStarted: $it") } } override fun onServiceFound(serviceInfo: NsdServiceInfo?) { Log.d(TAG, "onServiceFound: $serviceInfo") serviceInfo?.let { info -> Log.d(TAG, "onServiceFound: service info $info") if (info.serviceType.equals(SERVICE_TYPE)) { Log.d(TAG, "onServiceFound: service type matches") if (info.serviceName.equals(SERVICE_NAME)) { Log.d(TAG, "onServiceFound: Listening Same Machine") return } mNsdManager.resolveService(info, MyResolveListener()) return } } } inner class MyResolveListener : NsdManager.ResolveListener { override fun onResolveFailed(serviceInfo: NsdServiceInfo?, errorCode: Int) { Log.d(TAG, "onResolveFailed: $errorCode") serviceInfo?.let { Log.d(TAG, "onResolveFailed: Listening service $it") } } override fun onServiceResolved(serviceInfo: NsdServiceInfo?) { Log.d(TAG, "onServiceResolved: $serviceInfo") serviceInfo?.let { nsdServiceInfo -> if (nsdServiceInfo.serviceName.equals(mRandom.toString())) { Log.d(TAG, "onServiceResolved: Service Matched: $mRandom") if (nsdServiceInfo.serviceName.equals(SERVICE_NAME)) { Log.d(TAG, "onServiceResolved: Listening Port $nsdServiceInfo") return } var inetAddress: InetAddress? = null try { inetAddress = InetAddress.getByName(nsdServiceInfo.host.hostAddress) } catch (e: UnknownHostException) { e.printStackTrace() } try { inetAddress?.hostAddress } catch (e: Exception) { e.printStackTrace() } mHostPort = nsdServiceInfo.port mHostAddress = nsdServiceInfo.host Log.d(TAG, "onServiceResolved: Listening Port: $mHostPort") Log.d(TAG, "onServiceResolved: Listening IP: $mHostAddress") Toast.makeText(context, "Obtained IP: \n $mHostAddress", Toast.LENGTH_SHORT).show() if (mHostAddress is Inet6Address) { stopDiscoveringServices() Handler(Looper.getMainLooper()).postDelayed({ discoverServices(mRandom) }, 3000) } try { val localHost = InetAddress.getLocalHost() Log.d(TAG, "onServiceResolved: ${localHost.hostAddress}") } catch (e: UnknownHostException) { e.printStackTrace() } if (mHostAddress!!.hostAddress!! == STATIC_IP || mHostAddress is Inet6Address) { Log.d(TAG, "onServiceResolved: equals to static ip or ipv6") return } updateConnectionListener(mHostAddress!!.hostAddress, nsdServiceInfo.port) } } } } override fun onServiceLost(serviceInfo: NsdServiceInfo?) { Log.d(TAG, "onServiceLost: $serviceInfo") } override fun onDiscoveryStopped(serviceType: String?) { Log.d(TAG, "onDiscoveryStopped: $serviceType") } override fun onStartDiscoveryFailed(serviceType: String?, errorCode: Int) { Log.d(TAG, "onStartDiscoveryFailed: $errorCode") stopDiscoveringServices() } override fun onStopDiscoveryFailed(serviceType: String?, errorCode: Int) { Log.d(TAG, "onStopDiscoveryFailed: $errorCode") stopDiscoveringServices() } } fun discoverServices(i: Int) { Log.d(TAG, "discoverServices: $i") mRandom = i mNsdManager = context.getSystemService(Context.NSD_SERVICE) as NsdManager if (isDiscovering) { Log.d(TAG, "discoverServices: Already Discovering") return } isDiscovering = true mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener) Log.d(TAG, "discoverServices: started discovering") } fun stopDiscoveringServices() { if (isDiscovering) { isDiscovering = false mNsdManager.stopServiceDiscovery(mDiscoveryListener) Log.d(TAG, "stopDiscoveringServices: discovery stoped") } } companion object { private const val TAG = "NsdDiscovery" private const val SERVICE_NAME = "Client Device" private const val SERVICE_TYPE = "_http._tcp." private const val STATIC_IP = "192.168.43.1" } }
NsdService类
class NsdService(private val context: Context) { private lateinit var mNsdManager: NsdManager private var SERVICE_NAME = "Server device" private val SERVICE_TYPE = "_http._tcp." private var isServiceRegistered = false private var tryUnregister = 0 private var mPort = 0 private var mRandomName = SERVICE_NAME private var mRegistrationListener: RegistrationListener? = object : RegistrationListener { override fun onServiceRegistered(serviceInfo: NsdServiceInfo?) { isServiceRegistered = true serviceInfo?.let { SERVICE_NAME = serviceInfo.serviceName Log.d(TAG, "onServiceRegistered: Service Name: ${serviceInfo.serviceName}") LocalBroadcastManager.getInstance(context) .sendBroadcast(Intent(BroadcastActions.SERVICE_REGISTERED.name)) } } override fun onRegistrationFailed(serviceInfo: NsdServiceInfo?, errorCode: Int) { Log.d(TAG, "onRegistrationFailed: ") Handler(Looper.getMainLooper()).postDelayed({ registerService(mPort, mRandomName) }, 2000) } override fun onServiceUnregistered(serviceInfo: NsdServiceInfo?) { Log.d(TAG, "onServiceUnregistered: ") serviceInfo?.let { Log.d(TAG, "onServiceUnregistered: ${serviceInfo.serviceName}") } } override fun onUnregistrationFailed(serviceInfo: NsdServiceInfo?, errorCode: Int) { Log.d(TAG, "onUnregistrationFailed: ") isServiceRegistered = true if (tryUnregister < 3) { unRegisterService() tryUnregister++ } } } fun registerService(port: Int, random: String) { mNsdManager = context.getSystemService(Context.NSD_SERVICE) as NsdManager if (!isServiceRegistered) { mPort = port val nsdServiceInfo = NsdServiceInfo().apply { serviceName = random serviceType = SERVICE_TYPE setPort(port) } mNsdManager.registerService(nsdServiceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener) } } fun unRegisterService() { if (isServiceRegistered) { if (mRegistrationListener != null) { mNsdManager.unregisterService(mRegistrationListener) } isServiceRegistered = false } } companion object { private const val TAG = "NsdService" } }
针对性排查与解决方案
1. 检查Oppo系统的权限与隐私限制
Oppo的ColorOS对本地网络发现有额外管控:
- 确认应用已开启位置权限(NSD依赖位置服务扫描本地网络)
- 关闭「隐私替身」功能,该功能可能干扰网络扫描
- 在「设置 > 应用 > 你的应用 > 权限管理」中,确认授予「附近设备」权限(Android12+新增,ColorOS会强化该权限校验)
2. 取消IPv6地址过滤
Oppo设备可能默认优先使用IPv6,当前代码中直接过滤IPv6地址导致服务被跳过:
- 注释掉
onServiceResolved中if (mHostAddress is Inet6Address)的重启扫描逻辑 - 或修改代码兼容IPv6地址处理,不要直接忽略
3. 确保服务名称唯一性
ColorOS对重复服务名称的兼容性较差,修改NsdService的注册逻辑:
// 在registerService方法中,给服务名称添加随机后缀 serviceName = "$random-${System.currentTimeMillis()}"
4. 兼容多种NSD协议
尝试同时使用DNS-SD和MDNS协议,修改扫描与注册时的参数:
// 替换原有的PROTOCOL_DNS_SD NsdManager.PROTOCOL_DNS_SD or NsdManager.PROTOCOL_MDNS
5. 增加错误码日志排查
在onStartDiscoveryFailed中添加错误码解析,定位具体失败原因:
override fun onStartDiscoveryFailed(serviceType: String?, errorCode: Int) { val errorMsg = when(errorCode) { NsdManager.FAILURE_ALREADY_ACTIVE -> "扫描已在进行" NsdManager.FAILURE_INTERNAL_ERROR -> "系统内部错误" NsdManager.FAILURE_SERVICE_NOT_FOUND -> "未找到匹配服务" else -> "未知错误:$errorCode" } Log.e(TAG, "扫描启动失败: $errorMsg") stopDiscoveringServices() }
6. 验证网络环境
确保Oppo设备与服务端设备连接同一WiFi网络,且路由器未开启AP隔离(部分路由器默认开启,会阻止设备间本地通信)
内容的提问来源于stack exchange,提问作者Adnan Aslam
相关产品推荐
相关产品推荐

