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 API levels 16 and up, and I can't seem to retrieve the txtRecord field within the service info (it returns null for some reason). Turns out it's a known problem...
So now I'm trying to work with jmDNS, which doesn't seem to find services at all. here's my class (I'm working with the AndroidAnnotations framework) MDnsHelper:
@EBean
public class MDnsHelper implements ServiceListener {
public static final String SERVICE_TYPE = "_http._tcp.local";
Activity activity;
private JmDNS jmdns;
private MulticastLock multicastLock;
WifiManager wm;
InetAddress bindingAddress;
boolean isDiscovering;
public void init(Activity activity) {
this.activity = activity;
isDiscovering = false;
wm = (WifiManager) activity.getSystemService(Context.WIFI_SERVICE);
multicastLock = wm.createMulticastLock(activity.getPackageName());
multicastLock.setReferenceCounted(false);
}
@Background
public void startDiscovery() {
if (isDiscovering)
return;
System.out.println("starting...");
multicastLock.acquire();
try {
System.out.println("creating jmdns");
jmdns = JmDNS.create();
System.out.println("jmdns created");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (jmdns != null) {
jmdns.addServiceListener(SERVICE_TYPE, MDnsHelper.this);
isDiscovering = true;
System.out.println("discovering services of type: " + SERVICE_TYPE);
}
}
}
@Background
public void stopDiscovery() {
if (!isDiscovering || jmdns == null)
return;
System.out.println("stopping...");
multicastLock.release();
jmdns.removeServiceListener(SERVICE_TYPE, MDnsHelper.this);
System.out.println("listener for " + SERVICE_TYPE + " removed");
try {
jmdns.close();
isDiscovering = false;
System.out.println("jmdns closed");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void serviceAdded(ServiceEvent service) {
System.out.println("found: " + service.getInfo().toString());
}
@Override
public void serviceRemoved(ServiceEvent service) {
System.out.println("lost: " + service.getInfo().toString());
}
@Override
public void serviceResolved(ServiceEvent service) {
System.out.println("resolved: " + service.getInfo().toString());
}
}
And in my app I call:
init(getActivity());
And then startDiscovery();
to start scanning and stopDiscovery();
to stop scanning.
And of course, I gave the app the required permissions in the manifest... What am I missing here? If you need me to provide additional code/info - just ask. thanks!!
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.
In your Android manifest.xml make sure you have these permissions at least.
Before starting the activity you must allow multi-cast packets by acquiring a multicast lock.
And don't forget on stopping the scan to unlock the multicast lock and shut down JmDNS.
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.