Реализация Bonjour на Android

Я пытаюсь реализовать bonjour / zero conf в своем приложении для Android. Я использую библиотеку jmDns для поиска всех доступных устройств. Вот код, который я использую для поиска устройств в той же сети:

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

По сути, я добавляю их в список, чтобы отображать список всех доступных устройств. Теперь, когда я запускаю этот код, я не получаю никаких исключений / ничего похожего на ошибку. Но с другой стороны, в мой список ничего не добавляется [PS: в сети есть как минимум 5-6 ПК и Mac.

Я также пытался получить список из этого кода:

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

listener определяется в onCreate деятельности. Но и это ни одно устройство не вернуло.

Пожалуйста, помогите, подскажите, что я здесь делаю не так. Любая помощь приветствуется!


person mudit    schedule 11.01.2011    source источник
comment
Разве вы не должны использовать этот код: if (! InetAddress.isLoopbackAddress () &&! InetAddress.isLinkLocalAddress () && inetAddress.isSiteLocalAddress ())   -  person Radu    schedule 13.03.2013
comment
@mudit. Насколько я понимаю, прошло некоторое время с тех пор, как вы столкнулись с этой проблемой. Вы пробовали использовать _http._tcp вместо _http._tcp.local .. Я не могу объяснить почему, но в моем случае это имеет значение. Пока это имеет значение только при использовании NsdManager (стандартное обнаружение Android). Я узнаю, как это может повлиять на поиск JmDNS позже, как только наш пользователь с проблемой попробует это ...   -  person vladimir    schedule 30.10.2014


Ответы (5)


В Android 4.1 добавлено обнаружение сетевых служб, которое, похоже, только завершается. стек Bonjour в разных терминах. Я также вижу API нижнего уровня под названием android.net.wifi. p2p.WifiP2pManager, который напрямую предоставляет DNS-SD (а также UPnP?).

Обратите внимание, что базовый демон mDNSResponder, похоже, не работает все время и не используется для общесистемного поиска DNS (например, из браузера), насколько я могу судить прямо сейчас.

person natevw    schedule 30.10.2012
comment
И Network Service Discovery, и Bonjour являются реализациями Zeroconf, а не оберткой другого. - person Trisped; 09.05.2013
comment
Пожалуйста, не используйте это, пока Android не решит проблемы, связанные с обнаружением сетевых служб. Эти проблемы упоминаются как: 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=39750 - person Darshit Patel; 22.05.2013
comment
Я обнаружил, что Android NDS работает лучше, чем mdnsjava, на который есть ссылки в некоторых других комментариях здесь (с использованием Android 5). К сожалению, он по-прежнему не дает тех результатов, которые я вижу в приложении Bonjour Browser. - person Bill; 09.04.2016
comment
Android API полезен только для получения имен служб, IP-адресов и портов. Хотя API технически поддерживает дополнительную информацию (текст), вы обнаружите, что он не работает на 99% устройств. - person bremen_matt; 09.01.2017

Я не могу вам помочь с кодом, но я почти уверен, что есть проблемы с Android и mDNS, по крайней мере, с некоторыми телефонами и (я считаю) эмулятором.

Больше информации здесь:

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

person CMF    schedule 11.01.2011

Знаете ли вы, что на вашем телефоне включена многоадресная рассылка? См. http://home.heeere.com/tech-androidjmdns.html.

И вам, вероятно, следует искать "_ipp._tcp.local" (или что-то подобное) вместо служб "_http.tcp". Но это только для тестирования, правда? :-)

person gmw    schedule 11.08.2011

Как отмечалось в комментариях выше, встроенная поддержка Android не работает и / или не реализована полностью, чтобы разрешить получение записей TXT (начиная с Android v5.1). Мне также не удалось заставить работать библиотеку jmDns на обнаружение. Наконец я нашел проект mdnsjava, и он очень легко сработал для меня. Обратите внимание, что его пример кода неверен. Вот пример кода, который я использовал для синхронного поиска всех принтеров 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();
    }

Также обратите внимание, что вам необходимо добавить библиотеку dnsjava в папку libs и build.gradle. Я использовал версию 2.1.7.

person Matt__C    schedule 06.08.2015

Вы можете использовать существующий инструмент из Android Play Store, чтобы сначала просканировать локальную сеть, например «bonjour browser», чтобы убедиться, что есть сервисы, которые вы хотите просканировать. Затем вы можете проверить ключевое слово jmDNS для сканирования сети.

Но есть известная проблема: jmDns не работает на некоторых устройствах Android 4.x.

person Zephyr    schedule 11.06.2014
comment
Привет @Zephyr. Вы сказали, что это известная проблема, что jmDns не работает на некоторых устройствах Android 4.x. Вы знаете подробности? Какие есть причины? У нас есть один пользователь с этой проблемой. Браузер Bonjour у него работает хорошо, но через библиотеку jmDns ничего не удалось обнаружить. Пока что ваш комментарий здесь - единственное подтверждение, что проблема с jmDns не только у меня ... - person vladimir; 30.10.2014
comment
Привет @vladimir, в процессе разработки мы подтвердили, что JmDNS не работает на некоторых устройствах Android 4.1, он работает на устройствах с версией ниже 4.1. возможно, причина в реализации JmDNS на платформе Android, потому что исходная реализация Bonjour была на платформе iOS, но не так удобна, как iOS. Кстати, родной NSD для Android тоже ненадежен на ранних версиях 4.x, много вылетает. - person Zephyr; 30.10.2014
comment
@Zyphyr, а какую библиотеку вы используете, чтобы наконец открыть для себя? Я думаю об обнаружении через JmDNS и NSD, а затем показать пользователю некоторые итоговые результаты. Как вы думаете, сейчас есть варианты получше? - person vladimir; 30.10.2014
comment
@vladimir, спасибо за ваш голос, я хотел бы предложить вам адаптировать реализацию iOS Bonjour к платформе Android, вы получите встроенную библиотеку .so и библиотеку jar для работы. Мы сделали это за несколько месяцев до этого, он работает лучше, чем JmDNS и NSD. - person Zephyr; 30.10.2014
comment
Похоже, Google уже кое-что сделал: android.googlesource.com/platform/external/mdnsresponder Как вы думаете, в НРД это не используется? Боюсь, что я не лучше оборачиваю нативный код в библиотеку Android, чем разработчики из команды Android. - person vladimir; 31.10.2014
comment
@vladimir, я проверил исходный код в указанной вами ветке, там есть строчка Copyright (c) 2002-2003 Apple Computer, Inc. Все права защищены. в части авторского права, поэтому я полагаю, что код взят от Apple и не используется в NSD. На самом деле мы используем аналогичный код, но непосредственно с веб-сайта Apple для создания нашей собственной библиотеки .so. - person Zephyr; 01.11.2014
comment
На каких устройствах mDNS не работает? Исходя из моего опыта, у меня возникают проблемы с некоторыми планшетами Samsung. - person gregm; 16.06.2015
comment
@gregm, это был планшет Samsung GT-P5113. Я предполагаю, что в структуре Android возникла какая-то проблема. - person Zephyr; 16.06.2015
comment
У меня есть планшет Samsung SM-T110. Все еще не могу понять проблему. Это может быть проблема и с моим роутером Belkin. - person gregm; 17.06.2015
comment
@ gregm , вы можете использовать устройство iOS для перекрестного сравнения, возможно, вы можете исключить маршрутизатор Belkin из списка подозреваемых. - person Zephyr; 17.06.2015