【问题标题】:Bonjour implementation on AndroidBonjour 在 Android 上的实现
【发布时间】:2011-06-07 01:59:01
【问题描述】:

我正在尝试在我的 android 应用上实现 bonjour/zero conf。我正在使用 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 台 PC 和 Mac。

我也尝试从这段代码中获取列表:

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

listener 在活动的onCreate 中定义。但这也没有返回任何设备。

请帮忙,建议我在这里做错了什么。任何帮助表示赞赏!

【问题讨论】:

  • 你不应该使用这个代码吗:if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress() && inetAddress.isSiteLocalAddress())
  • @mudit。我知道你遇到这个问题已经过去了一段时间。您是否尝试通过“_http._tcp”而不是“_http._tcp.local”列出。我无法解释为什么,但它对我的情况有所不同。到目前为止,只有在使用 NsdManager(标准 Android 发现)时才会有所不同。稍后我会知道它可能如何影响 JmDNS 查找,只要我们有问题的用户尝试它...

标签: android bonjour zeroconf jmdns


【解决方案1】:

我无法为您提供有关代码的任何具体帮助,但我很确定至少在某些手机和(我相信)模拟器方面存在 Android 和 mDNS 问题。

更多信息在这里:

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

【讨论】:

    【解决方案2】:

    您知道您的手机上启用了多播吗?见http://home.heeere.com/tech-androidjmdns.html

    您可能应该寻找“_ipp._tcp.local”(或类似的东西)而不是“_http.tcp”服务。但这只是为了测试,对吧? :-)

    【讨论】:

      【解决方案3】:

      Android 4.1 添加了Network Service Discovery,这似乎只是在以不同的方式包装 Bonjour 堆栈。我还看到了一个名为android.net.wifi.p2p.WifiP2pManager 的较低级别的 API,它直接公开了 DNS-SD(以及 UPnP?)。

      请注意,据我所知,底层 mDNSResponder 守护程序似乎并非一直在运行,并且不用于系统范围的 DNS 查找(例如从浏览器)。

      【讨论】:

      【解决方案4】:

      您可以先使用 Android Play 商店中的现有工具扫描本地网络,例如“bonjour 浏览器”,以确保存在您要扫描的服务。然后你可以检查 jmDNS 关键字来扫描网络。

      但有一个已知问题是 jmDns 无法在某些 Android 4.x 设备上运行。

      【讨论】:

      • 你好@Zephyr。您说 jmDns 在某些 Android 4.x 设备上不起作用是已知问题。你知道更多细节吗?原因是什么?我们有一个用户遇到了这个问题。 Bonjour 浏览器对他很有效,但通过 jmDns 库无法发现任何内容。到目前为止,您在此处的评论 - 唯一确认 jmDns 有这个问题的不仅仅是我......
      • 您好@vladimir,在开发过程中,我们确认JmDNS 不适用于某些Android 4.1 设备,它适用于4.1 版本以下的设备。原因可能是在Android平台上JmDNS的实现,因为Bonjour最初的实现是在iOS平台上,只是不如iOS平台好用。顺便说一句,Android 原生 NSD 在早期的 4.x 版本上也不可靠,经常崩溃。
      • @Zyphyr,那么您最终使用什么库来发现?我正在考虑通过 JmDNS 和 NSD 进行发现,然后向用户显示一些总和结果。您认为目前有更好的选择吗?
      • @vladimir,感谢您的投票,我建议您将 iOS Bonjour 实现适配到 Android 平台,您将获得一个可使用的原生 .so 库和 jar 库。我们几个月前做过,它比 JmDNS 和 NSD 效果更好。
      • 看来谷歌已经在那儿做了一些事情:android.googlesource.com/platform/external/mdnsresponder你认为这在 NSD 中没有使用吗?我只是担心我在将原生代码包装到 Android lib 方面并不比 Android 团队的开发人员更好
      【解决方案5】:

      如上面的 cmets 中所述,原生 Android 支持不起作用和/或未完全实现以允许检索 TXT 记录(从 Android v5.1 开始)。我也无法让 jmDns 库为发现工作。我终于找到了mdnsjava project,它对我来说非常容易。请注意,其示例代码不正确。这是我用来同步查找所有 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 library 添加到您的 libs 文件夹和 build.gradle。我使用的是 2.1.7 版本。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-03
        • 2012-02-18
        相关资源
        最近更新 更多