30

Wifi P2P 服务发现未按预期运行。我看到不总是调用 DNSSD 侦听器的间歇性问题,因此我不知道附近设备运行相同的应用程序。我正在使用以下两个 API - 一个用于注册要被其他设备发现的服务,另一个用于发现在其他设备上运行的附近服务。知道我在这里做错了什么,或者在我调用这些 API 之前是否需要进行一些特定的其他 android API 调用序列,以确保在注册新服务时始终调用侦听器,或者即使服务在我们调用 API 发现本地服务之前注册。

注册本地服务的 API:

private void registerService() {
    Map<String, String> values = new HashMap<String, String>();
    values.put("name", "Steve");
    values.put("port", "8080");
    WifiP2pServiceInfo srvcInfo = WifiP2pDnsSdServiceInfo.newInstance(mMyDevice.deviceName, "_http._tcp", values);

    manager.addLocalService(channel, srvcInfo, new WifiP2pManager.ActionListener() {

        @Override
        public void onSuccess() {
            Toast.makeText(WiFiDirectActivity.this, "Local service added successfully", 
                Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onFailure(int reasonCode) {
            Toast.makeText(WiFiDirectActivity.this, "Local service addition failed : " + reasonCode,
                    Toast.LENGTH_SHORT).show();
        }
    });
}

用于发现本地服务的 API:

public void discoverService() {

    manager.clearServiceRequests(channel, null);

    DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {
        @Override
        /* Callback includes:
         * fullDomain: full domain name: e.g "printer._ipp._tcp.local."
         * record: TXT record data as a map of key/value pairs.
         * device: The device running the advertised service.
         */
        public void onDnsSdTxtRecordAvailable(String fullDomain, Map record, WifiP2pDevice device) {
            Log.d(TAG, "DnsSdTxtRecord available -" + record.toString());
        }
    };

    DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() {
        @Override
        public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice resourceType) {
            Log.d(TAG, "onBonjourServiceAvailable " + instanceName);
        }
    };

    manager.setDnsSdResponseListeners(channel, servListener, txtListener);

    WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
    manager.addServiceRequest(channel, serviceRequest, new ActionListener() {

        @Override
        public void onSuccess() {
            // Success!
            Log.d(TAG, "addServiceRequest success");
        }

        @Override
        public void onFailure(int code) {
            // Command failed.  Check for P2P_UNSUPPORTED, ERROR, or BUSY
            Log.d(TAG, "addServiceRequest failure with code " + code);
        }

    });
    manager.discoverServices(channel, new ActionListener() {

        @Override
        public void onSuccess() {
            // Success!
            Log.d(TAG, "discoverServices success");
        }

        @Override
        public void onFailure(int code) {
            // Command failed.  Check for P2P_UNSUPPORTED, ERROR, or BUSY
            if (code == WifiP2pManager.P2P_UNSUPPORTED) {
                Log.d(TAG, "P2P isn't supported on this device.");
            } else {
                Log.d(TAG, "discoverServices failure");
            }
        }
    });
}

注意:manager & channel 初始化为

WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
Channel channel = manager.initialize(this, getMainLooper(), null);
4

2 回答 2

37

WifiP2p(一般来说):

前段时间,我正在开发一个应用程序,该应用程序具有基于 with 的非常复杂的网络连接WifiP2p系统Service Broadcasting/Discovery。基于那次经验,我已经在这里写了几篇关于 SO 的文章,说明这是多么困难、磨损和有问题。以下是其中的两个(它们充满了我WifiP2p通过Service Discovery, 和WifiP2p本身获得的内幕知识):

为什么发现 Android WifiDirect 的对等点如此不可靠

无线 P2P。通知所有可用的对等点某些事件

我建议您阅读我的两个答案(即使它们更多地关注WifiP2p本身)。他们应该让您对使用WifiP2p Service Discovery. 我可以很容易地说,如果你想建立一个高效、相对可靠和健壮的WifiP2p连接系统(尤其是使用Service Discovery),你将不得不努力工作。

WifiP2p Service Discovery

为了更好地回答您的确切问题,我将告诉您我做了什么(与您不同)以使我的Service Discovery工作非常可靠。

1. 广播Service

首先:在注册您的Service(使用addLocalService方法)之前,您应该使用WifiP2pManager'clearLocalServices方法。重要的是,您应该addLocalService在侦听器通过回调clearLocalServices返回时调用onSuccess

尽管这很好地设置了广播,但我发现其他节点并不总是能够检测到广播service(尤其是当这些节点在注册您的本地时还没有主动检测服务时Service——但他们后来“加入”了)。我找不到 100% 可靠地解决此问题的方法。相信我,我可能正在尝试所有WifiP2p相关的东西。不,clearLocalServices-addLocalService序列并没有真正给出令人满意的结果。或者更重要的是:做一些不同的事情会更好。我决定做的是,在我成功添加本地服务(onSuccess回调来自addLocalService)之后,我启动了一个Thread会定期调用WifiP2pManager的方法discoverPeers. 这似乎迫使重新广播所有service信息。

所以......基本上你的广播代码的基础应该看起来更像这样(请记住,如果网络连接系统正确,我将在这里发布的每一段代码都被剥离了所有“检查”状态,您应该自己设计它们以最适合您的解决方案):

public void startBroadcastingService(){
    mWifiP2pManager.clearLocalServices(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
        @Override
        public void onSuccess() {
            mWifiP2pManager.addLocalService(mWifiP2pChannel, mWifiP2pServiceInfo,
                    new WifiP2pManager.ActionListener() {

                        @Override
                        public void onSuccess() {
                            // service broadcasting started
                            mServiceBroadcastingHandler
                                    .postDelayed(mServiceBroadcastingRunnable,
                                            SERVICE_BROADCASTING_INTERVAL);
                        }

                        @Override
                        public void onFailure(int error) {
                            // react to failure of adding the local service
                        }
                    });
        }

        @Override
        public void onFailure(int error) {
            // react to failure of clearing the local services
        }
    });
}

mServiceBroadcastingRunnable应该在哪里:

private Runnable mServiceBroadcastingRunnable = new Runnable() {
    @Override
    public void run() {
        mWifiP2pManager.discoverPeers(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
            @Override
            public void onSuccess() {
            }

            @Override
            public void onFailure(int error) {
            }
        });
        mServiceBroadcastingHandler
                .postDelayed(mServiceBroadcastingRunnable, SERVICE_BROADCASTING_INTERVAL);
    }
};

2. 发现Service

为了发现你,service我使用了类似的方法。无论是建立发现,还是试图强制“重新发现” services.

按照以下三种方法的顺序进行设置WifiP2pManager

removeServiceRequest, addServiceRequest,discoverServices

它们是按这个确切的顺序调用的,并且只有在前一个方法通过onSuccess回调“返回”后才调用特定方法(准确地说是第二个或第三个)。

使用直观的方法进行重新发现services(只需重复上述顺序:removeServiceRequest-> addServiceRequest-> discoverServices)。

我的代码的基础看起来更像这样(开始Service Discovery我会先调用prepareServiceDiscovery()然后startServiceDiscovery()):

public void prepareServiceDiscovery() {
    mWifiP2pManager.setDnsSdResponseListeners(mWifiP2pChannel,
            new WifiP2pManager.DnsSdServiceResponseListener() {

                @Override
                public void onDnsSdServiceAvailable(String instanceName,
                                                    String registrationType, WifiP2pDevice srcDevice) {
                    // do all the things you need to do with detected service
                }
            }, new WifiP2pManager.DnsSdTxtRecordListener() {

                @Override
                public void onDnsSdTxtRecordAvailable(
                        String fullDomainName, Map<String, String> record,
                        WifiP2pDevice device) {
                    // do all the things you need to do with detailed information about detected service
                }
            });

    mWifiP2pServiceRequest = WifiP2pDnsSdServiceRequest.newInstance();
}

private void startServiceDiscovery() {
    mWifiP2pManager.removeServiceRequest(mWifiP2pChannel, mWifiP2pServiceRequest,
            new WifiP2pManager.ActionListener() {
                @Override
                public void onSuccess() {
                    mWifiP2pManager.addServiceRequest(mWifiP2pChannel, mWifiP2pServiceRequest,
                            new WifiP2pManager.ActionListener() {

                                @Override
                                public void onSuccess() {
                                    mWifiP2pManager.discoverServices(mWifiP2pChannel,
                                            new WifiP2pManager.ActionListener() {

                                                @Override
                                                public void onSuccess() {
                                                    //service discovery started

                                                    mServiceDiscoveringHandler.postDelayed(
                                                            mServiceDiscoveringRunnable,
                                                            SERVICE_DISCOVERING_INTERVAL);
                                                }

                                                @Override
                                                public void onFailure(int error) {
                                                    // react to failure of starting service discovery
                                                }
                                            });
                                }

                                @Override
                                public void onFailure(int error) {
                                    // react to failure of adding service request
                                }
                            });
                }

                @Override
                public void onFailure(int reason) {
                    // react to failure of removing service request
                }
            });
}

mServiceDiscoveringRunnable只是:

private Runnable mServiceDiscoveringRunnable = new Runnable() {
    @Override
    public void run() {
        startServiceDiscovery();
    }
};

所有这些使我的系统运行良好。它还不完美,但由于缺乏关于这个主题的文档,我认为我无法做更多的改进。

如果您测试这种方法,请务必告诉我它如何为您工作(或者它是否适合您;))。

于 2015-07-26T19:56:13.187 回答
0

如果问题是服务的检测,我相信创建组是使设备和服务可检测的最佳方式,但如果在所有设备中创建组,则您无法直接连接。但作为wifi网络。我每天都这样做,而且效果很好。

于 2017-02-28T19:09:06.593 回答