NsdServiceInfo 不包含 Android 6.0 上的属性

问题描述

在应该在 Android 6+ 上运行的 Android 应用程序上,我尝试使用网络服务发现来检查我的网络上是否有一些设备可用。

基于 this part of the official documentation,我创建了这个小 POC:

class MainActivity : AppCompatActivity() {

    companion object {
        private const val TAG = "POC"

        private const val SERVICE_TYPE = "_http._tcp."
    }

    private val servicetoResolve = mutablelistof<NsdServiceInfo>()

    private var index = 0

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        findViewById<Button>(R.id.discover_btn).setonClickListener {
            search()
        }

    }

    private fun search() {
        lifecycleScope.launch(dispatchers.IO) {
            val serviceInfo = NsdServiceInfo().apply {
                serviceName = "MyServiceTest"
                serviceType = SERVICE_TYPE
                port = 80
            }

            val registrationListener = object : NsdManager.RegistrationListener {

                override fun onServiceRegistered(NsdServiceInfo: NsdServiceInfo) {}

                override fun onRegistrationFailed(serviceInfo: NsdServiceInfo,errorCode: Int) {}

                override fun onServiceUnregistered(arg0: NsdServiceInfo) {
                }

                override fun onUnregistrationFailed(serviceInfo: NsdServiceInfo,errorCode: Int) {}
            }

            val nsdManager = (getSystemService(Context.NSD_SERVICE) as NsdManager).apply {
                registerService(serviceInfo,NsdManager.PROTOCOL_DNS_SD,registrationListener)
            }

            // Instantiate a new discoveryListener
            val discoveryListener = object : NsdManager.discoveryListener {

                override fun ondiscoveryStarted(regType: String) {
                }

                override fun onServiceFound(service: NsdServiceInfo) {
                    servicetoResolve.add(service)
                }

                override fun onServiceLost(service: NsdServiceInfo) {}

                override fun ondiscoveryStopped(serviceType: String) {}

                override fun onStartdiscoveryFailed(serviceType: String,errorCode: Int) {
                    nsdManager.stopServicediscovery(this)
                }

                override fun onStopdiscoveryFailed(serviceType: String,errorCode: Int) {
                    nsdManager.stopServicediscovery(this)
                }
            }

            nsdManager.discoverServices(SERVICE_TYPE,discoveryListener)

            delay(5000)

            resolveService(nsdManager)
        }
    }

    private fun resolveService(nsdManager: NsdManager) {
        if (servicetoResolve.size > index) {
            nsdManager.resolveService(servicetoResolve[index],object : NsdManager.ResolveListener {
                override fun onResolveFailed(serviceInfo: NsdServiceInfo?,errorCode: Int) {
                    index++
                    resolveService(nsdManager)
                }

                override fun onServiceResolved(serviceInfo: NsdServiceInfo?) {
                    Log.d(TAG,"onServiceResolved : $serviceInfo || ${serviceInfo?.attributes}")
                    index++
                    resolveService(nsdManager)
                }

            })
        } else {
            Log.d(TAG,"nothing to resolve")
        }
    }

}

代码在 Android 7 到 11 上正常工作。但在 Android 6 上无法正常工作。我可以正确解析服务,但根据日志,它不包含任何属性

Log.d(TAG,"onServiceResolved : $serviceInfo || ${serviceInfo?.attributes}")

例如,Android 6.0 上的结果:

onServiceResolved : name: TJA470 (TJA470-F40103),type: ._http._tcp,host: /10.0.0.177,port: 80 || {}

这里是 Android 11 上的结果:

onServiceResolved : name: TJA470 (TJA470-F40103),port: 80,txtRecord: 1device.type=urn:schemas-hager-com:device:tja470: 1device.modelName=TJA470 export=Yes$device.modelURL=http://www.hager.comdevice.hostName=TJA470-F40103device.manufacturer=Hagerdevice.ip=10.0.0.1771device.modelDescription=Hager Pilot Configuration+device.manufacturerURL=http://www .hager.com(device.UDN=uuid:M2VSZEVUELAJYECHAJLU1708 device.UPC=470,device.serialNumber=M2VSZEVUELAJYECHAJLU1708device.modelNumber=3.1.15'presentationURL=http://TJA470-F40103.JA70TName=80TJA470 -F40103) || {device.type=[117,114,110,58,115,99,104,101,109,97,45,103,9,41,100,118,105,116,106,52,55,48,49],device.modelName=[84,74,65,48],export=[89,115],device.modelURL=[104,112,47,119,46,140,111,109],device.hostName=[84,70,49,51],device.manufacturer=[72,114],device.ip=[49,55],device.modelDescription=[72,1 14,32,80,108,67,102,117,er.110 uact[102,117] 116,device.UDN=15,171 100,77,50,86,83,90,69,85,76,89,72,8,56],device.UPC=[52,device.serialNumber=[77,device.modelNumber=[51,53],presentationURL=[104,84,51,56,device.friendlyName=[84,40,41]}

如您所见,这些属性出现在 Android 11 上,而不是在 Android 6.0 上。是 Android 6.0 上的 NSD_SERVICE 的问题还是我开发的 POC 的问题?

NsdServiceInfo 类已在 API 16 中添加,而 getAttributes 方法已在 API 21 中添加。因此通常一切都应在 Android 6.0 上正常工作:(

解决方法

问题不在我的代码中,而是在 Android SDK 中,根据 this ticket

在 Android 5 和 6 上,我需要使用第三方库,例如 Jmdns