Android - jmdns doesn't discover devices

后端 未结 2 1791
慢半拍i
慢半拍i 2020-12-23 12:22

I\'m trying to implement a class to discover services on the network. I\'ve tried working with Android\'s NSD and it does discover the services fine, but it supports only AP

相关标签:
2条回答
  • 2020-12-23 12:59

    If you are having this error in Android Oreo 8.x, this might help you.

    First, Remember to make sure you have added these permissions into your Android manifest.xml.

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

    Acquire a multicast lock to allow multi-cast packets.

    WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
    MulticastLock lock = wifi.createMulticastLock("jmdns-multicast-lock");
    lock.setReferenceCounted(true);
    lock.acquire();
    

    Now, use only this constructor JmDNS.create(InetAddress addr, String name) to create an instance of JmDNS and bind it to a specific network interface given its IP-address, like this:

    try {
        jmDNS = JmDNS.create(InetAddress.getByName(obtainIPv4Address(info)), HOST_NAME);
    } catch (IOException e) {
        LogHelper.e(TAG, "Error in JmDNS creation: " + e);
    }
    

    Finally, just make sure to call JmDNSunreisterAllServices(), and JmDNS.close() to stop JmDNS stream and releases any system resources associated with it. Also, call MulticastLock.release() to unlock the multicast lock when you're done with it.

    try {
        if (jmDNS != null) {
            jmDNS.unregisterAllServices();
            jmDNS.close();
            jmDNS = null;
        }
        if (lock != null) {
            lock.release();
            lock = null;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    0 讨论(0)
  • 2020-12-23 13:07

    I am the author of ZeroConf Browser for Android and I use the open source Library JmDNS for all my resolving. It works great but there are a few tricks to getting it to work properly.

    1. In your Android manifest.xml make sure you have these permissions at least.

      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
      <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
      
    2. Before starting the activity you must allow multi-cast packets by acquiring a multicast lock.

      @Override
      protected void onStart() {
          Log.i(TAG, "Starting ServiceActivity...");
          super.onStart();
          try {
              Log.i(TAG, "Starting Mutlicast Lock...");
              WifiManager wifi = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
              // get the device ip address
              final InetAddress deviceIpAddress = getDeviceIpAddress(wifi);
              multicastLock = wifi.createMulticastLock(getClass().getName());
              multicastLock.setReferenceCounted(true);
              multicastLock.acquire();
              Log.i(TAG, "Starting ZeroConf probe....");
              jmdns = JmDNS.create(deviceIpAddress, HOSTNAME);
              jmdns.addServiceTypeListener(this);
          } catch (IOException ex) {
              Log.e(TAG, ex.getMessage(), ex);
          }
          Log.i(TAG, "Started ZeroConf probe....");
      }
      
      private InetAddress getDeviceIpAddress(WifiManager wifi) {
         InetAddress result = null;
         try {
            // default to Android localhost
            result = InetAddress.getByName("10.0.0.2");
      
            // figure out our wifi address, otherwise bail
            WifiInfo wifiinfo = wifi.getConnectionInfo();
            int intaddr = wifiinfo.getIpAddress();
            byte[] byteaddr = new byte[] { (byte) (intaddr & 0xff), (byte) (intaddr >> 8 & 0xff),
                (byte) (intaddr >> 16 & 0xff), (byte) (intaddr >> 24 & 0xff) };
            result = InetAddress.getByAddress(byteaddr);
         } catch (UnknownHostException ex) {
            Log.w(TAG, String.format("getDeviceIpAddress Error: %s", ex.getMessage()));
         }
      
         return result;
      }
      
    3. And don't forget on stopping the scan to unlock the multicast lock and shut down JmDNS.

      @Override
      protected void onStop() {
          Log.i(TAG, "Stopping ServiceActivity...");
          super.onStop();
      
          stopScan();
      }
      
      private static void stopScan() {
          try {
              if (jmdns != null) {
                  Log.i(TAG, "Stopping ZeroConf probe....");
                  jmdns.unregisterAllServices();
                  jmdns.close();
                  jmdns = null;
              }
              if (multicastLock != null) {
                  Log.i(TAG, "Releasing Mutlicast Lock...");
                  multicastLock.release();
                  multicastLock = null;
              }
          } catch (Exception ex) {
              Log.e(TAG, ex.getMessage(), ex);
          }
      }
      
    4. Most importanty don't use the default constructor. You must use the IP Address Constructor. I noticed in your code you are just doing JmDNS.create(). I think for some reason the only way it works on Android is to use the contructor below.

      jmdns = JmDNS.create(deviceIpAddress, HOSTNAME);
      
    0 讨论(0)
提交回复
热议问题