web-dev-qa-db-fra.com

Implémentation de Bonjour sur Android

J'essaie d'implémenter bonjour/zero conf sur mon Android. J'utilise la bibliothèque jmDns pour rechercher tous les appareils disponibles. Voici le code que j'utilise pour rechercher les appareils dans le même réseau:

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();
        }
    }
}

Fondamentalement, je les ajoute dans une liste afin de pouvoir afficher une liste de tous les appareils disponibles. Maintenant, lorsque j'exécute ce code, je ne reçois aucune exception/rien de tel qu'une erreur. Mais d'un autre côté, rien n'est ajouté à ma liste [PS: il y a au moins 5-6 PC et Mac dans le réseau.

J'ai également essayé d'obtenir la liste de ce code:

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

listener est défini dans le onCreate de l'activité. Mais cela n'a pas non plus restitué aucun appareil.

Aidez-moi, suggérez ce que je fais mal ici. Toute aide est appréciée!

30
mudit

Android 4.1 ajoute Découverte du service résea qui semble simplement emballer la pile Bonjour en termes différents. Je vois également une API de niveau inférieur appelée Android.net.wifi.p2p.WifiP2pManager qui expose DNS-SD (ainsi que UPnP?) Directement.

Notez que le démon sous-jacent mDNSResponder ne semble pas fonctionner tout le temps et n'est pas utilisé pour les recherches DNS à l'échelle du système (par exemple à partir d'un navigateur) pour autant que je sache pour le moment.

17
natevw

Je ne peux pas vous aider spécifiquement avec le code mais je suis sûr qu'il y a des problèmes avec Android et mDNS au moins avec certains combinés et (je crois) l'émulateur.

Plus d'informations ici:

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

5
CMF

Comme indiqué dans les commentaires ci-dessus, le support natif Android ne fonctionne pas et/ou n'est pas complètement implémenté pour permettre la récupération des enregistrements TXT (à partir de Android v5.1). Je n'ai pas pu non plus faire fonctionner la bibliothèque jmDns pour la découverte. J'ai finalement trouvé le projet mdnsjava et cela a fonctionné très facilement pour moi. Notez que son exemple de code n'est pas correct. Voici un exemple de code que j'ai utilisé pour trouver de manière synchrone toutes les imprimantes IPP:

    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();
    }

Notez également que vous devez ajouter la bibliothèque dnsjava à votre dossier libs et à votre build.gradle. J'ai utilisé la version 2.1.7.

4
Matt__C

Savez-vous que la multidiffusion est activée sur votre téléphone? Voir http://home.heeere.com/tech-androidjmdns.html .

Et vous devriez probablement rechercher les services "_ipp._tcp.local" (ou quelque chose de similaire) au lieu des services "_http.tcp". Mais c'est juste pour les tests, non? :-)

4
gmw

Vous pouvez utiliser un outil existant du Play Store d'Android pour analyser le réseau local en premier, comme "bonjour browser" pour vous assurer qu'il existe les services que vous souhaitez analyser. Ensuite, vous pouvez vérifier le mot clé jmDNS pour analyser le réseau.

Mais il est connu que jmDns ne fonctionne pas sur certains appareils Android 4.x.

3
Zephyr