2011-01-11 20 views
26

Próbuję zaimplementować bonjour/zero conf na mojej aplikacji na Androida. Używam biblioteki jmDns do przeszukiwania wszystkich dostępnych urządzeń. Oto kod, który używam do wyszukiwania urządzeń w tej samej sieci:Implementacja Bonjour na Androidzie

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

Zasadniczo, dodaję je na liście tak, że mogę wyświetlić listę wszystkich dostępnych urządzeń. Teraz, gdy uruchamiam ten kod, nie dostaję żadnego wyjątku/niczego takiego jak błąd. Ale z drugiej strony nic nie jest dodawane do mojej listy [PS: w sieci jest co najmniej 5-6 komputerów PC i Maców.

Próbowałem również uzyskać listę z tym kodem:

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

listener jest zdefiniowana w onCreate aktywności. Ale to też nie zwróciło żadnego urządzenia.

Proszę o pomoc, zasugeruj, co robię źle tutaj. Każda pomoc jest doceniana!

+0

Nie należy używać tego kodu: if (! InetAddress.isLoopbackAddress() &&! InetAddress.isLinkLocalAddress() && inetAdress.isSiteLocalAddress()) – Radu

+0

@mudit.Rozumiem, że minęło trochę czasu, odkąd napotkasz ten problem. Czy próbowałeś listować przez "_http._tcp" zamiast "_http._tcp.local.". Nie potrafię wyjaśnić, dlaczego, ale w mojej sprawie robi różnicę. Do tej pory robi różnicę tylko przy użyciu NsdManager (standardowe wykrywanie Androida). Będę wiedział, jak to może wpłynąć na wyszukiwanie JmDNS później, jak tylko nasz użytkownik z problemem spróbuje go ... – vladimir

Odpowiedz

4

Czy wiesz o tym, że multicast jest włączona w telefonie? Zobacz http://home.heeere.com/tech-androidjmdns.html.

Powinieneś prawdopodobnie szukać "_ipp._tcp.local" (lub czegoś podobnego) zamiast usług "_http.tcp". Ale to tylko do testów, prawda? :-)

17

Android 4.1 dodaje Network Service Discovery, który wydaje się po prostu owijać stos Bonjour na różne sposoby. Widzę także API niskiego poziomu o nazwie android.net.wifi.p2p.WifiP2pManager, który udostępnia bezpośrednio DNS-SD (jak również UPnP?).

Należy zauważyć, że podstawowy demon mDNSResponder wydaje się nie działać cały czas i nie jest używany do wyszukiwania DNS na całym systemie (np. Z przeglądarki), o ile mogę to stwierdzić w tej chwili.

+0

Zarówno Network Service Discovery, jak i Bonjour są implementacjami [Zeroconf] (http://www.zeroconf.org/) , nie owijając drugiego. – Trisped

+5

Proszę nie używać tego do android rozwiązać problemy związane z Network Service Discovery. Te problemy są wymienione jako: 1) .http: //code.google.com/p/android/issues/detail? Id = 39583 2) .https: //code.google.com/p/android/issues/detail ? id = 35585 3) .http: //code.google.com/p/android/issues/detail? id = 39750 –

+0

Zauważyłem, że Android NDS działa lepiej niż mdnsjava, do którego odwołują się niektóre inne komentarze tutaj (używając Androida 5). Nadal nie daje to takich samych wyników, jakie widzę niestety w aplikacji Bonjour Browser. – Bill

2

Możesz użyć istniejącego narzędzia w Sklepie Play Androida, aby najpierw zeskanować sieć lokalną, np. "Przeglądarkę bonjour", aby upewnić się, że istnieją usługi, które chcesz przeskanować. Następnie możesz sprawdzić słowo kluczowe jmDNS, aby zeskanować sieć.

Ale jest znany problem, że jmDns nie działa na niektórych urządzeniach z Androidem 4.x.

+0

Witaj @ Zephyr. Powiedziałeś, że jest to znany problem, że jmDns nie działa na niektórych urządzeniach z Androidem 4.x. Czy znasz więcej szczegółów? Jakie są powody? Mamy jednego użytkownika z tym problemem. Bonjour Browser działa dobrze dla niego, ale nic nie można odkryć w bibliotece jmDns. Do tej pory twój komentarz tutaj - jedyne potwierdzenie, że nie tylko ja mam ten problem z jmDns ... – vladimir

+1

Witam @ Vladladimir, podczas rozwoju, potwierdziliśmy, że JmDNS nie działa na niektórych urządzeniach z Androidem 4.1, działa na urządzeniach pod 4.1 wersja. powodem może być implementacja JmDNS na platformie Android, ponieważ oryginalna implementacja Bonjour była na platformie iOS, po prostu nie tak użyteczna jak iOS. Nawiasem mówiąc, natywna wersja NSD systemu Android nie jest niezawodna także w wersjach wczesnych wersji 4.x, często się zawiesza. – Zephyr

+0

@Zyphyr, więc jakiej biblioteki używasz do odkrycia w końcu? Zastanawiam się nad odkryciem zarówno przez JmDNS, jak i NSD, a następnie pokazywanie użytkownikowi pewnych sum. Czy uważasz, że są teraz lepsze opcje? – vladimir

3

Jak wspomniano w komentarzach powyżej, natywne wsparcie dla systemu Android nie działa i/lub nie jest całkowicie zaimplementowane, aby umożliwić pobieranie rekordów TXT (od wersji Androida w wersji 5.1). Nie mogłem także uruchomić biblioteki jmDns do odkrycia. W końcu znalazłem mdnsjava project i zadziałało to dla mnie bardzo łatwo. Zwróć uwagę, że jego przykładowy kod jest niepoprawny. Oto przykładowy kod Kiedyś synchronicznie znaleźć wszystkie drukarki 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(); 
    } 

także pamiętać, że trzeba dodać dnsjava library do libs folder i swojej build.gradle. Użyłem wersji 2.1.7.