未调用Android P2P服务发现回调 [英] Android P2P service discovery callbacks not being called

查看:107
本文介绍了未调用Android P2P服务发现回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚接触Android,正在开发一个可通过WIFI直接交换数据的应用程序,因此我想使用DNS服务发现而不是单纯的P2P发现来获取更多有用的信息,例如设备昵称"等

到目前为止,我已经按照 http://developer上的教程进行操作.android.com/training/connect-devices-wirelessly/index.html 并阅读文档.

我的应用程序似乎已成功注册了它的本地服务,并且始终调用discoverServices的onSuccess回调,但是从未收到其他设备(我正在使用2个设备)上的txtServiceRecord.

这是我的完整代码:

package com.caballero.marco.dnssd_test;

import android.graphics.Color;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener;
import android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener;
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
import android.net.wifi.p2p.WifiP2pManager.ActionListener;
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.TextView;


import java.io.IOException;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;


public class MainActivity extends ActionBarActivity
{
    public static String SERVICE_NAME = "_marcotest";
    private int server_port = 0;
    private WifiP2pManager mManager;
    private Channel channel;
    private ServerSocket serverSocket;
    private TextView txtServiceStatus;
    private Button btnDiscover;
    final HashMap<String, String> buddies = new HashMap<String, String>();
    private ArrayAdapter<String> adapter;
    //private ActionListener serviceDiscoveryListener;
    private WifiP2pDnsSdServiceRequest serviceRequest;
    private DnsSdServiceResponseListener serviceResponseListener;
    private DnsSdTxtRecordListener txtRecordListener;
    private WifiP2pDnsSdServiceInfo serviceInfo;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        /* Load controls */
        txtServiceStatus = (TextView)findViewById(R.id.txtStatus);
        btnDiscover = (Button)findViewById(R.id.btnDiscover);
        btnDiscover.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startServiceDiscovery();
            }
        });

        mManager = (WifiP2pManager)getSystemService(WIFI_P2P_SERVICE);
        channel = mManager.initialize(this, getMainLooper(), null);
        adapter = new ArrayAdapter<String>( this,
                                            android.R.layout.simple_list_item_1,
                                            new ArrayList<String>());
        /* Initialize Socket Server */
        try {
            initializeSocketServer();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

        startRegistration();
        setupDiscoverServices();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    private void startRegistration() {
        //  Create a string map containing information about your service.
        Map record = new HashMap();
        record.put("listenport", String.valueOf(server_port));
        record.put("buddyname", "John Doe" + (int) (Math.random() * 1000));
        record.put("available", "visible");

        // Service information.  Pass it an instance name, service type
        // _protocol._transportlayer , and the map containing
        // information other devices will want once they connect to this one.
        serviceInfo = WifiP2pDnsSdServiceInfo.newInstance(SERVICE_NAME, "._tcp", record);

        // Add the local service, sending the service info, network channel,
        // and listener that will be used to indicate success or failure of
        // the request.
        mManager.addLocalService(channel, serviceInfo, new WifiP2pManager.ActionListener() {
            @Override
            public void onSuccess() {
                // Command successful! Code isn't necessarily needed here,
                // Unless you want to update the UI or add logging statements.
                SpannableString text = new SpannableString("Online");
                text.setSpan(new ForegroundColorSpan(Color.GREEN), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                txtServiceStatus.setText(text);
                Log.v("DnsSDTest", "Service added.");
            }

            @Override
            public void onFailure(int arg0)
            {
                // Command failed.  Check for P2P_UNSUPPORTED, ERROR, or BUSY
                SpannableString text = new SpannableString("Offline");
                text.setSpan(new ForegroundColorSpan(Color.RED), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                txtServiceStatus.setText(text);
            }
        });
    }

    private void initializeSocketServer() throws IOException
    {
        serverSocket = new ServerSocket(0);
        server_port = serverSocket.getLocalPort();
    }

    private void setupDiscoverServices()
    {
        txtRecordListener = new WifiP2pManager.DnsSdTxtRecordListener() {
            @Override
            public void onDnsSdTxtRecordAvailable(String fullDomainName, Map<String, String> txtRecordMap, WifiP2pDevice srcDevice)
            {
                Log.v("DnsSDTest", "DnsSdTxtRecord available -" + txtRecordMap.toString());
                buddies.put(srcDevice.deviceAddress, txtRecordMap.get("buddyname"));
            }
        };

        serviceResponseListener = new DnsSdServiceResponseListener() {
            @Override
            public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice srcDevice)
            {
                // Update the device name with the human-friendly version from
                // the DnsTxtRecord, assuming one arrived.
                srcDevice.deviceName = buddies
                        .containsKey(srcDevice.deviceAddress) ? buddies
                        .get(srcDevice.deviceAddress) : srcDevice.deviceName;

                // Add to the custom adapter defined specifically for showing
                // wifi devices.
                adapter.add(srcDevice.toString());
                adapter.notifyDataSetChanged();
                Log.v("DnsSDTest", "onBonjourServiceAvailable " + instanceName);
            }
        };

        mManager.setDnsSdResponseListeners(channel, serviceResponseListener, txtRecordListener);
        Log.v("DnsSDTest", "Added DNS SD response listeners.");
    }

    private void startServiceDiscovery()
    {
        serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
        mManager.addServiceRequest(channel, serviceRequest, new ActionListener() {
            @Override
            public void onSuccess() {
                Log.v("DnsSDTest", "Service Request added successfully!");
            }

            @Override
            public void onFailure(int reason) {
                Log.v("DnsSDTest", "Failed to add service request!");
            }
        });

        mManager.discoverServices(channel, new ActionListener() {
            @Override
            public void onSuccess() {
                Log.v("DnsSDTest", "Service discovery successfull!");
            }

            @Override
            public void onFailure(int reason) {
                Log.v("DnsSDTest", "Service discovery failed :(");
            }
        });
    }

    @Override
    protected void onPause()
    {
        super.onPause();
        mManager.removeLocalService(channel, serviceInfo, new ActionListener() {
            @Override
            public void onSuccess() {
                Log.v("DnsSDTest", "Removed service");
                serviceInfo = null;
            }

            @Override
            public void onFailure(int reason) {
                Log.v("DnsSDTest", "Failed to remove service");
            }
        });
    }

    @Override
    protected void onResume()
    {
        super.onResume();
        if(serviceInfo == null)
        {
            startRegistration();
        }
    }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();

        try {
            if(!serverSocket.isClosed())
                serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

解决方案

发现1:

仅在使用setupDiscoverServices()附加两个侦听器(服务侦听器和txtrecord侦听器)之后,才需要为这些附加的侦听器创建服务请求并启动发现.您随时可以手动创建服务请求并使用button触发发现服务的方法很容易出错.无法保证在使用按钮调用startServiceDiscovery()之前实际上已连接了侦听器.

解决方案1::在设置DNS SD响应侦听器之后,即在mManager.setDnsSdResponseListeners()之后,尝试调用方法startServiceDiscovery(),而不是单击按钮单击侦听器".

解决方案2:另外,我建议移动您的

'mManager.addServiceRequest(channel, serviceRequest, new ActionListener() {....}'

加入'setupDiscoverServices()'方法并尝试激活'mManager.addServiceRequest''onSuccess()'中的按钮(startServiceDiscovery()).通过这种方式,您可以实现在附加侦听器,注册服务和手动启动发现之间的同步点

下面的链接演示了一个WiFiDirect项目,其中对等方通过网络服务发现相互连接以进行消息交换.这些方法要求网络服务发现对我有用. https://github.com/Hariharan-Gandhi/WiFriends/blob/master/app/src/main/java/tud/cnlab/wifriends/WiFriends.java

发现2: 我还注意到,以下行中使用的服务类型是".tcp".

serviceInfo = WifiP2pDnsSdServiceInfo.newInstance(SERVICE_NAME, "._tcp", record);

但是,根据Android开发人员指南,第二个参数(服务类型)应采用以下格式:"_ protocol._transportlayer". http://developer.android.com/training/connect-devices- wirelessly/nsd.html . 在此处的演示代码developer.android.com/training/connect-devices-wirelessly/nsd-wifi-direct.html中,他们使用了"_presence._tcp",其中"presence"是XMPP的消息传递协议.请在 WifiP2pDnsSdServiceInfo.newInstance 中提供可用的服务类型.. >

我不确定在SVR记录中省略服务名称是否可以接受. [任何有知识的人都请在我输入错误的情况下更新我的信息]

I'm fairly new to Android and I'm working on an application that will exchange data over WIFI direct and I would like to use DNS Service Discovery instead of pure P2P discovery to get more useful information like device "nick names" etc.

So far I've followed the tutorials at http://developer.android.com/training/connect-devices-wirelessly/index.html and read through the documentation.

My application seems to register it's local service successfully and the onSuccess callback from discoverServices is always called, however the txtServiceRecord from other devices (I'm using 2 devices) is never received.

Here's my full code:

package com.caballero.marco.dnssd_test;

import android.graphics.Color;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener;
import android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener;
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
import android.net.wifi.p2p.WifiP2pManager.ActionListener;
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.TextView;


import java.io.IOException;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;


public class MainActivity extends ActionBarActivity
{
    public static String SERVICE_NAME = "_marcotest";
    private int server_port = 0;
    private WifiP2pManager mManager;
    private Channel channel;
    private ServerSocket serverSocket;
    private TextView txtServiceStatus;
    private Button btnDiscover;
    final HashMap<String, String> buddies = new HashMap<String, String>();
    private ArrayAdapter<String> adapter;
    //private ActionListener serviceDiscoveryListener;
    private WifiP2pDnsSdServiceRequest serviceRequest;
    private DnsSdServiceResponseListener serviceResponseListener;
    private DnsSdTxtRecordListener txtRecordListener;
    private WifiP2pDnsSdServiceInfo serviceInfo;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        /* Load controls */
        txtServiceStatus = (TextView)findViewById(R.id.txtStatus);
        btnDiscover = (Button)findViewById(R.id.btnDiscover);
        btnDiscover.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startServiceDiscovery();
            }
        });

        mManager = (WifiP2pManager)getSystemService(WIFI_P2P_SERVICE);
        channel = mManager.initialize(this, getMainLooper(), null);
        adapter = new ArrayAdapter<String>( this,
                                            android.R.layout.simple_list_item_1,
                                            new ArrayList<String>());
        /* Initialize Socket Server */
        try {
            initializeSocketServer();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

        startRegistration();
        setupDiscoverServices();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    private void startRegistration() {
        //  Create a string map containing information about your service.
        Map record = new HashMap();
        record.put("listenport", String.valueOf(server_port));
        record.put("buddyname", "John Doe" + (int) (Math.random() * 1000));
        record.put("available", "visible");

        // Service information.  Pass it an instance name, service type
        // _protocol._transportlayer , and the map containing
        // information other devices will want once they connect to this one.
        serviceInfo = WifiP2pDnsSdServiceInfo.newInstance(SERVICE_NAME, "._tcp", record);

        // Add the local service, sending the service info, network channel,
        // and listener that will be used to indicate success or failure of
        // the request.
        mManager.addLocalService(channel, serviceInfo, new WifiP2pManager.ActionListener() {
            @Override
            public void onSuccess() {
                // Command successful! Code isn't necessarily needed here,
                // Unless you want to update the UI or add logging statements.
                SpannableString text = new SpannableString("Online");
                text.setSpan(new ForegroundColorSpan(Color.GREEN), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                txtServiceStatus.setText(text);
                Log.v("DnsSDTest", "Service added.");
            }

            @Override
            public void onFailure(int arg0)
            {
                // Command failed.  Check for P2P_UNSUPPORTED, ERROR, or BUSY
                SpannableString text = new SpannableString("Offline");
                text.setSpan(new ForegroundColorSpan(Color.RED), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                txtServiceStatus.setText(text);
            }
        });
    }

    private void initializeSocketServer() throws IOException
    {
        serverSocket = new ServerSocket(0);
        server_port = serverSocket.getLocalPort();
    }

    private void setupDiscoverServices()
    {
        txtRecordListener = new WifiP2pManager.DnsSdTxtRecordListener() {
            @Override
            public void onDnsSdTxtRecordAvailable(String fullDomainName, Map<String, String> txtRecordMap, WifiP2pDevice srcDevice)
            {
                Log.v("DnsSDTest", "DnsSdTxtRecord available -" + txtRecordMap.toString());
                buddies.put(srcDevice.deviceAddress, txtRecordMap.get("buddyname"));
            }
        };

        serviceResponseListener = new DnsSdServiceResponseListener() {
            @Override
            public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice srcDevice)
            {
                // Update the device name with the human-friendly version from
                // the DnsTxtRecord, assuming one arrived.
                srcDevice.deviceName = buddies
                        .containsKey(srcDevice.deviceAddress) ? buddies
                        .get(srcDevice.deviceAddress) : srcDevice.deviceName;

                // Add to the custom adapter defined specifically for showing
                // wifi devices.
                adapter.add(srcDevice.toString());
                adapter.notifyDataSetChanged();
                Log.v("DnsSDTest", "onBonjourServiceAvailable " + instanceName);
            }
        };

        mManager.setDnsSdResponseListeners(channel, serviceResponseListener, txtRecordListener);
        Log.v("DnsSDTest", "Added DNS SD response listeners.");
    }

    private void startServiceDiscovery()
    {
        serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
        mManager.addServiceRequest(channel, serviceRequest, new ActionListener() {
            @Override
            public void onSuccess() {
                Log.v("DnsSDTest", "Service Request added successfully!");
            }

            @Override
            public void onFailure(int reason) {
                Log.v("DnsSDTest", "Failed to add service request!");
            }
        });

        mManager.discoverServices(channel, new ActionListener() {
            @Override
            public void onSuccess() {
                Log.v("DnsSDTest", "Service discovery successfull!");
            }

            @Override
            public void onFailure(int reason) {
                Log.v("DnsSDTest", "Service discovery failed :(");
            }
        });
    }

    @Override
    protected void onPause()
    {
        super.onPause();
        mManager.removeLocalService(channel, serviceInfo, new ActionListener() {
            @Override
            public void onSuccess() {
                Log.v("DnsSDTest", "Removed service");
                serviceInfo = null;
            }

            @Override
            public void onFailure(int reason) {
                Log.v("DnsSDTest", "Failed to remove service");
            }
        });
    }

    @Override
    protected void onResume()
    {
        super.onResume();
        if(serviceInfo == null)
        {
            startRegistration();
        }
    }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();

        try {
            if(!serverSocket.isClosed())
                serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

解决方案

Finding 1:

Only after you attach the both the listeners(Service listener and the txtrecord listener) using setupDiscoverServices(), you need to create a Service Request for these attached listners and initiate the discovery. You approach to manually create a Service Request at any time and trigger discover services using a button , is error prone. There is no guarantee that the listeners are actually attached before calling startServiceDiscovery() using a button.

Solution1: Try to call the method, startServiceDiscovery(), after setting up the DNS SD Response listeners i.e. after mManager.setDnsSdResponseListeners(), instead of calling on the button click Listener.

Solution2: Else, I would suggest, move your

'mManager.addServiceRequest(channel, serviceRequest, new ActionListener() {....}'

part into the 'setupDiscoverServices()' method and try to activate the button(startServiceDiscovery()) in the 'onSuccess()' of the 'mManager.addServiceRequest'. By this way you could achieve a synchronization point between attaching listeners, registering service and starting discovery(manually)

The below link demonstrates a WiFiDirect project wherein the peers connect with each other through the network service discovery for message exchange. This order of the methods calls for network service discovery worked for me. https://github.com/Hariharan-Gandhi/WiFriends/blob/master/app/src/main/java/tud/cnlab/wifriends/WiFriends.java

Finding 2: I also noticed that that service type used in the following line is ".tcp".

serviceInfo = WifiP2pDnsSdServiceInfo.newInstance(SERVICE_NAME, "._tcp", record);

However as per Android developer guide, the second parameter(service type) should be of the format: "_protocol._transportlayer". http://developer.android.com/training/connect-devices-wirelessly/nsd.html. In the demo code here, developer.android.com/training/connect-devices-wirelessly/nsd-wifi-direct.html, they have used "_presence._tcp" where "presence" is a messaging protocol of XMPP. Refer the detailed explanation here, Available service types in WifiP2pDnsSdServiceInfo.newInstance.

I am not sure if it is acceptable to omit the Service name in the SVR record [Anybody with knowledge abt this part kindly update me if I am wrong]

这篇关于未调用Android P2P服务发现回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆