Bonjour implementation on Android
Asked Answered
S

5

30

I am trying to implement bonjour/zero conf on my android app. I am using jmDns library for searching the all the available devices. Here is the code that I am using for searching the devices in the same network:

public class ListDevices extends ListActivity {
    JmDNS jmdns;
    JmDNSImpl impl;
    MulticastLock lock;
    protected ServiceListener listener;
    protected ServiceInfo info;
    public ListView lv;
    public ArrayList<String> deviceList;
    public int cancel = 0;
    public final static String TAG = "ListDevices";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        deviceList = new ArrayList<String>();
        showAllPrinters();

        setListAdapter(new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, deviceList));

        lv = getListView();
        lv.setTextFilterEnabled(true);

        lv.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                // When clicked, show a toast with the TextView text
                Toast.makeText(getApplicationContext(),
                       ((TextView) view).getText(), Toast.LENGTH_SHORT).show();
            }
        });
        this.listener = new ServiceListener() {
            public void serviceAdded(ServiceEvent event) {
                deviceList.add("Service added   : " + event.getName() + "."
                        + event.getType());
                Log.v(TAG, "Service added   : " + event.getName() + "."
                        + event.getType());
            }

            public void serviceRemoved(ServiceEvent event) {
                deviceList.add("Service removed : " + event.getName() + "."
                        + event.getType());
                Log.v(TAG, "Service removed : " + event.getName() + "."
                        + event.getType());
            }

            public void serviceResolved(ServiceEvent event) {
                deviceList.add("Service resolved: " + event.getInfo());
                Log.v(TAG, "Service resolved: " + event.getInfo());
            }
        };
    }

    public void showAllPrinters() {
        Log.d("ListDevices", "in showAllPrinters");
        try {

            WifiManager wifi = (WifiManager)
                               getSystemService(Context.WIFI_SERVICE);
            lock = wifi.createMulticastLock("fliing_lock");
            lock.setReferenceCounted(true);
            lock.acquire();

            InetAddress inetAddress = getLocalIpAddress();
            jmdns = JmDNS.create(inetAddress, "TEST");

            ServiceInfo[] infos = jmdns.list("_http._tcp.local.");

            if (infos != null && infos.length > 0) {
                for (int i = 0; i < infos.length; i++) {
                    deviceList.add(infos[i].getName());
                }
            } else {
                deviceList.add("No device found.");
            }
            impl = (JmDNSImpl) jmdns;

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public InetAddress getLocalIpAddress() {
        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface
                    .getNetworkInterfaces(); en.hasMoreElements();) {
                NetworkInterface intf = (NetworkInterface) en.nextElement();
                for (Enumeration<InetAddress> enumIpAddr = intf
                        .getInetAddresses(); enumIpAddr.hasMoreElements();) {
                    InetAddress inetAddress = (InetAddress) enumIpAddr
                            .nextElement();
                    if (!inetAddress.isLoopbackAddress()) {
                        return inetAddress;
                    }
                }
            }
        } catch (SocketException ex) {
            Log.e("ListDevices", ex.toString());
        }
        return null;
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (isFinishing()) {
            lock.release();
        }
    }
}

Basically, I am adding them in a list so that I can display a list of all available devices. Now when I am running this code, I am getting no exception/nothing like error. But on the other hand, nothing is added to my list [PS: there atleast 5-6 PCs and Macs are there in the network.

I also tried to get the list from this code:

jmdns.addServiceListener("_http._tcp.local.", listener);

listener is defined in the onCreate of the activity. But this also did not returned any device.

Please help, suggest what I am doing wrong here. Any help is appreciated!

Singlebreasted answered 11/1, 2011 at 10:2 Comment(2)
Shouldn't you be using this code: if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress() && inetAddress.isSiteLocalAddress())Restharrow
@mudit. I understand some time has passed since you run into this problem. Have you tried to list by "_http._tcp" instead of "_http._tcp.local.". I can't explain why, but it makes difference in my case. So far it makes difference only when using NsdManager (standard Android discovery). I will know how it might affect JmDNS lookup later, as soon as our user with the problem will try it...Sylphid
C
20

Android 4.1 adds Network Service Discovery that seems to be just wrapping up the Bonjour stack in different terms. I also see a lower-level API called android.net.wifi.p2p.WifiP2pManager that exposes DNS-SD (as well as UPnP?) directly.

Note that the underlying mDNSResponder daemon does not seem to be running all the time, and is not used for systemwide DNS lookups (e.g. from a browser) as far as I can tell right now.

Chevaldefrise answered 30/10, 2012 at 20:28 Comment(4)
Both Network Service Discovery and Bonjour are implementations of Zeroconf, not wrapping the other.Phage
Please do not use this till android solve Network Service Discovery related issues. These issues are mentioned as : 1).code.google.com/p/android/issues/detail?id=39583 2).code.google.com/p/android/issues/detail?id=35585 3).code.google.com/p/android/issues/detail?id=39750Adulterer
I've found that Android NDS works better than mdnsjava which is referenced in some of the other comments here (using Android 5). It still does not give me the same results that I see in the Bonjour Browser app unfortunately.Epicarp
The Android API is only useful for getting service names, IP addresses, and ports. Although the API technically supports additional info (text), , you will find that it does not work on 99% of devices.Thrashing
H
5

I can't give you any specific help with the code but I'm pretty sure that there are issues with Android and mDNS at least with some handsets and (I believe) the emulator.

More information here:

http://rgladwell.wordpress.com/2010/04/18/gotchas-android-and-multicast-dns/

Hilde answered 11/1, 2011 at 10:31 Comment(0)
H
4

Do you know for a fact that multicast is enabled on your phone? See http://home.heeere.com/tech-androidjmdns.html.

And you should probably looking for "_ipp._tcp.local" (or something similar) instead of "_http.tcp" services. But that's just for testing, right? :-)

Hendrickson answered 11/8, 2011 at 9:22 Comment(0)
M
4

As noted in comments above, the native Android support is not working and/or not implemented completely to allow retrieval of TXT records (as of Android v5.1). I also could not get the jmDns library to work for discovery. I finally found the mdnsjava project and it worked very easily for me. Note that its sample code is not correct. Here is some sample of code I used to synchronously find all IPP printers:

    String type[] = {"_ipp._tcp.local."};
    Lookup resolve = null;
    try {
        resolve = new Lookup(type, Type.ANY, DClass.IN);
        ServiceInstance[] records = resolve.lookupServices();
        for (ServiceInstance record : records) {
            Log.d(TAG, record.toString());
            Map txtMap = record.getTextAttributes();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

Also note that you need to add the dnsjava library to your libs folder and your build.gradle. I used version 2.1.7.

Meissen answered 6/8, 2015 at 20:53 Comment(0)
K
3

You may use an existing tool from Android's Play Store to scan the local network first, like "bonjour browser" to make sure there are the services you want to scan. Then you can check the jmDNS keyword to scan the network.

But there is a known issue that jmDns does not work on some Android 4.x devices.

Keramic answered 11/6, 2014 at 19:12 Comment(10)
Hello @Zephyr. You said that it is known issue that jmDns does not work on some Android 4.x devices. Do you know more details? What are reasons? We have one user with this problem. Bonjour Browser works well for him but nothing could be discovered via jmDns library. So far your comment here - the only confirmation that it's not only me having this problem with jmDns...Sylphid
Hello @vladimir, during development, we confirmed that JmDNS doesn't work on some Android 4.1 devices, it works on devices under 4.1 version. the reason maybe is in the implementation of JmDNS on Android platform, because the original implementation of Bonjour was on the iOS platform, just not as usable as the iOS one. By the way, the Android native NSD is not reliable too on the early 4.x versions, it crashes a lot.Keramic
@Zyphyr, so what library you are using to discover finally? I'm thinking of discovering through both JmDNS and NSD and then showing some sum results to the user. Do you think there are better options for now?Sylphid
@vladimir, thanks for your vote, I would like to suggest you to adapt the iOS Bonjour implementation to Android platform, you will get a native .so library and jar library to work with. We did it a few month before, it works better than JmDNS and NSD.Keramic
It looks like Google has already somrthing done there: android.googlesource.com/platform/external/mdnsresponder Do you think this is not used in NSD? I'm just afraid that I'm not better in wrapping native code into Android lib than developers from Android teamSylphid
@vladimir, I checked the source code in the branch you mentioned, there is the line of "Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved." in the copyright part, so I suppose that code are from Apple and not used in NSD. Actually we use the similar code but from Apple website directly to build our .so native library.Keramic
Which devices does mDNS fail to work on? Based on my experience, I am having trouble with some Samsung tabletsGyniatrics
@gregm, that was a Samsung tablet, GT-P5113. I guess there was some issue within the Android framework.Keramic
I have the SM-T110 Samsung Tablet here. Still can't figure out the problem. It could be a problem with my Belkin router as wellGyniatrics
@gregm,you can use an iOS device to do a cross comparison, maybe you might exclude the Belkin router out of the suspect list.Keramic

© 2022 - 2024 — McMap. All rights reserved.